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(操作动词) 包括:
– 读操作:get、list、watch
– 写操作:create、update、patch、delete、deletecollection
– 特殊: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-lookup 或 kubectl-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 应用的部署。
📖 系列目录
- 第 1 天:Kubernetes 是什么?核心概念与架构全景解析
- 第 2 天:手把手搭建你的第一个 K8s 集群(kubeadm 实战)
- 第 3 天:Pod 详解:K8s 最小的调度单元与生命周期管理
- 第 4 天:Deployment 与 ReplicaSet:声明式应用管理
- 第 5 天:Service 与网络基础:ClusterIP、NodePort、LoadBalancer 详解
- 第 6 天:Namespace 与资源配额:多租户隔离基础
- 第 7 天:ConfigMap 与 Secret:配置管理最佳实践
- 第 8 天:Volume 与 PersistentVolume:存储抽象层的核心机制
- 第 9 天:StorageClass 与动态存储供给实战
- 第 10 天:StatefulSet:有状态应用的部署与管理
- 第 11 天:Ingress 与 Ingress Controller:外部流量接入全攻略
- 第 12 天:NetworkPolicy:K8s 网络安全策略与微隔离
- 第 13 天:Headless Service 与服务发现机制深度解析
- 第 14 天:CSI 存储插件与生产存储选型指南
- 第 15 天:污点与容忍度:掌控 Pod 调度
- 第 16 天:Node Affinity 与 Pod Affinity:精细化调度策略实战
- 第 17 天:HPA 水平自动扩缩:基于 CPU/内存/自定义指标的弹性伸缩
- 第 18 天:VPA 与 Cluster Autoscaler:资源与集群层的自动扩缩
- 第 19 天:Job 与 CronJob:批处理与定时任务实战
- 第 20 天:PriorityClass 与抢占式调度机制
- 第 21 天:资源配额与 LimitRange:多租户资源管控
- 第 22 天:监控体系搭建:Prometheus + Grafana + Kube-state-metrics
- 第 23 天:日志收集实战:EFK/ELK 栈在 K8s 中部署
- 第 24 天:RBAC 权限控制:ServiceAccount、Role、ClusterRole 深度解析 ← 本篇
- 第 25 天:Helm Charts:包管理器使用与 Chart 开发实战 🔜
- 第 26 天:集群备份与恢复:etcd 快照 + Velero 方案 🔜
- 第 27 天:滚动更新与回滚策略:实现零停机发布 🔜
- 第 28 天:集群升级最佳实践:Control Plane 与 Node 升级步骤 🔜
- 第 29 天:多集群管理:Federation / Cluster API / 多集群服务网格 🔜
- 第 30 天:K8s 生产环境踩坑实录:性能调优、故障排查与最佳实践 🔜
下期预告:第 25 天 — Helm Charts:包管理器使用与 Chart 开发实战
从手动编写 YAML 到一键部署,Helm 是 K8s 生态中最流行的包管理器。明天我们将学习如何安装 Helm、使用 Chart 仓库、以及如何开发自己的 Helm Chart 来标准化团队部署流程。















暂无评论内容