按最小权限设计角色
目标
亲手创建角色与绑定来设计最小权限,并养成使用 kubectl auth can-i 验证权限边界的习惯。
为什么重要
RBAC 中最容易让人混淆的一点是,决定作用域的不是角色,而是绑定。同一个 ClusterRole,通过 ClusterRoleBinding 绑定时作用于整个集群,通过 RoleBinding 绑定时则只在该命名空间有效。凭借这一特性,可以只定义一次通用权限集合 ClusterRole,再由各团队在自己的命名空间中复用。第二个陷阱是子资源。pods、pods/log、pods/exec 是不同的资源名称,权限不会自动继承。要避免只读取日志的机器人顺带获得 shell 访问权限,就必须理解这种区分。最后,权限不是靠编写来确认,而是靠判定来确认。因此,不要只用眼睛阅读 manifest,而要通过 impersonation 询问。必须同时确认 yes 和 no,才能知道权限是否宽于实际需要。
步骤
- 创建命名空间
rbac-lab,并在其中创建app-reader、inspector、log-bot三个服务账号。 - 在
rbac-lab中创建 Rolepod-reader。只包含一条规则:apiGroups为核心组(空字符串),resources为pods,verbs为get、list、watch。任何位置都不得使用通配符*。 - 在
rbac-lab中创建 RoleBindingread-pods。roleRef的 kind 为Role,name 为pod-reader;主体的 kind 为ServiceAccount,name 为app-reader,namespace 为rbac-lab。 - impersonate
app-reader检查权限,并将结果保存到/root/ops/rbac/out/can-i.txt。文件中必须同时包含yes和no响应。至少检查以下三项——在rbac-lab中列出 Pod(yes)、在rbac-lab中删除 Pod(no)、在default命名空间中列出 Pod(no)。 - 创建 ClusterRole
node-viewer。resources中包含nodes,所有规则的verbs只能是get、list、watch。接着通过 ClusterRoleBindingnode-viewer-binding把该角色授予rbac-lab中的app-reader。最终,app-reader应能查看节点,但不能删除节点。 - 创建 ClusterRole
ns-inspector(必须能够读取 ConfigMap)。然后在rbac-lab中创建 RoleBindinginspect-here,将roleRef.kind设为ClusterRole,name 设为ns-inspector,主体设为rbac-lab中的inspector。最终,inspector能在rbac-lab中读取 ConfigMap,但不能在default中读取。 - 在
rbac-lab中创建 Rolelog-reader。resources中只加入pods/log,不要加入pods。通过 RoleBinding 把该角色授予log-bot。最终,log-bot能读取pods/log,不能读取pods本身,也不能使用pods/exec。 - 创建
/root/ops/rbac/out/rbac-audit.json,包含四个字段。cluster_admin_bindings是roleRef.name为cluster-admin的 ClusterRoleBinding 名称数组,其数量必须与真实集群中的数量完全一致,并包含默认绑定cluster-admin。wildcard_roles是使用*的角色名称数组(至少 1 个),secret_readers是处理secrets的角色名称数组(至少 1 个),least_privilege_violations是被判定为违反最小权限的项目数组。
参考
- 服务账号的完整主体名称为
system:serviceaccount:<네임스페이스>:<이름>。请使用kubectl auth can-i <동사> <리소스> -n <네임스페이스> --as=<주체>形式进行询问。 - 在
kubectl create role/create clusterrole/create rolebinding后添加--dry-run=client -o yaml,可以得到正确的 manifest 骨架。使用--serviceaccount=<네임스페이스>:<이름>时,会自动填写主体的 namespace 字段。 - 第 8 步手工统计几乎一定会出错。请通过
kubectl get clusterrolebindings -o json | jq提取数据。要找通配符角色,可以从kubectl get roles,clusterroles -A -o json中筛选verbs或resources含*的项目。 - 常见错误 1:在
apiGroups中填写"v1"或"core"。核心组的名称是空字符串。 - 常见错误 2:第 7 步同时加入
pods和pods/log。这样会连 Pod 本身也可读取,失去练习子资源隔离的意义。 - 常见错误 3:第 5 步创建 ClusterRole 后用 RoleBinding 进行绑定。节点不属于任何命名空间,因此 RoleBinding 不会授予其访问权限。
- 每次实验都会启动新的实验 Pod,因此前一个实验中创建的集群状态不会保留。请在本实验中自行创建命名空间和服务账号。这正是必须把运维流程写入 runbook 和 manifest,而不能依靠记忆的原因。
准备命名空间与服务账号
创建命名空间 rbac-lab,并在其中创建 app-reader、inspector、log-bot 三个服务账号。
只有先有主体,才能授予权限。服务账号属于命名空间,只需指定名称即可创建。
创建只读 Role
在 rbac-lab 中创建 Role pod-reader。只包含一条规则:apiGroups 为核心组(空字符串),resources 为 pods,verbs 为 get、list、watch。任何位置都不得使用通配符 *。
请确认核心资源的 API 组名称是什么。只读操作集合包含三个动词,并且不要使用通配符。
把 Role 绑定到服务账号
在 rbac-lab 中创建 RoleBinding read-pods。roleRef 的 kind 为 Role,name 为 pod-reader;主体的 kind 为 ServiceAccount,name 为 app-reader,namespace 为 rbac-lab。
当主体是服务账号时,只有名称还不够,还必须写明它属于哪个命名空间。
通过 impersonation 检查权限边界
impersonate app-reader 检查权限,并将结果保存到 /root/ops/rbac/out/can-i.txt。文件中必须同时包含 yes 和 no 响应。至少检查以下三项——在 rbac-lab 中列出 Pod(yes)、在 rbac-lab 中删除 Pod(no)、在 default 命名空间中列出 Pod(no)。
请记住服务账号完整名称的格式。必须同时检查允许和拒绝的操作,边界才会显现。
为集群作用域资源创建 ClusterRole
创建 ClusterRole node-viewer。resources 中包含 nodes,所有规则的 verbs 只能是 get、list、watch。接着通过 ClusterRoleBinding node-viewer-binding 把该角色授予 rbac-lab 中的 app-reader。最终,app-reader 应能查看节点,但不能删除节点。
节点是不属于命名空间的资源,无法通过 Role 管理。若要作用于整个集群,绑定也必须是集群作用域。
使用 RoleBinding 绑定 ClusterRole
创建 ClusterRole ns-inspector(必须能够读取 ConfigMap)。然后在 rbac-lab 中创建 RoleBinding inspect-here,将 roleRef.kind 设为 ClusterRole,name 设为 ns-inspector,主体设为 rbac-lab 中的 inspector。最终,inspector 能在 rbac-lab 中读取 ConfigMap,但不能在 default 中读取。
决定作用域的是绑定类型,而不是角色类型。请确认同一角色为何只在某个命名空间中有效。
创建只开放子资源的角色
在 rbac-lab 中创建 Role log-reader。resources 中只加入 pods/log,不要加入 pods。通过 RoleBinding 把该角色授予 log-bot。最终,log-bot 能读取 pods/log,不能读取 pods 本身,也不能使用 pods/exec。
日志的资源名称与 Pod 不同。如果连父资源也一并开放,这一步就失去了意义。
制作权限审计报告
创建 /root/ops/rbac/out/rbac-audit.json,包含四个字段。cluster_admin_bindings 是 roleRef.name 为 cluster-admin 的 ClusterRoleBinding 名称数组,其数量必须与真实集群中的数量完全一致,并包含默认绑定 cluster-admin。wildcard_roles 是使用 * 的角色名称数组(至少 1 个),secret_readers 是处理 secrets 的角色名称数组(至少 1 个),least_privilege_violations 是被判定为违反最小权限的项目数组。
不要手工统计,请从集群中提取。cluster-admin 绑定的数量必须与实际值完全一致。