RBAC(Role-Based Access Control,基于角色的访问控制)是 Kubernetes 集群里最核心的授权机制之一。它解决的问题很直接:谁可以对哪些资源执行哪些操作。在真实生产环境里,很多安全事故并不是“没做权限控制”,而是“权限给大了”“绑定范围搞错了”“以为只读其实能看到敏感数据”。Kubernetes 的 RBAC 正是为了把这些风险收敛到可管理的范围里::cite[166]。
本章你将学会
- 认证(Authentication)与鉴权/授权(Authorization)在 Kubernetes 中分别做什么
- Role、ClusterRole、RoleBinding、ClusterRoleBinding 的关系与使用边界
- 如何在集群里落实最小权限原则
- 常见 RBAC 配置错误,以及这些错误为什么危险
- 如何通过一套完整 YAML 给工作负载授予恰到好处的权限
1. 先理解:认证与鉴权不是一回事
在 Kubernetes API Server 处理请求时,通常会先经过两道关:
- 认证(Authentication):确认“你是谁”
- 授权(Authorization):确认“你能做什么”
例如,一个 Pod 使用 ServiceAccount Token 调用 API Server,API Server 会先识别这个请求对应的是哪个 ServiceAccount,再根据 RBAC 规则判断它是否有权限读取 ConfigMap、列出 Pod、创建 Job 等操作。RBAC 属于授权阶段,不负责证明身份真假,而是负责决定身份对应的操作边界::cite[166]。
可以把它理解成一张很实用的图:
| 阶段 | 关注点 | 典型问题 |
|---|---|---|
| 认证 Authentication | 你是谁 | 这个请求来自哪个用户 / 组 / ServiceAccount? |
| 授权 Authorization | 你能做什么 | 这个身份能不能 get pods、list secrets、create deployments? |
| 准入 Admission | 你这样做是否合规 | 即使你有权限,是否还需要经过策略校验? |
2. RBAC 四个核心对象
Kubernetes RBAC 主要由 4 类对象组成:Role、ClusterRole、RoleBinding、ClusterRoleBinding。其中 Role / ClusterRole 用来描述“权限集合”,Binding 用来描述“把权限授予谁”::cite[166]。
2.1 Role
Role 是命名空间级别的权限定义。它只能作用于某个 namespace 内的资源。
一个最典型的 Role,是允许读取某个 namespace 下的 Pod:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: demo
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
这里的含义很明确:在 demo 命名空间里,允许读取 Pod,但不允许删除、更新、创建。
2.2 ClusterRole
ClusterRole 是集群级别的权限定义。它有三种常见用法:
- 访问集群级资源,例如
nodes - 访问非资源 URL,例如
/healthz - 定义可复用权限,再通过
RoleBinding下发到多个命名空间::cite[166]
例如,定义一个可读取 Secret 的 ClusterRole:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
注意:ClusterRole 本身是集群级对象,但它不一定意味着“全命名空间生效”。真正决定作用范围的,是后面怎么绑定。
2.3 RoleBinding
RoleBinding 用来把 Role 或 ClusterRole 绑定给某个用户、组或 ServiceAccount,但它的生效范围始终是当前命名空间::cite[166]。
例如,把 pod-reader 这个 Role 绑定给某个 ServiceAccount:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: demo
subjects:
- kind: ServiceAccount
name: app-reader
namespace: demo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader
如果 RoleBinding 绑定的是 ClusterRole,它依然只在当前命名空间生效。
2.4 ClusterRoleBinding
ClusterRoleBinding 会把 ClusterRole 绑定到整个集群范围,这也是风险最高的一类绑定方式::cite[166]。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: secret-reader-global
subjects:
- kind: Group
name: ops-team
apiGroup: rbac.authorization.k8s.io
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: secret-reader
这意味着 ops-team 在所有 namespace 中都能读取 Secret。除非这是你明确想要的效果,否则不要轻易这么做。
3. 一张图记住对象关系
| 对象 | 作用 | 是否带 namespace | 典型使用场景 |
|---|---|---|---|
| Role | 定义命名空间内权限 | 是 | 某个业务命名空间内的读写控制 |
| ClusterRole | 定义集群级或可复用权限 | 否 | 节点权限、公共只读权限 |
| RoleBinding | 在命名空间内授予权限 | 是 | 把 Role/ClusterRole 授予某个 SA |
| ClusterRoleBinding | 在集群范围授予权限 | 否 | 平台管理员、集群级控制器 |
4. 实操:给一个应用只授予读取 ConfigMap 的权限
下面我们做一个很典型的场景:
- 在
demo命名空间部署一个应用 - 应用需要调用 Kubernetes API
- 它只能读取本 namespace 的 ConfigMap
- 它不应该拥有查看 Secret、创建 Pod、删除资源等能力
4.1 完整 YAML
apiVersion: v1
kind: Namespace
metadata:
name: demo
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: configmap-reader
namespace: demo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: configmap-read-only
namespace: demo
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: configmap-read-only-binding
namespace: demo
subjects:
- kind: ServiceAccount
name: configmap-reader
namespace: demo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: configmap-read-only
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
namespace: demo
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
serviceAccountName: configmap-reader
containers:
- name: app
image: nginx:1.27
ports:
- containerPort: 80
4.2 应用配置
kubectl apply -f rbac-demo.yaml
4.3 验证权限
先确认这个 ServiceAccount 是否能读取 ConfigMap:
kubectl auth can-i get configmaps \
--as=system:serviceaccount:demo:configmap-reader \
-n demo
预期输出:
yes
再测试它是否能读取 Secret:
kubectl auth can-i get secrets \
--as=system:serviceaccount:demo:configmap-reader \
-n demo
预期输出:
no
这就是最小权限原则最直接的落地方式:只给需要的资源、只给需要的动作、只给需要的命名空间::cite[167]。
5. 最小权限原则,应该怎样在集群里真正落地
Kubernetes 官方给出的 RBAC 最佳实践里,有几条非常值得长期执行:
- 尽量优先使用 namespace 级授权,优先
RoleBinding而不是ClusterRoleBinding - 避免使用
*通配符匹配所有资源和所有动词 - 不要把普通业务账号直接赋予
cluster-admin - 避免把用户加入
system:masters组,因为这会绕过 RBAC 检查::cite[167]
把这些原则翻译成平台治理动作,可以落成下面这张表:
| 落地动作 | 推荐做法 |
|---|---|
| 权限边界 | 每个应用一个独立 ServiceAccount |
| 授权范围 | 优先 namespace 内授权 |
| 动词控制 | 明确写出 get/list/watch/create/update/patch/delete,不要偷懒写 * |
| 资源控制 | 精确到 configmaps、leases、pods 等具体资源 |
| 高危资源 | secrets、nodes、persistentvolumes、serviceaccounts/token 单独审核 |
| 周期治理 | 定期用 kubectl auth can-i、审计日志、IaC 代码审查做复核 |
5.1 为什么优先 RoleBinding
因为命名空间是 Kubernetes 多租户隔离里最常用、最自然的一层边界。把权限收敛在 namespace 内,即便某个工作负载被攻陷,影响面通常也更可控::cite[167]。
5.2 为什么不要乱给 Secret 权限
官方特别提醒:get Secret 很危险,但 list 和 watch 也同样危险,因为返回结果里就可能包含 Secret 内容。很多人误以为“list 只是列出名称”,实际并不是这样::cite[167]。
5.3 为什么不要随意允许创建工作负载
一个用户如果能在某个 namespace 中创建 Pod / Deployment,就可能通过挂载 Secret、使用高权限 ServiceAccount、调度特权容器等方式间接扩大权限边界。因此“允许创建工作负载”本身就不是低风险权限::cite[167]。
6. 常见 RBAC 配置错误与风险
6.1 错误一:直接使用通配符
下面这种写法在实验环境里很省事,但在生产环境几乎等于埋雷:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dangerous-role
namespace: demo
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
Kubernetes 官方明确提醒,* 会把当前以及未来新增的资源、子资源、动词一并授权出去。这意味着随着 CRD、新版本 API、子资源不断增加,这个角色会越来越危险::cite[166]。
6.2 错误二:把 ClusterRoleBinding 当成“省事版 RoleBinding”
有些团队为了少写几份 YAML,会把命名空间级只读权限直接做成 ClusterRoleBinding。问题在于:你本来只是想看 dev 命名空间,结果变成了全集群可见。
记住一句话:
RoleBinding + ClusterRole= 复用权限定义,但仍然限制在 namespaceClusterRoleBinding + ClusterRole= 真正的全局授权
6.3 错误三:误给高危动词
RBAC 最佳实践里特别强调了几个高危点:
escalate:允许创建比自己更高权限的角色bind:允许把高权限角色绑定给自己或别人impersonate:允许伪装成其他用户/账号createonserviceaccounts/token:可以为已有 ServiceAccount 申请 token
这些权限一旦配错,往往不是“多看一点资源”这么简单,而是直接走向权限提升::cite[167]。
6.4 错误四:给了读 Secret,却以为是低风险
很多人把下面这类角色当作“排障只读权限”:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: troubleshooting-readonly
rules:
- apiGroups: [""]
resources: ["pods", "events", "configmaps", "secrets"]
verbs: ["get", "list", "watch"]
问题在于,secrets 一旦被包含进去,这个角色就已经不是普通只读角色了。对于数据库密码、云凭证、Webhook Token 来说,这通常已经足以造成严重泄露风险::cite[167]。
7. 排障技巧:如何快速判断权限问题
如果你怀疑某个工作负载是 RBAC 配错了,建议按这个顺序排查:
7.1 看当前身份
kubectl get pod demo-app-xxxxx -n demo -o yaml
重点确认:
spec.serviceAccountName- 所在 namespace
7.2 看绑定关系
kubectl get rolebinding -n demo
kubectl get clusterrolebinding
7.3 看是否真的有权限
kubectl auth can-i list configmaps \
--as=system:serviceaccount:demo:configmap-reader \
-n demo
7.4 看是否误用了默认 ServiceAccount
如果 Pod 没显式写 serviceAccountName,它会落到 namespace 里的 default ServiceAccount。这样很容易出现两种问题:
- 要么权限不足,应用报 403
- 要么大家共用一个 default,权限被越配越大
8. 本章小结
这一章最重要的不是背对象名字,而是建立下面这套权限设计思路:
- 先识别调用者身份
- 再只授予完成任务所需的最小权限
- 优先把权限限制在 namespace 内
- 避免
*、避免cluster-admin、避免system:masters - 对
secrets、bind、escalate、impersonate、serviceaccounts/token这类高危权限单独审计::cite[166]
如果你把 RBAC 设计成“默认不给、按需发放、持续复核”,Kubernetes 集群的权限面就会清晰很多。后面学习 ServiceAccount、Pod 安全和准入控制时,你会发现这些能力其实都在围绕同一个目标:让工作负载只能做它本来该做的事。
📝 版权声明:本文为原创技术博客,转载请注明出处。
如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!