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

KCSA — Kubernetes 安全助理

用攻击者的眼睛打开集群

在 TT Lab 中继续学习

本实验在真正的集群上运行

KCSA 考的是威胁模型和攻击面。要学会它,就得 真的去偷一偷看——从存储里取出明文,在没有权限的情况下读出 Secret,并看到审计日志里留下了它的痕迹。

假集群里没有存储,没有 apiserver 的认证链,也没有审计日志,所以这一切都只停留在文字上。嘴上听说“base64 不是加密”,和亲手从存储里取出明文,是两回事。

要避免与 CKS 重复。CKS 是 拦截 的实验,而这里的 KCSA,是用攻击来展示 为什么必须拦截。

第一次启动大约需要 2 分钟。

步骤

  1. 创建 Secret,并把 从存储中以明文取出 的内容写入 /root/kcsa/plaintext.txt。
  2. 打开 静态数据加密,并把明文消失这件事写入 /root/kcsa/encrypt.txt。
  3. 把旧 Secret 必须重写 才会被加密这件事,写入 /root/kcsa/rewrite.txt。
  4. 对 app 应用 PSA enforce=restricted、enforce-version=v1.36。只授予 runner SA 在 app 中的 pods get、list、create,不要允许 secrets get。在 /root/kcsa/leak.yaml 中编写 namespace app 的 leak Pod。使用 restartPolicy=Never、runner SA、关闭自动令牌挂载、runAsNonRoot 和 UID 65532、RuntimeDefault seccomp、allowPrivilegeEscalation=false、capabilities drop ALL。一个容器用 busybox:1.36 运行 command: [sha256sum, /s/password],并把 db Secret 卷 s 以只读方式挂载到 /s。不要用管理员创建来代替,要用 --as=system:serviceaccount:app:runner 创建。确认 Succeeded 之后,在 /root/kcsa/escalate.txt 中写下 direct_secret=no、create_pod=yes、psa=restricted、secret_mount=readable,以及实际日志中的一行哈希,并说明 PSA 会拦住的运行设置和拦不住的数据访问边界。不要输出合成密钥的原文。
  5. 用匿名和默认 SA 去敲 apiserver 的门,把 认证边界 写入 /root/kcsa/anon.txt。
  6. 在 /etc/kubernetes/audit.yaml 中写审计策略。第一条规则要对 core 组的 secrets、configmaps、serviceaccounts/token,不限用户、动词和命名空间,以 Metadata 级别保护。接下来只把 /healthz、/readyz、/livez 及它们各自的 /* 子路径设为 None,最后一条是无条件的 Metadata。omitStages 只能省略 RequestReceived。总共使用 3 条规则,或者在兜底的默认规则之前再加上一条 RBAC 写入详细规则,共 4 条。可选的详细规则,只对 rbac.authorization.k8s.io 的 roles、rolebindings、clusterroles、clusterrolebindings 的 create、update、patch、delete、deletecollection,以 RequestResponse 记录。在 /etc/rancher/k3s/config.yaml.d/90-labhub-audit.yaml 中用 kube-apiserver-arg+ 追加审计参数,以保留现有的加密设置,然后重启 k3s。日志限制为 /var/log/kubernetes/audit.log、blocking 模式、maxsize=5、maxbackup=1、maxage=1。准备完成后,用提供的辅助工具 python3 /opt/fixtures/audit-evidence.py capture --policy /etc/kubernetes/audit.yaml --log /var/log/kubernetes/audit.log --case /root/kcsa/audit-case.json --events /root/kcsa/audit-evidence.jsonl,收集合成 Secret 的创建 201、查询 200、拒绝 403、删除 200。保留四个不含正文的 Metadata 事件和策略指纹,并把结果说明写入 /root/kcsa/audit.txt。辅助工具不会修改策略,也不会放入真实密钥。
  7. 把到目前为止的内容用 4C 和 STRIDE 整理,写入 /root/kcsa/model.txt。
  8. 在 /root/kcsa/report.md 中写 plaintext_found=yes、encrypted=yes、audit_lines= 三行以及说明。

参考

这是 70 分钟的实验,所以请在到期之前用+时间延长(最长 180 分钟)。会话结束时,工作成果会消失。

base64 不是加密

创建 Secret,并把 从存储中以明文取出 的内容写入 /root/kcsa/plaintext.txt。

用 sqlite3 打开存储,在 hex(value) 里找明文。

打开静态数据加密

打开 静态数据加密,并把明文消失这件事写入 /root/kcsa/encrypt.txt。

写一份 EncryptionConfiguration,用 --encryption-provider-config 传给 apiserver。

旧 Secret 必须重写才会改变

把旧 Secret 必须重写 才会被加密这件事,写入 /root/kcsa/rewrite.txt。

用 kubectl get secret -o json | kubectl replace -f - 重写。

Restricted 的 Pod 也能读取 Secret 卷

对 app 应用 PSA enforce=restricted、enforce-version=v1.36。 只授予 runner SA 在 app 中的 pods get、list、create,不要允许 secrets get。 在 /root/kcsa/leak.yaml 中编写 namespace app 的 leak Pod。使用 restartPolicy=Never、 runner SA、关闭自动令牌挂载、 runAsNonRoot 和 UID 65532、RuntimeDefault seccomp、allowPrivilegeEscalation=false、 capabilities drop ALL。一个容器用 busybox:1.36 运行 command: [sha256sum, /s/password],并把 db Secret 卷 s 以只读方式 挂载到 /s。不要用管理员创建来代替,要用 --as=system:serviceaccount:app:runner 创建。确认 Succeeded 之后,在 /root/kcsa/escalate.txt 中写下 direct_secret=no、 create_pod=yes、psa=restricted、secret_mount=readable,以及实际日志中的一行哈希, 并说明 PSA 会拦住的运行设置和拦不住的数据访问边界。不要输出合成密钥的原文。

发出请求的主体和 Pod 的 SA 是不同的。用 runner 来创建,并区分 PSA 的运行条件和对 Secret 的引用。

敲一敲认证边界

用匿名和默认 SA 去敲 apiserver 的门,把 认证边界 写入 /root/kcsa/anon.txt。

请用匿名请求和默认 SA 令牌直接调用 apiserver。

不留下记录,就等于没发生过

在 /etc/kubernetes/audit.yaml 中写审计策略。第一条规则要对 core 组的 secrets、configmaps、serviceaccounts/token,不限用户、动词和命名空间,以 Metadata 级别保护。接下来只把 /healthz、/readyz、/livez 及它们各自的 /* 子路径设为 None,最后一条是无条件的 Metadata。omitStages 只能省略 RequestReceived。总共使用 3 条规则,或者在兜底的默认规则之前再加上一条 RBAC 写入详细规则,共 4 条。可选的详细规则,只对 rbac.authorization.k8s.io 的 roles、rolebindings、clusterroles、clusterrolebindings 的 create、update、patch、delete、deletecollection,以 RequestResponse 记录。在 /etc/rancher/k3s/config.yaml.d/90-labhub-audit.yaml 中用 kube-apiserver-arg+ 追加审计参数,以保留现有的加密设置,然后重启 k3s。日志限制为 /var/log/kubernetes/audit.log、blocking 模式、maxsize=5、maxbackup=1、maxage=1。准备完成后,用提供的辅助工具 python3 /opt/fixtures/audit-evidence.py capture --policy /etc/kubernetes/audit.yaml --log /var/log/kubernetes/audit.log --case /root/kcsa/audit-case.json --events /root/kcsa/audit-evidence.jsonl,收集合成 Secret 的创建 201、查询 200、拒绝 403、删除 200。保留四个不含正文的 Metadata 事件和策略指纹,并把结果说明写入 /root/kcsa/audit.txt。辅助工具不会修改策略,也不会放入真实密钥。

保护规则必须先匹配。omitStages 不是删除正文。请区分策略的编写和实际完成事件的收集。

用 4C 和 STRIDE 整理

把到目前为止的内容用 4C 和 STRIDE 整理,写入 /root/kcsa/model.txt。

请把到目前为止看到的攻击,分别对应到 4C 的层和 STRIDE 的类别上。

学到了什么

在 /root/kcsa/report.md 中写 plaintext_found=yes、encrypted=yes、audit_lines= 三行以及说明。

写 plaintext_found=yes、encrypted=yes、audit_lines= 三行以及说明。