Pod Security Admission 与 securityContext
目标
掌握仅通过命名空间标签设定工作负载安全底线的方法,并亲手完成能够真正通过 restricted 配置文件的 Pod 规范。
为什么重要
PodSecurityPolicy 已在 1.25 中移除。使用 PSP 时,必须向 ServiceAccount 授予“use 此 PSP”的权限,这一结构本身就可能成为权限提升路径,而且很难预测多个 PSP 中究竟会应用哪一个。替代方案 PSA 只需几行命名空间标签,并可分别启用 enforce、audit、warn 三种模式,从而实现渐进式引入。若在现有集群中立即启用 enforce,大量工作负载会被阻止,因此标准流程是先启用 warn 和 audit 进行观察。
restricted 配置文件要求的四项设置(runAsNonRoot、allowPrivilegeEscalation false、capabilities drop ALL、seccompProfile)是 CKS 中最常出现的组合。与其死记硬背,不如亲自逐一移除,观察会产生什么错误,更容易长期掌握。
此环境的 API 服务器已经启用 PodSecurity Admission,因此违规 Pod 会真正被拒绝。
步骤
- 创建命名空间
cks-psa,并添加标签pod-security.kubernetes.io/enforce=baseline。 - 创建命名空间
cks-psa-strict,将 enforce、audit、warn 三个标签全部设为restricted, 并将enforce-version、audit-version、warn-version三个标签全部设为latest。 - 在
cks-psa-strict中创建 Podhardened(容器名称app,镜像nginx:1.27-alpine)。 为通过 restricted,Pod 层级需要runAsNonRoot: true和seccompProfile.type: RuntimeDefault,容器层级需要allowPrivilegeEscalation: false和capabilities.drop: [ALL]。 - 尝试在
cks-psa-strict中 apply 包含privileged: true容器的 Podbad-pod。 将输出(包括标准错误)保存到/root/cks-securitycontext/denied.txt。 Pod 不得创建成功。 - 在
cks-psa中创建 Podnonroot-app(容器名称app)。在 Pod 层级 securityContext 中 设置runAsNonRoot: true、runAsUser: 10001、runAsGroup: 10001、fsGroup: 20001。 - 在
cks-psa-strict中创建 Poddropped(容器名称app)。Pod 层级的seccompProfile.type为RuntimeDefault,runAsNonRoot为true; 容器层级设置allowPrivilegeEscalation: false、capabilities.drop: [ALL]、readOnlyRootFilesystem: true。 - 创建 RuntimeClass
cks-sandbox。handler为runsc,overhead.podFixed为 内存160Mi和 CPU250m。 - 在
cks-psa-strict中创建 Deploymentpayments。replicas 为 2,选择器和 Pod 标签为app=payments,Pod 规范的runtimeClassName为cks-sandbox;Pod 模板应具备 与第 3 步相同的四项条件,以通过 restricted。
参考
kubectl label ns cks-psa-strict pod-security.kubernetes.io/enforce=restricted pod-security.kubernetes.io/enforce-version=latest ...- 第 4 步执行示例:
kubectl apply -f bad-pod.yaml 2>&1 | tee /root/cks-securitycontext/denied.txt kubectl explain pod.spec.securityContext与kubectl explain pod.spec.containers.securityContext会显示不同的字段列表。- 常见错误 1:把
capabilities放在 Pod 层级。它仅用于容器层级。 - 常见错误 2:遗漏
-version标签,导致集群升级时配置文件定义改变,原本正常的 Pod 也可能被拒绝。
应用 baseline 配置文件
创建命名空间 cks-psa,并添加标签 pod-security.kubernetes.io/enforce=baseline。
PSA 通过命名空间标签运行。标签键以 pod-security.kubernetes.io/ 开头。
设置全部三种模式与版本标签
创建命名空间 cks-psa-strict,将 enforce、audit、warn 三个标签全部设为 restricted,
并将 enforce-version、audit-version、warn-version 三个标签全部设为 latest。
enforce、audit、warn 各自都有对应的 -version 标签。固定版本可以避免集群升级直接导致策略收紧。
通过 restricted 的 Pod
在 cks-psa-strict 中创建 Pod hardened(容器名称 app,镜像 nginx:1.27-alpine)。
为通过 restricted,Pod 层级需要 runAsNonRoot: true 和
seccompProfile.type: RuntimeDefault,容器层级需要 allowPrivilegeEscalation: false
和 capabilities.drop: [ALL]。
restricted 强制要求四项设置。缺少任何一项都会被拒绝,错误消息会指出触发了哪个字段。
还要注意一点:runAsNonRoot: true 不会替你指定 UID。它只表示“不得以 root 运行”;如果镜像未指定 UID,在真实节点上 kubelet 会无法启动 Pod,并报出 CreateContainerConfigError。真实集群中应同时设置 runAsUser,或使用按非 root 用户构建的镜像。本实验环境不会实际运行 Pod,因此不会显现这一差异。
确认违规 Pod 被拒绝
尝试在 cks-psa-strict 中 apply 包含 privileged: true 容器的 Pod bad-pod。
将输出(包括标准错误)保存到 /root/cks-securitycontext/denied.txt。
Pod 不得创建成功。
必须同时把 apply 的标准输出与标准错误保存到文件。请使用 2>&1 | tee。如果 Pod 被创建,说明策略并未生效。
指定运行用户与组
在 cks-psa 中创建 Pod nonroot-app(容器名称 app)。在 Pod 层级 securityContext 中
设置 runAsNonRoot: true、runAsUser: 10001、runAsGroup: 10001、fsGroup: 20001。
runAsUser/runAsGroup/fsGroup 位于 Pod 层级 securityContext;runAsNonRoot 两个层级都可使用。fsGroup 会改变卷文件的组所有权。
组合 seccomp 与 capability
在 cks-psa-strict 中创建 Pod dropped(容器名称 app)。Pod 层级的
seccompProfile.type 为 RuntimeDefault,runAsNonRoot 为 true;
容器层级设置 allowPrivilegeEscalation: false、capabilities.drop: [ALL]、
readOnlyRootFilesystem: true。
由于该命名空间使用 restricted,此 Pod 也必须满足全部四项必要条件才能创建。
RuntimeClass 对象
创建 RuntimeClass cks-sandbox。handler 为 runsc,overhead.podFixed 为
内存 160Mi 和 CPU 250m。
RuntimeClass 是集群范围资源。handler 的值必须逐字符匹配节点容器运行时配置中的 Runtime 名称。
综合:使用沙箱 Runtime 部署
在 cks-psa-strict 中创建 Deployment payments。replicas 为 2,选择器和 Pod 标签为
app=payments,Pod 规范的 runtimeClassName 为 cks-sandbox;Pod 模板应具备
与第 3 步相同的四项条件,以通过 restricted。
Deployment 的 Pod 模板同样接受 PSA 检查。在 Pod 规范的 runtimeClassName 中填写前面创建的 RuntimeClass 名称。