LabHub
学习 学习路径 课程

Kubernetes 运维实务

按最小权限设计角色

在 LabHub 中继续学习

目标

亲手创建角色与绑定来设计最小权限,并养成使用 kubectl auth can-i 验证权限边界的习惯。

为什么重要

RBAC 中最容易让人混淆的一点是,决定作用域的不是角色,而是绑定。同一个 ClusterRole,通过 ClusterRoleBinding 绑定时作用于整个集群,通过 RoleBinding 绑定时则只在该命名空间有效。凭借这一特性,可以只定义一次通用权限集合 ClusterRole,再由各团队在自己的命名空间中复用。第二个陷阱是子资源。podspods/logpods/exec 是不同的资源名称,权限不会自动继承。要避免只读取日志的机器人顺带获得 shell 访问权限,就必须理解这种区分。最后,权限不是靠编写来确认,而是靠判定来确认。因此,不要只用眼睛阅读 manifest,而要通过 impersonation 询问。必须同时确认 yes 和 no,才能知道权限是否宽于实际需要。

步骤

  1. 创建命名空间 rbac-lab,并在其中创建 app-readerinspectorlog-bot 三个服务账号。
  2. rbac-lab 中创建 Role pod-reader。只包含一条规则:apiGroups 为核心组(空字符串),resourcespodsverbsgetlistwatch。任何位置都不得使用通配符 *
  3. rbac-lab 中创建 RoleBinding read-podsroleRef 的 kind 为 Role,name 为 pod-reader;主体的 kind 为 ServiceAccount,name 为 app-reader,namespace 为 rbac-lab
  4. impersonate app-reader 检查权限,并将结果保存到 /root/ops/rbac/out/can-i.txt。文件中必须同时包含 yesno 响应。至少检查以下三项——在 rbac-lab 中列出 Pod(yes)、在 rbac-lab 中删除 Pod(no)、在 default 命名空间中列出 Pod(no)。
  5. 创建 ClusterRole node-viewerresources 中包含 nodes,所有规则的 verbs 只能是 getlistwatch。接着通过 ClusterRoleBinding node-viewer-binding 把该角色授予 rbac-lab 中的 app-reader。最终,app-reader 应能查看节点,但不能删除节点。
  6. 创建 ClusterRole ns-inspector(必须能够读取 ConfigMap)。然后在 rbac-lab 中创建 RoleBinding inspect-here,将 roleRef.kind 设为 ClusterRole,name 设为 ns-inspector,主体设为 rbac-lab 中的 inspector。最终,inspector 能在 rbac-lab 中读取 ConfigMap,但不能在 default 中读取。
  7. rbac-lab 中创建 Role log-readerresources 中只加入 pods/log不要加入 pods。通过 RoleBinding 把该角色授予 log-bot。最终,log-bot 能读取 pods/log,不能读取 pods 本身,也不能使用 pods/exec
  8. 创建 /root/ops/rbac/out/rbac-audit.json,包含四个字段。cluster_admin_bindingsroleRef.namecluster-admin 的 ClusterRoleBinding 名称数组,其数量必须与真实集群中的数量完全一致,并包含默认绑定 cluster-adminwildcard_roles 是使用 * 的角色名称数组(至少 1 个),secret_readers 是处理 secrets 的角色名称数组(至少 1 个),least_privilege_violations 是被判定为违反最小权限的项目数组。

参考

准备命名空间与服务账号

创建命名空间 rbac-lab,并在其中创建 app-readerinspectorlog-bot 三个服务账号。

只有先有主体,才能授予权限。服务账号属于命名空间,只需指定名称即可创建。

创建只读 Role

rbac-lab 中创建 Role pod-reader。只包含一条规则:apiGroups 为核心组(空字符串),resourcespodsverbsgetlistwatch。任何位置都不得使用通配符 *

请确认核心资源的 API 组名称是什么。只读操作集合包含三个动词,并且不要使用通配符。

把 Role 绑定到服务账号

rbac-lab 中创建 RoleBinding read-podsroleRef 的 kind 为 Role,name 为 pod-reader;主体的 kind 为 ServiceAccount,name 为 app-reader,namespace 为 rbac-lab

当主体是服务账号时,只有名称还不够,还必须写明它属于哪个命名空间。

通过 impersonation 检查权限边界

impersonate app-reader 检查权限,并将结果保存到 /root/ops/rbac/out/can-i.txt。文件中必须同时包含 yesno 响应。至少检查以下三项——在 rbac-lab 中列出 Pod(yes)、在 rbac-lab 中删除 Pod(no)、在 default 命名空间中列出 Pod(no)。

请记住服务账号完整名称的格式。必须同时检查允许和拒绝的操作,边界才会显现。

为集群作用域资源创建 ClusterRole

创建 ClusterRole node-viewerresources 中包含 nodes,所有规则的 verbs 只能是 getlistwatch。接着通过 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-readerresources 中只加入 pods/log不要加入 pods。通过 RoleBinding 把该角色授予 log-bot。最终,log-bot 能读取 pods/log,不能读取 pods 本身,也不能使用 pods/exec

日志的资源名称与 Pod 不同。如果连父资源也一并开放,这一步就失去了意义。

制作权限审计报告

创建 /root/ops/rbac/out/rbac-audit.json,包含四个字段。cluster_admin_bindingsroleRef.namecluster-admin 的 ClusterRoleBinding 名称数组,其数量必须与真实集群中的数量完全一致,并包含默认绑定 cluster-adminwildcard_roles 是使用 * 的角色名称数组(至少 1 个),secret_readers 是处理 secrets 的角色名称数组(至少 1 个),least_privilege_violations 是被判定为违反最小权限的项目数组。

不要手工统计,请从集群中提取。cluster-admin 绑定的数量必须与实际值完全一致。