LabHub
学习 学习路径 课程

KCSA — Kubernetes 安全助理

用标签把 Pod Security Admission 挂上

在 LabHub 中继续学习

目标

只通过命名空间标签实施 Pod 安全策略,确认违反 restricted 的 Pod 确实被拒绝并查看拒绝消息,最后亲自观察 PSA 的核心特性:即使提高级别,已经运行的 Pod 也不会被驱逐

为什么重要

PSP 失败不是因为功能不足,而是因为无法调试。多个 PSP 匹配时难以判断采用了哪一个,而且它具有 mutating 行为,使实际运行的 spec 与编写的 spec 不同。没人使用的安全功能就不是安全。

PSA 正是基于这一教训设计的:**一个标签就是策略,拒绝消息会列出所有违规字段。**它牺牲表达能力换取可运维性。理解这一取舍为何正确,是 KCSA 经常考查的重点。

第 7 步是本实验的亮点。PSA 只在准入时生效,因此即使把 enforce 提升到 restricted,已经运行的 Pod 仍会继续存活。表面上像是什么都没发生,直到下一次滚动发布或节点更换时 Pod 无法启动,问题才爆发。亲手确认策略变更与事故之间存在时间差,会改变你设计迁移的方式。

步骤

  1. 创建命名空间 kcsa-psa-baseline,添加四个标签:pod-security.kubernetes.io/enforce=baselinepod-security.kubernetes.io/enforce-version=v1.30pod-security.kubernetes.io/audit=restrictedpod-security.kubernetes.io/warn=restricted
  2. 创建命名空间 kcsa-psa-restricted,添加四个标签:pod-security.kubernetes.io/enforce=restrictedpod-security.kubernetes.io/enforce-version=v1.30pod-security.kubernetes.io/audit=restrictedpod-security.kubernetes.io/warn=restricted
  3. 尝试在 kcsa-psa-restricted 中创建带 privileged 容器的 Pod bad。它必须被拒绝,并将完整拒绝消息保存到 /root/kcsa-psa/reject.txt。Pod bad 最终必须保持不存在。
  4. kcsa-psa-baseline 中创建 Pod app-baseline:镜像 nginx:1.27-alpine,securityContext 完全不设置,使其达到 Running。
  5. kcsa-psa-restricted 中创建 Pod app-restricted:镜像 nginx:1.27-alpine;Pod 级设置 securityContext.runAsNonRoot: truesecurityContext.seccompProfile.type: RuntimeDefault;容器级设置 allowPrivilegeEscalation: falsecapabilities.drop: ["ALL"]runAsUser: 1000
  6. /root/kcsa-psa/exempt.yaml 中编写 AdmissionConfiguration:plugins[0].namePodSecurityconfiguration.kindPodSecurityConfigurationdefaults.enforcebaselineexemptions.namespaces 的第一项为 kube-system。再在 /root/kcsa-psa/exempt-note.txt 中逐行准确写出 PSA 豁免的三个维度:usernamesruntimeClassesnamespaces
  7. 只把 kcsa-psa-baselineenforce 标签改为 restricted。随后:(a) 查看现有 Pod app-baseline 的当前状态,在 /root/kcsa-psa/upgrade.txt 中写入 existing-pod=<상태>;(b) 尝试创建与第 4 步相同 spec 的 Pod app-baseline2,确认被拒绝后在同一文件追加 new-pod=rejected。Pod app-baseline2 必须保持不存在。

参考

创建 baseline 命名空间

创建命名空间 kcsa-psa-baseline,添加四个标签:pod-security.kubernetes.io/enforce=baselinepod-security.kubernetes.io/enforce-version=v1.30pod-security.kubernetes.io/audit=restrictedpod-security.kubernetes.io/warn=restricted

PSA 只通过命名空间标签工作。共有三种模式(enforce/audit/warn),另加一个固定版本的标签。enforce 是实际阻止的级别,audit/warn 用于预览“提升后会破坏什么”。

创建 restricted 命名空间

创建命名空间 kcsa-psa-restricted,添加四个标签:pod-security.kubernetes.io/enforce=restrictedpod-security.kubernetes.io/enforce-version=v1.30pod-security.kubernetes.io/audit=restrictedpod-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: truesecurityContext.seccompProfile.type: RuntimeDefault;容器级设置 allowPrivilegeEscalation: falsecapabilities.drop: ["ALL"]runAsUser: 1000

需要四项要求,其中两项位于 Pod 级 securityContext,两项位于容器级。若混淆位置,拒绝消息会告诉你。还必须明确指定 runAsUser。

整理豁免配置与豁免维度

/root/kcsa-psa/exempt.yaml 中编写 AdmissionConfiguration:plugins[0].namePodSecurityconfiguration.kindPodSecurityConfigurationdefaults.enforcebaselineexemptions.namespaces 的第一项为 kube-system。再在 /root/kcsa-psa/exempt-note.txt 中逐行准确写出 PSA 豁免的三个维度:usernamesruntimeClassesnamespaces

豁免无法用命名空间标签表示,要写入 apiserver 的准入配置文件。本实验只编写该文件。豁免有三个维度,请思考各自按什么依据跳过检查。

只提升标签时现有 Pod 会怎样

只把 kcsa-psa-baselineenforce 标签改为 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,差异便会非常清楚。