Kubernetes 1.22 中加入了一个新的功能叫 PodSecurity admission,据称是一个 PSP 的替代方案,于是我就“抱着试一试的态度”,第一时间体验了一下。
这个新功能的思路很直白,把 Pod/Container SecurityContext 的限制分为了三组,分别命名为 Privileged、Baseline 以及 Restricted,顾名思义,这三个级别代表着特权、普通以及严格管理三种对策。用法还是很简单的,只要给要控制的命名空间或者 Pod 打上标签即可。可用的标签列表如下:
pod-security.kubernetes.io/enforce:pod-security.kubernetes.io/enforce-version:pod-security.kubernetes.io/audit:pod-security.kubernetes.io/audit-version:pod-security.kubernetes.io/warn:pod-security.kubernetes.io/warn-version:
其中的规定动作包括:
- 
enforce:仅允许创建符合该策略的 Pod 被创建,不合乎要求的 Pod 会被拒绝; - 
audit:可以创建违规 Pod,但是会出现在审计日志中; - 
warn:可以创建违规 Pod,但是会在客户端返回警告信息。 
而版本是跟随 Kubernetes 的,例如 1.22 或者 latest。
需要注意的是,多数情况下 Pod 都是用模板创建的,为了尽早发现问题,audit 和 warn 都是可以针对 Deployment 之类的控制器生效的,而 enforce 仅对 Pod 有效。
举个栗子
首先用 Kind 部署一个测试集群,使用如下的配置文件:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  "PodSecurity": true
nodes:
- role: control-plane
  image: kindest/node:v1.22.0
- role: control-plane
  image: kindest/node:v1.22.0
- role: control-plane
  image: kindest/node:v1.22.0
- role: worker
  image: kindest/node:v1.22.0
这里使用 "PodSecurity": true 启用该功能。创建集群并载入镜像:
$ kind create cluster --config 122.yaml
 ✓ Ensuring node image (kindest/node:v1.22.0) 🖼
 ✓ Preparing nodes 📦 📦 📦 📦
 ✓ Configuring the external load balancer ⚖️
 ✓ Writing configuration 📜
...
$ kind load docker-image dustise/sleep:v0.9.7
Image: "dustise/sleep:v0.9.7" with ID "sha256:cd6cdf0ece4664dcbc10cb98273799a0e4a0e0c2145bf36bb7031915c0ab04df" not yet present on node "kind-control-plane2", loading...
集群生成完毕之后,新建几个命名空间用来测试:
$ kubectl create ns dev
namespace/dev created
$ kubectl create ns stage
namespace/stage created
$ kubectl create ns prod
namespace/prod created
给三个命名空间分别打上标签:
$ kubectl label ns dev pod-security.kubernetes.io/warn=restricted
namespace/dev labeled
$ kubectl label ns stage pod-security.kubernetes.io/audit=restricted
namespace/stage labeled
$ kubectl label ns prod pod-security.kubernetes.io/enforce=restricted
namespace/prod labeled
接下来在每个命名空间创建 Deployment,看看会发生什么:
$ kubectl create deployment sleep --image=dustise/sleep:v0.9.7 -n prod
deployment.apps/sleep created
$ kubectl get pods -n prod
No resources found in prod namespace.
$ kubectl get events -n prod
...
Error creating: allowPrivilegeEscalation != false (container "sleep" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "sleep" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "sleep" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "sleep" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
...
可以看到,Deployment 成功创建,然而却没有 Pod 出现,查看事件会看到其创建过程被拒绝。
再去 Dev 命名空间看一下:
kubectl create deployment sleep --image=dustise/sleep:v0.9.7 -n dev
Warning: would violate "latest" version of "restricted" PodSecurity profile: allowPrivilegeEscalation != false (container "sleep" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "sleep" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "sleep" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "sleep" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
deployment.apps/sleep created
会看到直接返回告警信息,但是 Pod 还是建立起来了。
后记
这个新功能在我看来有些尴尬,每个类别的策略都是隐藏在预配置之中的,要想创建符合其要求的 Pod 可能会费点力气,用 CI 或者 Kyverno 辅助创建可能会更好。
文章来源于互联网:实名反对 PodSecurity Admission




