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

KCSA — Kubernetes 安全助理

能创建角色,就能成为管理员吗

在 TT Lab 中继续学习

目标

用低权限的 ServiceAccount 尝试 RBAC 权限提升,观察 apiserver 的权限提升防护(escalate/bind)是否真的挡住了这种尝试。并确认只有合法的管理员才能把权限交出去,模拟身份(impersonation)同样是受到单独保护的权限,把这些以报告的形式留下来。

为什么重要

RBAC 里最危险的失误,是把“能创建 Role 的权限”交出去,实际上就等于交出了“能成为任何东西的权限”。如果只要有创建 Role 的权限,就能给自己创建并绑定一个包含 Secret 权限的 Role,那么这个 ServiceAccount 转眼就成了集群管理员。

Kubernetes 在 apiserver 层面堵住了这一点——不能创建或绑定包含自己当前并不拥有的权限的 Role(权限提升防护)。所以即使给了创建 Role 的权限,也不会直接导致特权扩大。亲眼看到这条边界不在代码里,而在 apiserver 的批准阶段,以及为什么像 impersonate 这样的动词被单独当作危险动词来对待,是这个实验的核心。

步骤

  1. 创建命名空间 kcsa-priv 和 ServiceAccount lowpriv。
  2. 给 lowpriv 绑定只允许创建 Role、RoleBinding 的 Role rolemaker。
  3. 以管理员身份创建作为目标的 ClusterRole secret-admin(Secret 的 get/list)。
  4. 确认以 lowpriv 的身份尝试创建带 Secret 权限的 Role 时被拒绝,并保存下来。
  5. 确认以 lowpriv 的身份尝试把 secret-admin 绑定给自己时被拒绝,并保存下来。
  6. 由管理员正式把 secret-admin 绑定给 lowpriv,让它现在能读取 Secret。
  7. 确认没有模拟身份权限的 ServiceAccount auditor2 无法冒充别人。
  8. 把什么被拦住、什么通过了,记录到 report.txt。

参考

准备低权限主体

创建命名空间 kcsa-priv 以及其中的 ServiceAccount lowpriv。暂时不给任何权限。

ServiceAccount 是命名空间里的主体(subject)。把 create 用 --dry-run=client 生成后再 apply,运行多次也安全。这一步不给 lowpriv 绑定任何 Role。

只把创建 Role 的权限交给它

在命名空间 kcsa-priv 中创建 Role rolemaker——apiGroups 为 rbac.authorization.k8s.io,resources 为 roles、rolebindings,verbs 为 create、get、list。然后用 RoleBinding(rolemaker-binding)把这个 Role 绑定到 ServiceAccount lowpriv。lowpriv 可以创建 Role 和 RoleBinding,但不能有 Secret 权限。

RBAC 分为 Role(权限的集合)和 RoleBinding(连接到主体)。对 kubectl create role、create rolebinding 使用 --verb、--resource、--serviceaccount。请记住,lowpriv 在这一步之后获得了创建 Role 的权限,但对 Secret 仍然没有权限——这是后面几步的关键。

诱人的目标——读取 Secret 的权限

以管理员权限创建 ClusterRole secret-admin——对核心组 secrets 的 get、list 权限。这是后面的步骤里,lowpriv 试图拿到手的目标权限。

ClusterRole 是不绑定命名空间的权限集合。对 kubectl create clusterrole 使用 --verb、--resource。这一步直接用默认的 kubeconfig(cluster-admin)创建即可。

想把自己没有的权限给自己,却被挡住

现在以 lowpriv 的身份(--as=system:serviceaccount:kcsa-priv:lowpriv),试着在命名空间 kcsa-priv 中创建包含 Secret get 权限的 Role sneaky。lowpriv 没有 Secret 权限,所以 apiserver 必须拒绝这次创建。把拒绝消息原样保存到 /root/kcsa-priv/escalate-denied.txt。

RBAC 有权限提升防护规则——不能创建包含自己没有的权限的 Role。即使有创建 Role 的权限(第 2 步),这条规则也会另外起作用。命令失败才是正常的,所以要把标准错误也一起存入文件(2>&1)。消息里会看到 'forbidden' 和 'not currently held'。

想把目标权限绑定给自己,却被挡住

以 lowpriv 的身份(--as=system:serviceaccount:kcsa-priv:lowpriv),试着在命名空间 kcsa-priv 中创建把 ClusterRole secret-admin 绑定给自己(lowpriv)的 RoleBinding grab。这同样是把 lowpriv 没有的权限交出去,所以必须被拒绝。把拒绝消息保存到 /root/kcsa-priv/bind-denied.txt。

lowpriv 可以创建 RoleBinding(第 2 步)。但是,要绑定包含自己没有的权限的 Role,要么自己已经有这个权限,要么对目标 Role 有 bind 权限。两者都没有,所以 apiserver 会拦住。失败才是正常的,所以用 2>&1 把错误也存下来。

管理员正式交出权限

这次用管理员权限(默认 kubeconfig),在命名空间 kcsa-priv 中创建把 ClusterRole secret-admin 绑定到 ServiceAccount lowpriv 的 RoleBinding granted。现在 lowpriv 应该能够在 kcsa-priv 中 get Secret。

边界不在于 lowpriv 的“创建 RoleBinding 的能力”,而在于 apiserver 的权限提升检查。已经拥有这个权限的管理员创建绑定,就能通过。用 --clusterrole 和 --serviceaccount 创建绑定,并确认 auth can-i get secrets --as=<lowpriv> 是否变成了 yes。

冒充别人的权限也受到单独保护

在命名空间 kcsa-priv 中创建 ServiceAccount auditor2(不给它模拟身份的权限)。确认 auditor2 能不能冒充其他用户(impersonate users),看到没有权限的主体无法模拟身份。

模拟身份(--as)本身就是另外的 RBAC 权限(对 users/groups/serviceaccounts 资源的 impersonate 动词)。没有被授予权限的 ServiceAccount,auth can-i impersonate users --as=<그 SA>(占位符为该 SA)必须是 no。请与管理员(默认 kubeconfig)是 yes 这一点做个对比。

把什么被拦住、什么通过了,以账簿的形式留下

把观察结果恰好写成四行,保存到 /root/kcsa-priv/report.txt——self-escalate-role=blocked、self-bind-clusterrole=blocked、admin-grant=allowed、impersonate-without-verb=blocked。值必须与集群的实际行为一致。

评分器会在集群里重新确认这四行——以 lowpriv 重新尝试自我提升是否失败,管理员绑定之后 lowpriv 能否 get Secret,auditor2 能否模拟身份。不要靠猜测来写,要把前面步骤里看到的结果原样抄过来。