4. 基于角色的访问控制(RBAC)核心概念
OpenShift 的授权体系建立在 Kubernetes RBAC 之上,但通过默认角色、项目(Namespace)模型和 OAuth 集成做了增强。理解 RBAC,关键是先分清四个对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding。它们两两组合,分别回答两个问题:“允许做什么”(Role/ClusterRole)和“把权限给谁、在哪个范围生效”(RoleBinding/ClusterRoleBinding)。
很多初学者会把 Role 和 ClusterRole 理解为“小权限”和“大权限”,这并不准确。真正的区别在于作用范围与可复用性:Role 是命名空间内的权限集合,只能被同一命名空间内的 RoleBinding 引用;ClusterRole 是集群级权限集合,既可被 ClusterRoleBinding 引用(作用于整个集群),也可被 RoleBinding 引用(只作用于某个命名空间)。这一点是 OpenShift 权限治理中最容易被误用的地方。
四个对象的语义
Role:定义在某个命名空间内的一组规则(rules),每条规则由 apiGroups、resources、verbs 三要素构成。例如允许在 dev 命名空间中读取 Pod 和查看日志。Role 本身不授予任何人权限,它只是一份“权限清单”。
ClusterRole:同样是规则集合,但不属于任何命名空间。它常用于两类场景:一是集群级资源(如 nodes、persistentvolumes、clusterroles)的授权;二是定义一套可被多个命名空间复用的通用权限模板,例如“只读用户”“命名空间管理员”。
RoleBinding:把 Role 或 ClusterRole 绑定给主体(User、Group、ServiceAccount),并限定在某个命名空间内生效。当它引用 ClusterRole 时,效果是“把集群级权限模板裁剪到本命名空间使用”,这是 OpenShift 默认角色大量采用的方式。
ClusterRoleBinding:把 ClusterRole 绑定给主体,作用范围是整个集群,对所有命名空间及集群级资源生效。它不能引用 Role,因为 Role 是命名空间内的对象。
作用范围与组合关系
四种组合中,只有三种是合法的:Role + RoleBinding(命名空间内)、ClusterRole + RoleBinding(命名空间内复用集群模板)、ClusterRole + ClusterRoleBinding(集群范围)。Role + ClusterRoleBinding 不合法,因为 ClusterRoleBinding 无法引用命名空间对象。下面这张图展示了四种对象的语义、作用范围以及合法组合关系。
规则三要素与主体
无论 Role 还是 ClusterRole,其 rules 都由三要素描述:apiGroups 指定 API 组(核心组为空字符串 ""),resources 指定资源类型(如 pods、deployments、pods/log),verbs 指定动作(get、list、watch、create、update、patch、delete)。此外还可选 resourceNames 把权限收窄到具体对象名。绑定中的主体(subjects)有三种:User、Group、ServiceAccount。OpenShift 中用户和组来自 OAuth 身份提供者,ServiceAccount 则是 Pod 内进程使用的身份。
下面是一个命名空间内的只读 Role 与绑定示例,允许 dev 命名空间中的开发者组读取 Pod、查看日志,但不能修改:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-pod-reader
namespace: dev
subjects:
- kind: Group
name: dev-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
若希望同一套权限在多个命名空间复用,应改为定义 ClusterRole,再用各命名空间的 RoleBinding 引用它。例如 OpenShift 内置的 view、edit、admin 都是 ClusterRole,通过 RoleBinding 授予某个命名空间内的用户,从而避免为每个命名空间重复定义 Role。
OpenShift 默认角色与聚合
OpenShift 预置了大量 ClusterRole,常用的有:basic-user(所有认证用户默认拥有,可查看项目与自身权限)、self-provisioner(允许创建项目)、view(只读)、edit(可改工作负载但不能改配额与角色)、admin(命名空间管理员,可管理角色绑定)、cluster-admin(超级权限)。其中 view/edit/admin 使用聚合标签(aggregate-to-*),把其他 ClusterRole 的规则合并进来,便于扩展。
oc auth can-i <verb> <resource> -n <namespace>,或 oc auth can-i --list -n dev 查看当前身份在该命名空间内的全部权限。排查“为什么没有权限”时,先确认绑定所在命名空间与主体名称是否匹配,再确认 roleRef 指向的是 Role 还是 ClusterRole。
实践中的常见误区
- 把 ClusterRoleBinding 当“方便”用:给普通用户绑定 view 的 ClusterRoleBinding,会让其看到所有命名空间资源,违反最小权限原则。应优先用 RoleBinding 限定命名空间。
- 混淆 Role 与 ClusterRole 的引用限制:RoleBinding 可以引用 ClusterRole,但 ClusterRoleBinding 不能引用 Role。写错 kind 会导致绑定创建失败或权限不生效。
- 忽略 ServiceAccount 的绑定:Pod 内访问 API 使用的是 ServiceAccount,若未给对应 SA 绑定权限,应用会收到 403。需检查
oc get rolebinding,clusterrolebinding -A | grep <sa-name>。 - 权限叠加误判:RBAC 是纯加法模型,多个绑定叠加后取并集,不存在“拒绝”规则。因此一旦授予了过宽权限,只能通过删除绑定来收回。