LabHub
学习 学习路径 课程

KCSA — Kubernetes 安全助理

控制平面加固检查

在 LabHub 中继续学习

目标

整理控制平面组件的危险设置清单,亲手编写 etcd 静态加密配置,通过 kubectl auth can-i 测量并确认命名空间隔离和匿名访问范围,最后编写汇总证据的加固报告。

为什么重要

安全检查真正获得信任的时刻,不是说“最好这样做”,而是展示**“当前集群就是这样”**。kubectl auth can-i --as= 是生成这类证据的工具。与其阅读 RBAC 清单并在脑中计算,不如直接询问 apiserver;即使存在绑定重叠或组继承等复杂情况,也能得到准确答案。

亲手编写 EncryptionConfiguration,是因为 providers 数组的顺序决定一切。若把 identity 放在前面,就会一边以为已启用加密,一边仍以明文存储。这个错误不会报错,因此很难察觉。

本实验环境无法修改 apiserver 进程的真实标志。因此第 2、3、4 步采用编写检查产物的形式。也请一并了解,实际应对 CIS 基准时正是这种形态——留下配置依据往往比修改设置更耗时。

步骤

  1. 创建目录 /root/kcsa-hard 和命名空间 kcsa-hard
  2. /root/kcsa-hard/risky-flags.txt 中严格按以下形式写五行生产 apiserver 不应存在的设置:--anonymous-auth=true--authorization-mode=AlwaysAllow--insecure-port=8080--profiling=true--service-account-lookup=false。不要加入其他行。
  3. /root/kcsa-hard/encryption-config.yaml 中编写 EncryptionConfiguration:apiVersion 为 apiserver.config.k8s.io/v1,目标资源为 secrets,providers 正好 2 个,按正确顺序放置 aescbc(键名 key1,secret 是经过 base64 编码的真实值)和 identity
  4. /root/kcsa-hard/kubelet-checklist.txt 中严格按以下形式写四行 kubelet 加固项:authentication.anonymous.enabled=falseauthentication.webhook.enabled=trueauthorization.mode=WebhookreadOnlyPort=0。不要加入其他行。
  5. 创建命名空间 kcsa-team-akcsa-team-b,并分别创建 ServiceAccount app。在 kcsa-team-a 中创建 Role pod-reader(对核心组 pods 授予 getlist)和 RoleBinding app-pod-reader(目标是 kcsa-team-a 的 SA app)。随后在两个命名空间分别运行 kubectl auth can-i list pods,并使用 --as=system:serviceaccount:kcsa-team-a:app,确认答案不同。
  6. 以匿名用户询问三项权限,将结果保存到 /root/kcsa-hard/anon.txt,内容为三行 키=값get-pods=(在命名空间 kcsa-hard 中 get Pod)、list-secrets=(在全部命名空间 list secrets)、healthz=(get 非资源路径 /healthz)。匿名主体无法通过 --as 模拟(见下文),因此使用管理员权限创建 SubjectAccessReview,读取 .status.allowed,将 true 写为 yes,false 写为 no
  7. 编写 /root/kcsa-hard/hardening-report.md。以下五行必须原样作为章节标题:## apiserver## etcd## kubelet## namespace## anonymous。正文还必须提及以下五项证据:--anonymous-auth=falseaescbcreadOnlyPort=0kcsa-team-bsystem:anonymous

参考

准备工作区和命名空间

创建目录 /root/kcsa-hard 和命名空间 kcsa-hard

创建一个用于集中存放产物的目录和一个实验命名空间。创建目录时有一个选项可一次建立所有中间路径。

编写 apiserver 危险标志清单

/root/kcsa-hard/risky-flags.txt 中严格按以下形式写五行生产 apiserver 不应存在的设置:--anonymous-auth=true--authorization-mode=AlwaysAllow--insecure-port=8080--profiling=true--service-account-lookup=false。不要加入其他行。

填写时思考每个标志破坏的是哪个阶段(认证、授权、信息暴露、令牌验证)。文件只能包含指定的五行,并须保留包含值的完整形式。

编写 EncryptionConfiguration

/root/kcsa-hard/encryption-config.yaml 中编写 EncryptionConfiguration:apiVersion 为 apiserver.config.k8s.io/v1,目标资源为 secrets,providers 正好 2 个,按正确顺序放置 aescbc(键名 key1,secret 是经过 base64 编码的真实值)和 identity

providers 数组的顺序具有含义:第一项用于写入,所有项用于读取,据此确定两个 provider 的顺序。secret 必须是经过 base64 编码的真实字符串,保留占位符无法通过。

整理 kubelet 认证与授权检查项

/root/kcsa-hard/kubelet-checklist.txt 中严格按以下形式写四行 kubelet 加固项:authentication.anonymous.enabled=falseauthentication.webhook.enabled=trueauthorization.mode=WebhookreadOnlyPort=0。不要加入其他行。

用点号形式写 kubelet 配置文件(KubeletConfiguration)的字段路径,涵盖匿名访问、Webhook 认证、授权模式和只读端口。思考授权模式使用 AlwaysAllow 会让什么失去意义。

用 can-i 证明命名空间隔离

创建命名空间 kcsa-team-akcsa-team-b,并分别创建 ServiceAccount app。在 kcsa-team-a 中创建 Role pod-reader(对核心组 pods 授予 getlist)和 RoleBinding app-pod-reader(目标是 kcsa-team-a 的 SA app)。随后在两个命名空间分别运行 kubectl auth can-i list pods,并使用 --as=system:serviceaccount:kcsa-team-a:app,确认答案不同。

Role 只在自身命名空间有效。不能只做断言,要通过测量证明:以同一 ServiceAccount 分别询问两个命名空间,答案会不同。可用 --as 模拟其他主体。

观察匿名用户能做什么

以匿名用户询问三项权限,将结果保存到 /root/kcsa-hard/anon.txt,内容为三行 키=값get-pods=(在命名空间 kcsa-hard 中 get Pod)、list-secrets=(在全部命名空间 list secrets)、healthz=(get 非资源路径 /healthz)。匿名主体无法通过 --as 模拟(见下文),因此使用管理员权限创建 SubjectAccessReview,读取 .status.allowed,将 true 写为 yes,false 写为 no

本步骤不能背答案。必须直接询问当前集群并原样转录结果。但匿名主体不能用 kubectl auth can-i --as=system:anonymous 查询,因为匿名用户无权创建该命令使用的审查对象。另有一种由管理员代问的审查对象,也能查询非资源路径。

汇总成加固报告

编写 /root/kcsa-hard/hardening-report.md。以下五行必须原样作为章节标题:## apiserver## etcd## kubelet## namespace## anonymous。正文还必须提及以下五项证据:--anonymous-auth=falseaescbcreadOnlyPort=0kcsa-team-bsystem:anonymous

根据前五步的产物编写文档。章节标题必须与指定形式完全一致,正文必须包含支持各节结论的具体值。