Kubernetes RBAC 精细化权限管理实战:Role、ClusterRole、ServiceAccount
深入讲解 Kubernetes RBAC 权限体系:Role/ClusterRole 定义权限规则、RoleBinding/ClusterRoleBinding 绑定权限、ServiceAccount 为工作负载授权,通过多租户场景、CI/CD 最小权限、运维只读账号等生产案例,掌握 K8s 精细化访问控制。
Kubernetes RBAC(基于角色的访问控制)是集群安全的核心机制。默认的 cluster-admin 权限等于“root”,真实生产环境绝不能给所有人这个权限。本文从 RBAC 核心模型出发,通过真实场景演示如何精细化管理集群访问权限。
RBAC 核心模型
主体(Subject) 角色(Role/ClusterRole) 资源(Resource)
用户/服务账号 → 绑定(Binding) → API 对象操作权限
三种主体类型:
- User(用户):K8s 本身不管理用户,通常用证书或 OIDC 集成
- Group(组):用户分组
- ServiceAccount(服务账号):Pod 内程序使用的身份
两种角色作用域:
- Role:命名空间级别(只能授权本命名空间内的资源)
- ClusterRole:集群级别(可以授权所有命名空间 + 非命名空间资源)
一、Role 和 ClusterRole
创建 Role(命名空间级别)
# 在 production 命名空间中,允许读取 Pod 信息
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: production
rules:
- apiGroups: [""] # "" 代表核心 API 组(Pod/Service/ConfigMap 等)
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"] # 子资源(允许查看日志)
verbs: ["get"]
# 开发者角色:在 dev 命名空间可以读写大部分资源
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets", "endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
创建 ClusterRole(集群级别)
# 只读集群角色(可用于所有命名空间)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-readonly
rules:
- apiGroups: [""]
resources: ["*"] # 所有核心资源
verbs: ["get", "list", "watch"]
- apiGroups: ["apps", "batch", "extensions"]
resources: ["*"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["nodes"] # 节点信息(非命名空间资源,只有 ClusterRole 能授权)
verbs: ["get", "list", "watch"]
---
# CI/CD 流水线角色(只能更新 Deployment 镜像)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-updater
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "patch", "update"]
- apiGroups: ["apps"]
resources: ["deployments/status"]
verbs: ["get"]
二、RoleBinding 和 ClusterRoleBinding
RoleBinding(将角色绑定到主体)
# 把 developer 角色绑定给用户 alice(在 dev 命名空间)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: alice-developer
namespace: dev
subjects:
- kind: User
name: alice # 用户名(来自证书 CN 或 OIDC claims)
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
# 把 ClusterRole 限制在单个命名空间使用(RoleBinding 绑 ClusterRole)
# 注意:ClusterRole 的全局资源(nodes 等)在这种绑定下仍然无法访问
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: readonly-production
namespace: production
subjects:
- kind: Group
name: ops-team # 用户组
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-readonly # 引用 ClusterRole
apiGroup: rbac.authorization.k8s.io
ClusterRoleBinding(集群范围绑定)
# 让 monitoring 服务账号可以访问所有命名空间的 Pod 指标
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus-cluster-reader
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring # ServiceAccount 所在的命名空间
roleRef:
kind: ClusterRole
name: cluster-readonly
apiGroup: rbac.authorization.k8s.io
三、ServiceAccount:为 Pod 授权
Pod 内的程序(如 Prometheus、ArgoCD、Operator)需要调用 K8s API 时,必须使用 ServiceAccount。
创建并使用 ServiceAccount
# 创建 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-deployer
namespace: production
---
# 给 ServiceAccount 绑定权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-deployer-role
namespace: production
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-deployer-binding
namespace: production
subjects:
- kind: ServiceAccount
name: app-deployer
namespace: production
roleRef:
kind: Role
name: app-deployer-role
apiGroup: rbac.authorization.k8s.io
---
# Deployment 使用此 ServiceAccount
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: production
spec:
template:
spec:
serviceAccountName: app-deployer # 指定 ServiceAccount
containers:
- name: app
image: my-app:v1.0
禁用默认 Token 自动挂载(安全加固)
# 不需要调用 API 的 Pod,禁用 ServiceAccount Token 挂载
spec:
automountServiceAccountToken: false # Pod 级别
# 或在 ServiceAccount 上默认禁用
apiVersion: v1
kind: ServiceAccount
metadata:
name: no-api-access
automountServiceAccountToken: false # SA 级别
四、生产场景实战
场景一:多团队命名空间隔离
# 为不同团队创建命名空间
kubectl create namespace team-frontend
kubectl create namespace team-backend
kubectl create namespace team-data
# 创建团队角色(可以管理本命名空间所有资源)
cat << 'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-admin
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
- nonResourceURLs: ["*"]
verbs: ["*"]
EOF
# 为各团队绑定其命名空间管理权
for ns in team-frontend team-backend team-data; do
team=$(echo $ns | sed 's/team-//')
kubectl create rolebinding ${ns}-admin \
--clusterrole=namespace-admin \
--group=${team}-developers \
--namespace=${ns}
done
场景二:CI/CD 最小权限
# ArgoCD 或 Jenkins 的部署权限:只能更新指定命名空间的 Deployment
apiVersion: v1
kind: ServiceAccount
metadata:
name: cicd-deployer
namespace: cicd
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cicd-deploy
namespace: production
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "update", "patch"]
resourceNames: ["web-app", "api-server"] # 进一步限制:只能操作这两个 Deployment
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"] # 可以查看 Pod 状态(确认部署是否成功)
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cicd-deploy-binding
namespace: production
subjects:
- kind: ServiceAccount
name: cicd-deployer
namespace: cicd
roleRef:
kind: Role
name: cicd-deploy
apiGroup: rbac.authorization.k8s.io
场景三:运维只读账号
# 给新入职运维人员:只读访问,但可以查看日志和进入 Pod exec
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ops-readonly
rules:
# 读取所有工作负载资源
- apiGroups: ["", "apps", "batch", "extensions", "networking.k8s.io"]
resources: ["*"]
verbs: ["get", "list", "watch"]
# 查看 Pod 日志
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
# 允许 exec 进入 Pod(排查问题用,敏感环境可去掉)
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
# 禁止查看 Secret 内容(虽然能看到 Secret 对象存在,但不能 get 内容)
# 注意:下面要排除 secrets
---
# 为 ops 组的所有用户绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ops-team-readonly
subjects:
- kind: Group
name: ops-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: ops-readonly
apiGroup: rbac.authorization.k8s.io
场景四:Prometheus 监控权限
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups: [""]
resources:
- nodes
- nodes/proxy
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups: ["extensions", "networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"] # 采集节点 /metrics 端点
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring
roleRef:
kind: ClusterRole
name: prometheus
apiGroup: rbac.authorization.k8s.io
五、RBAC 权限验证与审计
# 检查当前用户有哪些权限
kubectl auth can-i list pods
# yes
kubectl auth can-i delete deployments -n production
# no
# 检查特定用户的权限(管理员用)
kubectl auth can-i list pods --as=alice
kubectl auth can-i list pods --as=alice --namespace=production
# 检查 ServiceAccount 的权限
kubectl auth can-i list pods \
--as=system:serviceaccount:monitoring:prometheus
# 列出当前命名空间的所有 Role
kubectl get roles -n production
kubectl get rolebindings -n production
# 列出集群级别的角色
kubectl get clusterroles | grep -v "^system:"
kubectl get clusterrolebindings | grep -v "^system:"
# 查看某个 Role 的详细规则
kubectl describe role developer -n dev
# 查看谁有权操作 secrets(安全审计)
kubectl get rolebindings,clusterrolebindings -A -o json | \
jq -r '.items[] | select(.roleRef.name | test("secret|admin")) |
"\(.kind)/\(.metadata.name) → \(.roleRef.name)"'
使用 kubectl-who-can(第三方工具)
# 安装
kubectl krew install who-can
# 查看谁能 delete pods
kubectl who-can delete pods -n production
# 查看谁能读 secrets
kubectl who-can get secrets -n production
六、常见错误与修复
# 错误:"User cannot get resource pods"
# 排查步骤:
kubectl auth can-i get pods --as=<username> -n <namespace>
# 找到绑定关系
kubectl get rolebindings -n <namespace> -o wide | grep <username>
kubectl get clusterrolebindings -o wide | grep <username>
# 检查用户属于哪些 group(证书模式下 O= 字段是 group)
kubectl config view --raw | \
grep client-certificate-data | awk '{print $2}' | \
base64 -d | openssl x509 -noout -subject
# subject=CN=alice, O=dev-team ← CN=用户名, O=组
# 错误:ServiceAccount 调用 API 报 403
# 排查:
# 1. 确认 Pod 使用了正确的 ServiceAccount
kubectl get pod <pod-name> -o jsonpath='{.spec.serviceAccountName}'
# 2. 确认 ServiceAccount 有对应权限
kubectl auth can-i list pods \
--as=system:serviceaccount:<namespace>:<sa-name>
# 3. 检查 Token 是否正确挂载
kubectl exec -it <pod-name> -- ls /var/run/secrets/kubernetes.io/serviceaccount/
RBAC 设计原则
几个实践中积累的原则:最小权限原则 — 只给真正需要的权限,宁可后期扩充,不要一开始给太多;优先用 RoleBinding + ClusterRole — 避免为每个命名空间重复创建相同的 Role;ServiceAccount 与工作负载一对一 — 不同功能的 Pod 用不同 SA,权限精确到用途;禁用默认 Token 挂载 — 不需要调用 API 的 Pod 设置 automountServiceAccountToken: false;定期审计 — 用 kubectl auth can-i 和 who-can 周期性检查权限范围,避免权限蔓延(Permission Drift)。
