psa不是psp平替,而是放弃“突变+授权”模型,改用纯标签驱动的静态校验;删除psp后若未配置psa label,新pod按宽松模式放行,但一旦设置enforce label即严格拒绝违规pod且无fallback。

Pod Security Admission(PSA)不是PSP的平替,而是从设计上放弃“突变+授权”模型,改用纯标签驱动的静态策略校验——这意味着你不能再靠RBAC绑定策略,必须提前给Namespace打label。
为什么直接删掉PSP后Pod会卡在Pending状态
因为PSA默认不启用任何策略,删掉PSP又没配PSA label时,所有新Pod都按“宽松模式”放行,看似正常;但一旦你开始加pod-security.kubernetes.io/enforce label,它就会立刻拒绝不符合标准的Pod,且不提供fallback机制。
- 常见错误现象:
error: pods "nginx" is forbidden: violates PodSecurity "restricted:latest": privileged (container "nginx" must not set securityContext.privileged=true) - 根本原因:PSA只做准入检查,不修改Pod字段(PSP能自动drop capabilities、强制runAsNonRoot,PSA不做这些)
- 迁移前提:你的Pod YAML必须已满足目标策略要求,比如
securityContext.runAsNonRoot: true、privileged: false、allowPrivilegeEscalation: false等字段得自己写全 - 验证方式:用
kubectl label --dry-run=server ns/default pod-security.kubernetes.io/enforce=restricted先试跑,看输出哪些违规项
如何为不同命名空间配置enforce/audit/warn三级策略
PSA通过三个label控制同一命名空间下的三种行为,它们可以共存,但enforce优先级最高,只要它存在,audit和warn就只起辅助作用。
评估 Kubernetes 集群安全态势,覆盖 RBAC、工作负载安全、网络策略、基础设施即代码(IaC)、运行时监控和密钥管理等 30 项控制项……
-
pod-security.kubernetes.io/enforce: restricted—— 违反即拒,适用于生产核心命名空间 -
pod-security.kubernetes.io/audit: baseline—— 违规记录到API Server审计日志,适合灰度环境观察影响面 -
pod-security.kubernetes.io/warn: restricted—— 给kubectl create/apply返回警告,但Pod仍能运行,适合开发测试环境过渡 - 注意:
enforce和audit的值必须是同一策略级别(如restricted),否则audit不会生效;warn可独立设置更低级别(如baseline)
restricted策略下最常被忽略的5个硬性要求
PSA的restricted策略比旧PSP的“非特权”更严格,很多老配置会在这里翻车。
-
securityContext.capabilities.drop必须显式包含ALL,不能留空或只drop部分 -
securityContext.seccompProfile.type必须为RuntimeDefault或Localhost,禁止Unconfined -
hostNetwork、hostIPC、hostPID全部禁用,连false都得写明(YAML里布尔值省略等于false,但PSA要求显式声明) -
volumeMounts中不能有subPathExpr字段(K8s 1.25+新增限制,旧PSP不管这个) - InitContainer也必须满足全部要求,容易漏检
与Seccomp配合时的关键路径和权限问题
PSA本身不处理seccomp,但它强制要求restricted策略下必须启用seccomp,默认值是RuntimeDefault。如果你自定义profile,路径和权限必须精确匹配。
- profile文件必须放在kubelet配置的
--seccomp-default-profile目录下(通常是/var/lib/kubelet/seccomp/),且kubelet启动参数需含--feature-gates=SeccompDefault=true - Pod中引用时
localhostProfile值是相对路径,比如custom-profile.json,实际读取位置是/var/lib/kubelet/seccomp/custom-profile.json - 常见错误:
seccompProfile.type: Localhost写了但localhostProfile为空,或文件权限不是644,kubelet会静默跳过并回退到Unconfined(触发PSA拒绝) - 验证是否生效:
kubectl get pod <pod-name> -o jsonpath='{.spec.securityContext.seccompProfile}'</pod-name>,确认输出非空且type正确
真正麻烦的不是配label,而是让存量Pod YAML全部满足restricted策略的显式字段要求——尤其是那些由Helm Chart或CI流水线自动生成的模板,往往缺runAsNonRoot或drop: ["ALL"],得逐个补全,否则enforce一开就全挂。










