Pod Security Policy安全策略:禁止特权容器运行
在大规模模型训练任务日益频繁地部署于 Kubernetes 集群的今天,一个看似微小的配置错误,就可能让整个节点陷入瘫痪。想象一下:某位用户提交了一个“调试用”的训练任务,仅仅为了挂载某个设备或修改内核参数,便在 YAML 中加上了privileged: true——下一秒,这个容器就能像宿主机上的 root 用户一样为所欲为。这不是假设,而是真实发生过的生产事故。
尤其在使用如ms-swift这类支持 LoRA、QLoRA 微调和 vLLM/SGLang 推理加速的 AI 框架时,任务往往需要访问 GPU/NPU 等硬件资源,甚至执行底层驱动操作。这使得系统对权限控制的要求更高。一旦缺乏有效约束,攻击者便可利用供应链漏洞、镜像后门或配置疏忽,通过特权容器实现容器逃逸,进而横向渗透整个集群。
虽然 Kubernetes 官方已在 v1.25 版本中移除了Pod Security Policy(PSP),但它的设计理念——在准入阶段拦截高风险行为——仍是当前安全体系的核心逻辑。理解 PSP 如何阻止特权容器运行,不仅有助于排查遗留系统的安全问题,更能为迁移到现代策略机制(如 Pod Security Admission 或 OPA/Gatekeeper)提供坚实基础。
什么是“特权容器”?它为何如此危险?
简单来说,一个设置了securityContext.privileged: true的容器,等同于获得了宿主机的 root 权限。它不再受限于命名空间和 cgroups 的隔离机制,而是可以直接与内核交互。
当容器运行时(如 containerd)看到这个标志,就会为其开启所有 Linux capabilities,并允许访问/dev下的所有设备节点。这意味着:
- 它可以运行
iptables修改防火墙规则; - 可以加载 eBPF 程序监控或劫持网络流量;
- 能直接读写磁盘分区,绕过 PersistentVolume 的管理;
- 甚至能调用 NVIDIA 或 Ascend 驱动接口,进行低级硬件操作。
某些旧版 AI 工具链确实依赖这种方式初始化加速卡,但这绝不应成为常态。更合理的做法是通过Device Plugin + capability 白名单实现精细化授权,而非一刀切地开放全部权限。
举个例子,下面这段 YAML 如果被恶意利用,后果不堪设想:
apiVersion: v1 kind: Pod metadata: name: malicious-training-pod spec: containers: - name: trainer image: attacker/image:latest securityContext: privileged: true command: ["/bin/sh"] args: ["-c", "mkdir /host && mount --bind / /host && rm -rf /host/etc/*"]这段代码会将宿主机根目录挂载进容器并清空/etc,导致 SSH 失效、服务崩溃、节点彻底失联。而这一切,只需要一次未经审查的 Pod 创建请求。
PSP 是如何拦下这类威胁的?
尽管 PSP 已退出历史舞台,但它的工作机制仍值得深入剖析——因为它揭示了 Kubernetes 安全防线的本质:前置拦截 + 规则校验 + 权限绑定。
PSP 并非自动生效的策略,而是一种需显式启用的集群级资源。它本身不直接作用于 Pod,而是通过准入控制器链中的PodSecurityPolicy插件,在 API Server 接收到创建请求时介入判断。
具体流程如下:
- 用户提交 Pod 创建请求;
- API Server 触发准入控制器链;
- PSP 控制器激活,查找所有可用的 PSP 资源;
- 根据请求者的 ServiceAccount 和 RBAC 绑定关系,筛选出其有权使用的策略列表;
- 遍历这些策略,检查目标 Pod 是否满足任意一条中的全部条件;
- 若匹配成功,则放行;否则返回
Forbidden错误。
关键在于,即使你写的 Pod 想要以特权模式运行,只要没有对应的 PSP 明确允许,且你的身份无权使用该策略,请求就会被拒绝。
以下是一个典型的限制性 PSP 示例:
apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: name: restricted-psp spec: privileged: false allowPrivilegeEscalation: false requiredDropCapabilities: - ALL volumes: - configMap - secret - emptyDir - persistentVolumeClaim hostNetwork: false hostIPC: false hostPID: false runAsUser: rule: MustRunAsNonRoot seLinux: rule: RunAsAny supplementalGroups: rule: MustRunAs ranges: - min: 1 max: 65535 fsGroup: rule: MustRunAs ranges: - min: 1 max: 65535 readOnlyRootFilesystem: true这份策略几乎封死了所有常见的提权路径:
-privileged: false直接禁止特权容器;
-allowPrivilegeEscalation: false阻止 setuid 程序提权;
-requiredDropCapabilities: [ALL]删除所有 capabilities,仅可通过allowedCapabilities白名单补充必要权限;
-runAsNonRoot强制非 root 用户运行;
- 根文件系统只读,防止持久化恶意程序。
但请注意:PSP 本身不具备绑定能力。它只是一个“规则模板”,必须配合 RBAC 才能生效。例如,你需要为特定 ServiceAccount 授予使用该策略的权限:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: ai-training name: psp-role rules: - apiGroups: ['policy'] resources: ['podsecuritypolicies'] verbs: ['use'] resourceNames: - restricted-psp --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: namespace: ai-training name: psp-binding subjects: - kind: ServiceAccount name: swift-sa namespace: ai-training roleRef: kind: Role name: psp-role apiGroup: rbac.authorization.k8s.io只有当swift-sa这个账号提交 Pod 请求时,才会被纳入restricted-psp的管控范围。这种“策略+授权”分离的设计,既保证了灵活性,也避免了误伤系统组件。
在 ms-swift 场景下的实际挑战与应对
在基于 ms-swift 框架的大模型训练平台中,我们常面临几个典型的安全痛点:
1. 开发人员“图方便”滥用特权模式
有些用户为了调试模型加载性能,可能会尝试手动挂载设备或调整内核参数(如共享内存大小),于是直接加上privileged: true。他们或许没有恶意,但这种习惯极容易演变为安全隐患。
解决方案很简单:在命名空间级别强制实施 restrictive PSP,任何包含privileged: true的 Pod 都会被直接拒绝。同时配合审计日志记录此类事件,推动团队建立安全开发规范。
2. 第三方镜像存在潜在后门
ms-swift 支持一键拉取 ModelScope 上的数百个预训练模型及其推理镜像。虽然来源可信,但仍需防范供应链攻击。比如某个镜像内部隐藏脚本,尝试通过nsenter切换到宿主机命名空间。
在这种情况下,即便镜像试图提权,PSP 也能在创建阶段就将其拦截。这就是“纵深防御”的体现:不依赖单一环节的信任。
3. 多租户环境下的权限越界风险
多个团队共用一个集群时,必须确保彼此隔离。A 团队的训练任务不能访问 B 团队的数据卷,更不能干扰节点操作系统状态。
通过为每个命名空间分配独立的 PSP 策略,我们可以实现差异化控制:
- 生产环境:全面禁用特权、强制非 root、只读根文件系统;
- 开发/调试环境:适度放宽,允许添加特定 capability(如SYS_PTRACE),但仍禁止privileged;
- 系统组件专用命名空间:保留有限特权策略,仅供 CNI、CSI 等可信插件使用。
这样的分层设计,既能保障安全基线,又不至于过度影响效率。
从 PSP 到未来:我们该如何演进?
自 Kubernetes v1.25 起,PSP 已被彻底移除。官方推荐使用Pod Security Admission(PSA)作为替代方案。PSA 更轻量、原生集成、无需额外控制器,且支持命名空间级别的标签控制。
迁移非常直观:
kubectl label ns ai-training pod-security.kubernetes.io/enforce=restricted这条命令即可在ai-training命名空间中强制执行“受限”级别的安全策略,效果类似于之前的 restrictive PSP。
当然,对于更复杂的策略需求(如自定义校验逻辑、跨资源关联判断),业界普遍转向Open Policy Agent(OPA) + Gatekeeper。它支持基于 Rego 语言编写细粒度策略,可轻松实现“禁止使用 latest 标签”、“必须设置 resource limits”等高级规则。
无论采用哪种机制,核心思想不变:在 Pod 创建之前完成安全校验,把风险挡在门外。
结语
禁止特权容器运行,并非为了增加使用门槛,而是为了让系统在面对未知威胁时更具韧性。特别是在 AI 训练这种高资源消耗、深系统交互的场景下,每一次权限的授予都应被视为一次风险的引入。
PSP 虽已落幕,但它教会我们的原则依然有效:
- 最小权限必须落地;
- 隔离边界不可轻易打破;
- 安全不应依赖“自觉”,而应依靠机制强制。
当我们站在大模型时代的入口,享受着 ms-swift 等先进框架带来的便利时,更要记得:真正的技术进步,不只是跑得更快,更是走得更稳。