遇到这个问题的集群,通常不是一开始就加了 PodSecurityPolicy,而是在某个巡检节点发现工作负载里有特权容器,要求统一收敛。我接手时第一件事不是急着改配置,而是先确认现状:集群里的特权容器到底有多少、分布在哪些 Namespace、是不是都真的有提权需求。
先确认现状,再拟准入策略
在没有引入任何策略之前,特权容器很难通过常规的 kubectl get pods 直接看出来。我习惯先用这条命令把整个集群里显式声明了 privileged: true 的 Pod 清单拉出来:
kubectl get pods -A -o json | jq '.items[] | select(any(.spec.containers[]; .securityContext.privileged == true)) | .metadata.namespace + "/" + .metadata.name'如果 jq 不方便,也可以用 kubectl get pods -A -o yaml | grep -B 5 'privileged: true',但输出会混在一起,不如 jq 干净。这一步的核心是确认影响面,同时把需要豁免的合法特权容器单独列出来。
容易误判的地方
一个常见的误判是认为“创建了 PSP 并绑定到 ServiceAccount 就马上生效”。实际上,PodSecurityPolicy 必须由 kube-apiserver 的准入控制器启用之后才会起作用。另一个误判是“启用了准入控制器,没有 PSP 的 Pod 会被拒绝”——这个说法不准确,准确地说,当 PSP 准入控制器启用后,每个 Pod 必须匹配至少一个“允许使用”的 PSP,否则创建请求会被拒绝。也就是说,如果没有提前准备好可用的 PSP,一旦打开准入控制器,整个集群可能进入“什么 Pod 都创建不了”的故障状态。
建议的处理顺序
稳妥的做法是先把 PSP 策略和 RBAC 授权准备好,最后才修改 apiserver 参数。建议顺序如下:
- 梳理特权容器,区分“必须特权”和“误用特权”两类;
- 为“必须特权”的命名空间准备宽松一点的 PSP,同时给其他命名空间准备禁特权 PSP;
- 创建 ClusterRole,声明对具体 PSP 的 use 权限;
- 通过 ClusterRoleBinding 或 RoleBinding 把权限绑定到对应 ServiceAccount(建议按 Namespace 绑定,不要绑定到 system:serviceaccounts);
- 修改 kube-apiserver 的启动参数,加入
--enable-admission-plugins=PodSecurityPolicy(旧版本是--admission-control),逐个重启 apiserver。
这里每个步骤都需要验证,不要一次性全做完再看结果。比如 RBAC 绑定错误,应该靠 kubectl auth can-i 先检查权限。
配置示例:禁止特权容器的 PSP
下面是一份相对收敛的 PSP 配置,核心是 privileged: false,同时关闭了 privilege escalation,并要求删除所有 cap:
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- configMap
- emptyDir
- secret
runAsUser:
rule: MustRunAs
ranges:
- min: 1000
max: 65535
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny这份配置不适合直接套用,因为 runAsUser 的范围限定了非 root 用户。如果集群里的镜像必须跑 root,就要放宽成 runAsUser: { rule: RunAsAny },否则很多现有 Pod 会因为 UID 不匹配而被拒绝。所以每一项都要结合环境确认。
验证方法:用特权 Pod 探测拦截效果
启动准入控制器后,先用普通 Pod 验证基础创建能力,再提交一个 explicit privileged Pod。比如创建一个简单的 Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: privileged-test
spec:
replicas: 1
selector:
matchLabels:
app: privileged-test
template:
metadata:
labels:
app: privileged-test
spec:
containers:
- name: busybox
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
securityContext:
privileged: true如果 PSP 生效,创建这个 Deployment 时会看到类似 Forbidden: PodSecurityPolicy does not allow privileged containers 的报错。同时,我们可以通过 kubectl auth can-i use podsecuritypolicy/restricted --as=system:serviceaccount:namespace:default 来确认 ServiceAccount 是否具备使用特定 PSP 的权限。
需要特别注意的是:PSP 只在 Pod 创建或更新时触发,已经运行中的特权 Pod 不会被主动驱逐或修改。如果你发现某个 Pod 在策略生效后仍然保持特权,多半是因为它没有重新创建。
回滚和风险边界
如果启用后业务大面积异常,最快的回滚方式是去掉 kube-apiserver 启动参数里的 PodSecurityPolicy,然后重启 apiserver。这个操作本身风险不高,但要注意 apiserver 的高可用部署方式:如果只有一个静态 Pod 模式,重启时要保证 etcd 健康。
另一个常见风险是 PSP 策略过严,导致某些需要目录挂载或 hostPort 的 Pod 被拒绝。处理这类问题要回到 PSP 的 volumes、hostPorts、allowedCapabilities 字段上去,不要靠关闭准入控制来规避。因为 PodSecurityPolicy 本身在 Kubernetes 1.21 版本后也被弃用了,如果你所在集群版本较新,建议还是评估 Pod Security Admission 或 Gatekeeper 这一类更现代的方向。
后续维护上,建议把 PSP 的授权收敛到 Namespace 级别,避免把 use 权限绑到 system:serviceaccounts:default 这类全局对象。每季度重新拉一次特权容器清单,用来校验策略是否真的覆盖了所有新加入的工作负载。