用标签把 Pod Security Admission 挂上
目标
只通过命名空间标签实施 Pod 安全策略,确认违反 restricted 的 Pod 确实被拒绝并查看拒绝消息,最后亲自观察 PSA 的核心特性:即使提高级别,已经运行的 Pod 也不会被驱逐。
为什么重要
PSP 失败不是因为功能不足,而是因为无法调试。多个 PSP 匹配时难以判断采用了哪一个,而且它具有 mutating 行为,使实际运行的 spec 与编写的 spec 不同。没人使用的安全功能就不是安全。
PSA 正是基于这一教训设计的:**一个标签就是策略,拒绝消息会列出所有违规字段。**它牺牲表达能力换取可运维性。理解这一取舍为何正确,是 KCSA 经常考查的重点。
第 7 步是本实验的亮点。PSA 只在准入时生效,因此即使把 enforce 提升到 restricted,已经运行的 Pod 仍会继续存活。表面上像是什么都没发生,直到下一次滚动发布或节点更换时 Pod 无法启动,问题才爆发。亲手确认策略变更与事故之间存在时间差,会改变你设计迁移的方式。
步骤
- 创建命名空间
kcsa-psa-baseline,添加四个标签: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。 - 创建命名空间
kcsa-psa-restricted,添加四个标签:pod-security.kubernetes.io/enforce=restricted、pod-security.kubernetes.io/enforce-version=v1.30、pod-security.kubernetes.io/audit=restricted、pod-security.kubernetes.io/warn=restricted。 - 尝试在
kcsa-psa-restricted中创建带 privileged 容器的 Podbad。它必须被拒绝,并将完整拒绝消息保存到/root/kcsa-psa/reject.txt。Podbad最终必须保持不存在。 - 在
kcsa-psa-baseline中创建 Podapp-baseline:镜像nginx:1.27-alpine,securityContext 完全不设置,使其达到 Running。 - 在
kcsa-psa-restricted中创建 Podapp-restricted:镜像nginx:1.27-alpine;Pod 级设置securityContext.runAsNonRoot: true和securityContext.seccompProfile.type: RuntimeDefault;容器级设置allowPrivilegeEscalation: false、capabilities.drop: ["ALL"]、runAsUser: 1000。 - 在
/root/kcsa-psa/exempt.yaml中编写 AdmissionConfiguration:plugins[0].name为PodSecurity,configuration.kind为PodSecurityConfiguration,defaults.enforce为baseline,exemptions.namespaces的第一项为kube-system。再在/root/kcsa-psa/exempt-note.txt中逐行准确写出 PSA 豁免的三个维度:usernames、runtimeClasses、namespaces。 - 只把
kcsa-psa-baseline的enforce标签改为restricted。随后:(a) 查看现有 Podapp-baseline的当前状态,在/root/kcsa-psa/upgrade.txt中写入existing-pod=<상태>;(b) 尝试创建与第 4 步相同 spec 的 Podapp-baseline2,确认被拒绝后在同一文件追加new-pod=rejected。Podapp-baseline2必须保持不存在。
参考
- 标签使用
kubectl label namespace <이름> <키>=<값>添加;修改已有值需要--overwrite。 - 拒绝消息输出到标准错误,因此应像
kubectl apply -f bad.yaml 2> /root/kcsa-psa/reject.txt一样保存。 - 使用
kubectl get pod app-baseline -n kcsa-psa-baseline -o jsonpath='{.status.phase}'查看 Pod 状态。 - 常见错误 1:第 4 步预先给 Pod 加入安全设置。这样第 7 步就失去对比,也无法通过评分。
- 常见错误 2:第 3 或第 7 步为强行创建被拒绝的 Pod 而暂时降低标签。评分会确认该 Pod 不存在。
创建 baseline 命名空间
创建命名空间 kcsa-psa-baseline,添加四个标签: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。
PSA 只通过命名空间标签工作。共有三种模式(enforce/audit/warn),另加一个固定版本的标签。enforce 是实际阻止的级别,audit/warn 用于预览“提升后会破坏什么”。
创建 restricted 命名空间
创建命名空间 kcsa-psa-restricted,添加四个标签:pod-security.kubernetes.io/enforce=restricted、pod-security.kubernetes.io/enforce-version=v1.30、pod-security.kubernetes.io/audit=restricted、pod-security.kubernetes.io/warn=restricted。
与上一步同样是四个标签,但值都采用最严格级别。若遗漏版本标签,升级集群时策略内容可能发生变化。
确认违反 restricted 的 Pod 被拒绝
尝试在 kcsa-psa-restricted 中创建带 privileged 容器的 Pod bad。它必须被拒绝,并将完整拒绝消息保存到 /root/kcsa-psa/reject.txt。Pod bad 最终必须保持不存在。
本步骤的目标是制造失败。命令失败时消息会写到标准错误,请注意重定向。拒绝消息会说明违反了哪个 profile 和哪个字段。
只通过 baseline 的普通 Pod
在 kcsa-psa-baseline 中创建 Pod app-baseline:镜像 nginx:1.27-alpine,securityContext 完全不设置,使其达到 Running。
这是一个没有任何特殊安全设置的普通 Pod。它应通过 baseline,但不满足任何 restricted 要求。它是下一步的对照组,不要额外加固。
通过 restricted 的 Pod
在 kcsa-psa-restricted 中创建 Pod app-restricted:镜像 nginx:1.27-alpine;Pod 级设置 securityContext.runAsNonRoot: true 和 securityContext.seccompProfile.type: RuntimeDefault;容器级设置 allowPrivilegeEscalation: false、capabilities.drop: ["ALL"]、runAsUser: 1000。
需要四项要求,其中两项位于 Pod 级 securityContext,两项位于容器级。若混淆位置,拒绝消息会告诉你。还必须明确指定 runAsUser。
整理豁免配置与豁免维度
在 /root/kcsa-psa/exempt.yaml 中编写 AdmissionConfiguration:plugins[0].name 为 PodSecurity,configuration.kind 为 PodSecurityConfiguration,defaults.enforce 为 baseline,exemptions.namespaces 的第一项为 kube-system。再在 /root/kcsa-psa/exempt-note.txt 中逐行准确写出 PSA 豁免的三个维度:usernames、runtimeClasses、namespaces。
豁免无法用命名空间标签表示,要写入 apiserver 的准入配置文件。本实验只编写该文件。豁免有三个维度,请思考各自按什么依据跳过检查。
只提升标签时现有 Pod 会怎样
只把 kcsa-psa-baseline 的 enforce 标签改为 restricted。随后:(a) 查看现有 Pod app-baseline 的当前状态,在 /root/kcsa-psa/upgrade.txt 中写入 existing-pod=<상태>;(b) 尝试创建与第 4 步相同 spec 的 Pod app-baseline2,确认被拒绝后在同一文件追加 new-pod=rejected。Pod app-baseline2 必须保持不存在。
PSA 只在准入时判断,这一事实决定了提升级别后的结果。请实际查看并原样记录现有 Pod 状态,再创建相同 spec 的新 Pod,差异便会非常清楚。