TT Lab
开始
学习 学习路径 课程

KCSA — Kubernetes 安全助理

审计员来了,却拿不出“已启用”的证据

在 TT Lab 中继续学习

目标

在集群里 亲自确认 若干安全控制项(阻止匿名访问、强制 Pod Security、关闭 ServiceAccount 令牌自动挂载、资源配额),并把结果以按控制 ID 分列的 pass/fail 报告和缺陷清单的形式留下来。

为什么重要

CIS Kubernetes Benchmark、NSA/CISA 加固指南、SOC 2 和 ISO 27001 这类框架,说到底都是在问“这项控制有没有打开”的问题清单。在审计中成为问题的,比起没有控制,更多是 写着打开了,实际上却是关着的。所以报告里的每一行,都应该来自集群现在给出的答案(auth can-i、对象字段、标签),而不是来自配置文件或记忆。

还有,不能只看加固过的地方就结束。找出像没人动过的 default 命名空间这样 留在控制之外的位置,并记为缺陷,是合规检查的一半。

步骤

  1. 创建检查对象命名空间 kcsa-comp。
  2. 询问 system:anonymous 能不能 list Secret,并记录到 anon.txt。
  3. 给 kcsa-comp 加上 pod-security.kubernetes.io/enforce=restricted 标签。
  4. 创建满足全部 restricted 要求的 Pod hardened。
  5. 关闭 default ServiceAccount 的令牌自动挂载。
  6. 用 ResourceQuota quota 设置命名空间资源上限。
  7. 把四个控制项的实际结果写成 compliance.csv 报告。
  8. 找出没有 enforce 标签的命名空间,作为缺陷记录到 gaps.txt。

参考

建立审计对象命名空间

创建将作为合规检查对象的命名空间 kcsa-comp。

审计从划定范围开始。命名空间用 create 配合 --dry-run=client 生成再 apply,运行多次也安全。

没有登录的人能不能看到 Secret

直接向集群询问未认证的用户(system:anonymous)在命名空间 kcsa-comp 中能不能 list Secret,并把答案以 anonymous-list-secrets=<yes|no> 一行写入 /root/kcsa-comp/anon.txt。

先给 kubectl auth can-i 加上 --as=system:anonymous 试试。得到的不是答案,而是拒绝——can-i 是以该用户自己的身份创建 SelfSubjectAccessReview,而匿名用户连这个都做不到。所以要由管理员代为询问,创建 SubjectAccessReview(authorization.k8s.io/v1),填好 spec.user、groups(system:unauthenticated)、resourceAttributes,读取 status.allowed。如果是 false,就是 no。

给命名空间立一个 restricted 门卫

给命名空间 kcsa-comp 加上 Pod Security Admission 标签 pod-security.kubernetes.io/enforce=restricted(想要的话,也可以同时加 warn、audit 标签)。

Pod Security Standards 靠一个命名空间标签就能打开。标签键是 pod-security.kubernetes.io/<모드>(占位符为模式),值是 privileged、baseline、restricted 之一。在 kubectl label 上加 --overwrite,再次运行也安全。

放进一个通过 restricted 标准的 Pod

在命名空间 kcsa-comp 中创建 Pod hardened(镜像 nginx:1.27-alpine)。在 Pod 级别声明 runAsNonRoot: true 和 seccompProfile.type: RuntimeDefault,在容器级别声明 allowPrivilegeEscalation: false、capabilities.drop: [ALL]、runAsNonRoot: true,满足 restricted 配置档的全部要求。

restricted 配置档要求不以 root 运行、阻止权限提升、丢弃所有 capability、指定 seccomp 配置档。securityContext 有 Pod 级别(spec.securityContext)和容器级别(containers[].securityContext)两处,每个字段能放的位置不同。只要有一项要求缺失,就可能因为第 3 步的标签而被拒绝创建。

没用到的令牌被插进了所有 Pod

给命名空间 kcsa-comp 的 default ServiceAccount 设置 automountServiceAccountToken: false,让没有另外请求的 Pod 不会自动挂载 API 令牌。

命名空间一创建,控制器就会帮你创建 default ServiceAccount。如果还没有,请稍等一会儿再确认。这个字段是 ServiceAccount 对象的顶层字段,可以用 patch 来改。

别让一个团队把集群吃光

在命名空间 kcsa-comp 中创建 ResourceQuota quota,把 pods=10、requests.cpu=2、requests.memory=2Gi 设为上限。

ResourceQuota 是限制整个命名空间总量的对象,在 spec.hard 下写出资源名称和上限。可以在 kubectl create quota 上用 --hard,把多个条目用逗号连起来。

交给审计员的控制项报告

创建 /root/kcsa-comp/compliance.csv。第一行是表头 control,status,下面把四个控制项 anonymous-access、psa-enforce、sa-token-automount、resource-quota 各写一行,status 里写实际确认的结果(pass 或 fail)。四个项目都必须是通过状态。

报告中的值不是声明,而是证据。评分器会对每一行在集群里重新确认对应的控制,如果写下的 status 与实际状态不同,就判为失败。想一想第 2、3、5、6 步里看到的结果,各自对应哪个控制项,写之前再确认一遍。

默认命名空间由谁在守护

没有 PSA enforce 标签的命名空间属于合规缺陷(gap)。确认集群的 default 命名空间是否有 enforce 标签,把有缺陷的命名空间名称以 psa-missing-namespace=<네임스페이스>(占位符为命名空间)一行写入 /root/kcsa-comp/gaps.txt。(不要加标签去修复——这一步是记录发现的步骤。)

想一次看到所有命名空间的标签,就在 kubectl get ns 上使用增加标签列的选项。把刚刚加固过的命名空间和没人动过的命名空间并排放在一起比较,缺陷就看出来了。