返回首页

6.1:RBAC 权限体系

RBAC(Role-Based Access Control,基于角色的访问控制)是 Kubernetes 集群里最核心的授权机制之一。它解决的问题很直接:谁可以对哪些资源执行哪些操作。在真实生产环境里,很多安全事故并不是“没做权限控制”,而是“权限给大了”“绑定范围搞错了”“以为只读其实能看到敏感数据”。Kubernetes 的 RBAC 正是为了把这些风险收敛到可管理的范围里::cite[166]。

本章你将学会

  • 认证(Authentication)与鉴权/授权(Authorization)在 Kubernetes 中分别做什么
  • Role、ClusterRole、RoleBinding、ClusterRoleBinding 的关系与使用边界
  • 如何在集群里落实最小权限原则
  • 常见 RBAC 配置错误,以及这些错误为什么危险
  • 如何通过一套完整 YAML 给工作负载授予恰到好处的权限

1. 先理解:认证与鉴权不是一回事

在 Kubernetes API Server 处理请求时,通常会先经过两道关:

  1. 认证(Authentication):确认“你是谁”
  2. 授权(Authorization):确认“你能做什么”

例如,一个 Pod 使用 ServiceAccount Token 调用 API Server,API Server 会先识别这个请求对应的是哪个 ServiceAccount,再根据 RBAC 规则判断它是否有权限读取 ConfigMap、列出 Pod、创建 Job 等操作。RBAC 属于授权阶段,不负责证明身份真假,而是负责决定身份对应的操作边界::cite[166]。

可以把它理解成一张很实用的图:

阶段 关注点 典型问题
认证 Authentication 你是谁 这个请求来自哪个用户 / 组 / ServiceAccount?
授权 Authorization 你能做什么 这个身份能不能 get podslist secretscreate deployments
准入 Admission 你这样做是否合规 即使你有权限,是否还需要经过策略校验?

2. RBAC 四个核心对象

Kubernetes RBAC 主要由 4 类对象组成:RoleClusterRoleRoleBindingClusterRoleBinding。其中 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 用来把 RoleClusterRole 绑定给某个用户、组或 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,不要偷懒写 *
资源控制 精确到 configmapsleasespods 等具体资源
高危资源 secretsnodespersistentvolumesserviceaccounts/token 单独审核
周期治理 定期用 kubectl auth can-i、审计日志、IaC 代码审查做复核

5.1 为什么优先 RoleBinding

因为命名空间是 Kubernetes 多租户隔离里最常用、最自然的一层边界。把权限收敛在 namespace 内,即便某个工作负载被攻陷,影响面通常也更可控::cite[167]。

5.2 为什么不要乱给 Secret 权限

官方特别提醒:get Secret 很危险,但 listwatch 也同样危险,因为返回结果里就可能包含 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 = 复用权限定义,但仍然限制在 namespace
  • ClusterRoleBinding + ClusterRole = 真正的全局授权

6.3 错误三:误给高危动词

RBAC 最佳实践里特别强调了几个高危点:

  • escalate:允许创建比自己更高权限的角色
  • bind:允许把高权限角色绑定给自己或别人
  • impersonate:允许伪装成其他用户/账号
  • create on serviceaccounts/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. 本章小结

这一章最重要的不是背对象名字,而是建立下面这套权限设计思路:

  1. 先识别调用者身份
  2. 再只授予完成任务所需的最小权限
  3. 优先把权限限制在 namespace 内
  4. 避免 *、避免 cluster-admin、避免 system:masters
  5. secretsbindescalateimpersonateserviceaccounts/token 这类高危权限单独审计::cite[166]

如果你把 RBAC 设计成“默认不给、按需发放、持续复核”,Kubernetes 集群的权限面就会清晰很多。后面学习 ServiceAccount、Pod 安全和准入控制时,你会发现这些能力其实都在围绕同一个目标:让工作负载只能做它本来该做的事


📝 版权声明:本文为原创技术博客,转载请注明出处。

如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!

上一篇

2.3 Service 与服务发现:让应用稳定被访问

下一篇

6.4:Secret 安全管理