K8s 系列 | 第 24 天:RBAC 权限控制:ServiceAccount、Role、ClusterRole 深度解析


tags: [Kubernetes, K8s系列, DevOps, RBAC, 权限控制, ServiceAccount, 安全]

K8s 系列 | 第 24 天:RBAC 权限控制:ServiceAccount、Role、ClusterRole 深度解析

第 24/30 天

引言

在 Kubernetes 生产环境中,安全永远是第一要务。随着集群规模的增长和团队的扩大,如何精细地控制谁(或什么组件)能对集群资源执行哪些操作,成为一个核心挑战。Kubernetes 的 RBAC(Role-Based Access Control,基于角色的访问控制) 正是解决这一问题的官方方案。

从 v1.8 开始,RBAC 已成为 Kubernetes 的默认鉴权模式,取代了早期的 ABAC(Attribute-Based Access Control)。它通过定义「角色」和「绑定」来实现权限的声明式管理,让集群管理员能够以 K8s 原生的方式管理权限——换句话说,权限配置本身就是 YAML 资源。本文将深入解析 RBAC 的四大核心对象:ServiceAccount、Role、ClusterRole、RoleBinding 和 ClusterRoleBinding,并通过完整的实战带你从零搭建一套生产级权限体系。

一、核心概念

1.1 为什么需要 RBAC?

在 K8s 集群中,有两类主体需要访问 API Server:

  • 人类用户:开发人员、运维人员、审计人员
  • 程序身份:Pod 中运行的应用、CI/CD 工具、监控组件

K8s 本身不管理用户账户(User Account),而是依赖外部认证系统(证书、OIDC、Webhook 等)。但对于程序身份,K8s 提供了原生的 ServiceAccount 资源。RBAC 的核心作用就是将这两类主体的访问权限限制在「最小必要范围」内。

1.2 四大核心对象

对象 作用域 用途
ServiceAccount Namespace 为 Pod 提供身份标识
Role Namespace 定义某个 Namespace 内的权限规则
ClusterRole 集群级 定义集群范围的权限规则(或跨 Namespace 复用)
RoleBinding Namespace 将 Role/ClusterRole 绑定到某个 Namespace 内的用户/ServiceAccount
ClusterRoleBinding 集群级 将 ClusterRole 绑定到集群级的用户/ServiceAccount

1.3 权限控制的三个要素

RBAC 的权限规则由三个要素组成:

# 权限规则的核心结构
rules:
- apiGroups: [""]        # API 组,"" 表示核心 API 组
  resources: ["pods"]    # 资源类型
  verbs: ["get", "list", "watch"]  # 操作动词

verbs(操作动词) 包括:
– 读操作:getlistwatch
– 写操作:createupdatepatchdeletedeletecollection
– 特殊:use(用于 PodSecurityPolicy)、impersonate(用于模拟身份)

1.4 ServiceAccount 与普通用户的区别

# 普通用户:由外部认证系统管理,K8s 不存储
# 需要通过 kubectl 配置证书或 token 来使用
kubectl config set-credentials myuser --client-certificate=user.crt --client-key=user.key

# ServiceAccount:K8s 原生资源,自动生成 Token
kubectl create serviceaccount my-sa
# 查看自动生成的 Secret
kubectl get secrets | grep my-sa-token

二、实战步骤

2.1 创建 ServiceAccount 并查看其自动生成的 Token

# 创建命名空间
kubectl create namespace dev-team

# 创建 ServiceAccount
kubectl create serviceaccount app-sa -n dev-team

# 查看 ServiceAccount 详情
kubectl describe sa app-sa -n dev-team

# 获取自动生成的 Secret 名称
SA_SECRET=$(kubectl get sa app-sa -n dev-team -o jsonpath='{.secrets[0].name}')
echo "Secret: $SA_SECRET"

# 查看 Token 内容
kubectl get secret $SA_SECRET -n dev-team -o jsonpath='{.data.token}' | base64 -d

2.2 创建 Role:为某个 Namespace 定义权限

# role-pod-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev-team
  name: pod-reader
rules:
- apiGroups: [""]              # 核心 API 组
  resources: ["pods"]          # Pod 资源
  verbs: ["get", "list", "watch"]  # 只读权限
- apiGroups: [""]
  resources: ["pods/log"]      # 查看 Pod 日志
  verbs: ["get", "list"]
# 应用 Role
kubectl apply -f role-pod-reader.yaml

# 验证 Role 是否创建成功
kubectl get role -n dev-team

2.3 创建 RoleBinding:将角色绑定到 ServiceAccount

# rolebinding-pod-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: dev-team
subjects:
- kind: ServiceAccount
  name: app-sa
  namespace: dev-team
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
# 应用 RoleBinding
kubectl apply -f rolebinding-pod-reader.yaml

# 验证绑定关系
kubectl describe rolebinding read-pods -n dev-team

2.4 验证权限 — 用 ServiceAccount 的 Token 调用 API

# 获取 ServiceAccount 的 Token
TOKEN=$(kubectl get secret $SA_SECRET -n dev-team -o jsonpath='{.data.token}' | base64 -d)

# 获取 API Server 地址
APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')

# 测试:读取 Pod(应成功)
curl -s -H "Authorization: Bearer $TOKEN" -k "$APISERVER/api/v1/namespaces/dev-team/pods" | head -20

# 测试:删除 Pod(应失败,没有 delete 权限)
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" -k "$APISERVER/api/v1/namespaces/dev-team/pods/some-pod"

# 测试:读取其他 Namespace 的 Pod(应失败,Role 作用域限制在 dev-team)
curl -s -H "Authorization: Bearer $TOKEN" -k "$APISERVER/api/v1/namespaces/default/pods" | head -5

2.5 创建 ClusterRole:获取集群范围的权限

当需要跨 Namespace 访问资源,或管理集群级别的资源(Node、PV、Namespace 本身)时,必须使用 ClusterRole:

# clusterrole-storage-admin.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: storage-admin
rules:
- apiGroups: [""]
  resources: ["persistentvolumes"]     # PV 是集群级资源
  verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: ["storage.k8s.io"]
  resources: ["storageclasses"]         # StorageClass 是集群级资源
  verbs: ["get", "list", "watch", "create"]
# 通过 ClusterRoleBinding 绑定到 ServiceAccount(集群级)
kubectl create clusterrolebinding app-storage-admin 
  --clusterrole=storage-admin 
  --serviceaccount=dev-team:app-sa

# 也可以将 ClusterRole 通过 RoleBinding 绑定到某个 Namespace
# 这样只在该 Namespace 内生效
kubectl create rolebinding app-pod-reader 
  --clusterrole=pod-reader 
  --serviceaccount=dev-team:app-sa 
  -n dev-team

2.6 在 Pod 中使用 ServiceAccount

# pod-with-sa.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-sa
  namespace: dev-team
spec:
  serviceAccountName: app-sa    # 指定 ServiceAccount
  containers:
  - name: app
    image: curlimages/curl:latest
    command: ["/bin/sh", "-c"]
    args:
    - |
      # 自动挂载的 Token 路径
      TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
      NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
      # 使用自动挂载的凭证调用 API
      curl -s -H "Authorization: Bearer $TOKEN" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt 
        https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/pods
      sleep 3600

三、常见问题

3.1 Role 和 ClusterRole 到底怎么选?

简单判断标准: 如果操作的资源是 Namespace 级别的(Pod、Service、Deployment、ConfigMap),用 Role;如果操作的是集群级资源(Node、PV、Namespace、ClusterRole 自身),或者需要跨 Namespace 访问,用 ClusterRole。一个常见的模式是先创建 ClusterRole 定义通用权限模板,再通过 RoleBinding 将其绑定到不同 Namespace,这样既避免了重复定义,又限制了作用范围。

3.2 为什么我绑定了 Role 但权限不生效?

最常见的原因有:
1. RoleBinding 与 Role 不在同一个 Namespace — RoleBinding 只能引用自己 Namespace 内的 Role
2. ServiceAccount 与 Pod 不在同一个 Namespace — 创建 Pod 时务必确认 serviceAccountName 所在的 Namespace
3. Role 中 apiGroups 写错 — 例如 apps/v1 的 Deployment 属于 apps API 组,而不是核心组 ""

3.3 如何授予对所有资源的所有权限(类似管理员)?

K8s 内置了一个 cluster-admin 的 ClusterRole:

# 这是 K8s 自动创建的 cluster-admin ClusterRole
# 通过以下绑定即可获得超级管理员权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-admin-binding
subjects:
- kind: ServiceAccount
  name: admin-sa
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

⚠️ 生产警告: cluster-admin 授予了对所有资源的完全控制权,包括 Secrets(意味着可以读取任何 Secret)。请务必谨慎使用。

3.4 如何调试权限问题?

# 使用 kubectl auth can-i 命令测试权限
# 测试当前用户能否在 dev-team 创建 Pod
kubectl auth can-i create pods -n dev-team

# 以特定 ServiceAccount 身份测试
kubectl auth can-i get pods -n dev-team --as system:serviceaccount:dev-team:app-sa

# 查看某个用户的权限列表
kubectl get rolebinding,clusterrolebinding --all-namespaces | grep app-sa

# 使用 whoami 查看当前认证身份
kubectl config view --minify -o jsonpath='{.users[0].name}'

四、生产最佳实践

4.1 最小权限原则

每个应用只分配它真正需要的权限。例如,一个只需要读取 ConfigMap 的应用,不要给它创建 Pod 的权限:

# 好的实践:精确的最小权限
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get"]   # 只读,不写

4.2 使用自动化工具管理 RBAC

推荐使用 rbac-lookupkubectl-who-can 插件来审计集群权限:

# 安装 kubectl-who-can
kubectl krew install who-can

# 查看谁能操作 Pod
kubectl who-can get pods -n dev-team

# 查看某个 ServiceAccount 能做哪些操作
kubectl who-can get pods --as system:serviceaccount:dev-team:app-sa

4.3 聚合 ClusterRole

K8s 1.9+ 支持 ClusterRole 聚合(Aggregation),可以将多个 ClusterRole 的权限合并为一个:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: dev-full-access
aggregationRule:
  clusterRoleSelectors:
  - matchLabels:
      rbac: dev-role
rules: []  # 规则由匹配的 ClusterRole 自动聚合

4.4 定期审计与监控

# 列出所有 ClusterRoleBinding,检查是否有过于宽泛的权限
kubectl get clusterrolebinding -o wide | grep -E "cluster-admin|system:master"

# 检查是否有非系统 ServiceAccount 绑定了高危 ClusterRole
kubectl get clusterrolebinding -o json | jq '.items[] | select(.roleRef.name == "cluster-admin") | {name: .metadata.name, subjects: .subjects}'

总结

RBAC 是 Kubernetes 安全的基石,它通过声明式的方式实现了精细化的权限控制。本文从 ServiceAccount 创建开始,到 Role/ClusterRole 的定义,再到 RoleBinding/ClusterRoleBinding 的绑定,完整覆盖了 RBAC 的核心概念和实战流程。在生产环境中,「最小权限原则」应该是你设计 RBAC 策略的黄金法则——永远从一个权限都不给开始,然后逐步添加必要的权限。

掌握 RBAC 不仅是安全运维的基本功,也是理解 K8s 多租户隔离、Operator 开发、CI/CD 集成等高级话题的前置条件。下一篇文章我们将进入 Helm Charts 的世界,看看如何用包管理器来标准化和简化 K8s 应用的部署。


📖 系列目录


下期预告:第 25 天 — Helm Charts:包管理器使用与 Chart 开发实战

从手动编写 YAML 到一键部署,Helm 是 K8s 生态中最流行的包管理器。明天我们将学习如何安装 Helm、使用 Chart 仓库、以及如何开发自己的 Helm Chart 来标准化团队部署流程。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容