PSP 为什么死了,PSA 又有什么不同
一句话总结
PSP 采用“通过 RBAC 连接策略与用户”的结构,但过于复杂。PSA 舍弃这种连接,将其简化为三个命名空间标签。这是牺牲表达能力、换取可运维性的取舍。
为什么需要它
PodSecurityPolicy 的工作方式如下:创建 PSP 对象,在 ClusterRole 中加入对该 PSP 的 use 权限,再把它绑定到创建 Pod 的主体——不是人,而是创建 Pod 的控制器 SA。准入时,系统会查找“该主体可使用的 PSP 中,是否有允许这个 Pod 的策略”。
问题有很多。
- 多个 PSP 同时匹配时,很难知道实际采用了哪一个。 虽然存在排序规则,却不直观。
- PSP 还会执行 mutating,悄悄修改 Pod spec,导致编写内容与实际运行内容不同。
- 请求主体不是人而是控制器 SA,这一点不断造成混淆。
- 因此,调试极其痛苦。 回答“这个 Pod 为什么被拒绝”往往耗时很久。
结果是,许多集群要么完全不启用 PSP,要么给所有人一个宽松 PSP 就结束。无人使用的安全功能就不是安全。 PSP 已在 v1.25 中彻底移除。
工作原理
三种配置档
| 配置档 | 特性 | 典型限制 |
|---|---|---|
| privileged | 无限制 | 无;用于 CNI、存储驱动等系统工作负载 |
| baseline | 只阻止已知的权限提升 | 禁止 hostNetwork/hostPID/hostIPC、privileged、hostPath,以及添加危险 capability |
| restricted | 强制最佳实践 | baseline + 必须 runAsNonRoot、必须 seccompProfile、丢弃全部 capability、allowPrivilegeEscalation=false |
满足 restricted 至少需要在 Pod spec 中设置四项:runAsNonRoot: true、allowPrivilegeEscalation: false、capabilities.drop: [ALL]、seccompProfile.type: RuntimeDefault。
三种模式
| 模式 | 行为 | 使用时机 |
|---|---|---|
enforce |
拒绝创建违规 Pod | 实际执行 |
audit |
只记录到审计日志,仍允许创建 | 评估影响 |
warn |
向 kubectl 用户显示警告,仍允许创建 | 准备迁移 |
标签形式为 pod-security.kubernetes.io/<모드>: <프로파일>,可通过 <모드>-version 固定版本。
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.30
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
为什么固定版本很重要。 不固定时即为 latest,集群升级的瞬间,策略内容可能改变。明明没有部署,却突然开始拒绝 Pod 的事故正源于此。
上述示例是实践中最常见的组合:用 baseline enforce 真正阻止违规,同时把 audit/warn 设为 restricted,预先收集“升级为 restricted 后会破坏什么”。
必须了解的性质:只在准入时工作
PSA 只在创建 Pod 时判断。即使提高标签级别,已经运行的 Pod 也不会被驱逐。因此,刚把 enforce 提升为 restricted 时,可能看似什么都没发生,直到下一次滚动发布或节点替换时 Pod 无法启动才暴露问题。策略变更与事故之间存在时间差。
豁免(exemptions)
有些例外无法通过命名空间标签表达,因此 AdmissionConfiguration 提供三个维度的豁免。
usernames——不检查特定用户的请求runtimeClasses——不检查使用特定 RuntimeClass 的 Podnamespaces——不检查特定命名空间(通常为kube-system)
豁免属于集群全局配置,需要重启 apiserver,不能通过命名空间标签修改。 这也是安全机制,因为命名空间管理员无法自行豁免。
PSA 不够用时
PSA 只有三个配置档,无法表达“只允许这个仓库的镜像”“所有 Pod 必须设置资源限制”“禁止没有团队标签的命名空间”等要求。这时需要增加策略引擎。
- Kyverno——学习曲线低,使用 YAML 编写策略,还能生成(generate)资源,CNCF Incubating
- OPA Gatekeeper——使用 Rego,表达能力极高,可进行跨资源验证,资源消耗较高,CNCF Graduated
作者博客的判断很明确:“简单策略使用 Kyverno,复杂的跨资源验证使用 OPA Gatekeeper”;推荐组合是 RBAC(基础授权)+ PSA(Pod 安全标准)+ 策略引擎(自定义)。
Gatekeeper 的准入 Webhook 存在一个盲区,因此另有 Audit Controller。Webhook 只阻止新请求;如果稍后才添加策略,已经部署的违规资源会原样保留。 Audit 会定期扫描全部资源并找出它们。使用 enforcementAction: dryrun 在不阻止请求的情况下仅收集违规,是评估新策略影响的标准流程。
实际现场中的情况
作者重建家庭实验室的记录中,有一起与 PSA 原理完全相同的事件。安装 Cilium 后,hubble-relay 和 hubble-ui 一直 Pending,原因是 0/1 nodes are available: 1 node(s) had untolerated taint(s)。Deployment 没有容忍控制平面的 NoSchedule taint。它与 PSA 迁移一样,都属于**“正常工作却看似事故”的类型**。作者的结论也相同:“这不是错误,而是正常行为。”
作者总结的 PSA 标准迁移流程如下:① 通过 dry-run 审计当前状态(kubectl label --dry-run=server --overwrite ns --all ...);② 先应用 warn/audit;③ 修复违规工作负载;④ 启用 enforce;⑤ 通过 AdmissionConfiguration 为新命名空间设置默认值。“关键是渐进式实施,绝不能一次性启用 enforce。”
接下来阅读什么
先再读一篇秘密管理理论,然后在实验中亲自给命名空间添加 PSA 标签。确认违反 restricted 的 Pod 被拒绝及其拒绝消息,再创建能通过 restricted 的 Pod;最后亲自观察:仅修改标签提高级别后,现有 Pod 仍然存活,只有新 Pod 会被拒绝。