深色模式
K8s RBAC 入门:Role、ClusterRole 与绑定
摘要:RBAC 是 K8s 权限体系的核心。本文讲清 Role/ClusterRole/RoleBinding/ClusterRoleBinding 的区别与组合方式,给出最小权限 ServiceAccount 的 YAML 模板与权限自查命令。
适用环境
bash
kubectl version --short 2>/dev/null || kubectl version
kubectl auth can-i --list
kubectl get clusterroles | head -5
kubectl api-resources | head -51
2
3
4
2
3
4
操作步骤
1. 先理解四个对象
| 对象 | 作用域 | 说明 |
|---|---|---|
| Role | 命名空间内 | 定义对哪些资源能做哪些动作 |
| ClusterRole | 集群级 | 同上,也可用于跨命名空间的非资源端点 |
| RoleBinding | 命名空间内 | 把 Role 绑给主体 |
| ClusterRoleBinding | 集群级 | 把 ClusterRole 绑给主体 |
主体(subject)三类:User、Group、ServiceAccount。
2. 最小权限 Role:只给必需的动词
yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-config-reader
namespace: prod
rules:
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
动词说明:get/list/watch/read 为读,create/update/patch/delete/deletecollection 为写。
3. 创建 ServiceAccount 并绑定
yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: prod
automountServiceAccountToken: false # 不需要调 API 时关闭
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-config-reader-binding
namespace: prod
subjects:
- kind: ServiceAccount
name: app-sa
namespace: prod
roleRef:
kind: Role
name: app-config-reader
apiGroup: rbac.authorization.k8s.io1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bash
kubectl apply -f rbac.yaml
kubectl -n prod describe rolebinding app-config-reader-binding1
2
2
4. Pod 里使用 SA
yaml
spec:
serviceAccountName: app-sa
automountServiceAccountToken: true1
2
3
2
3
bash
kubectl -n prod run test --rm -it --image=bitnami/kubectl:latest \
--serviceaccount=app-sa --restart=Never -- \
auth can-i get secrets -n prod1
2
3
2
3
5. 权限自查:三件套
bash
# 我能做什么
kubectl auth can-i --list
# 某个 SA 能做什么
kubectl auth can-i create pods -n prod --as=system:serviceaccount:prod:app-sa
kubectl auth can-i delete secrets -n prod --as=system:serviceaccount:prod:app-sa
# 谁能做危险动作(枚举 clusterrolebinding)
kubectl get clusterrolebindings -o json \
| jq -r '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name + " -> " + (.subjects[]? | "\(.kind)/\(.name)")'1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
6. 重点排查的高危权限
以下权限组合等于集群接管,务必逐一确认必要性:
secrets的get/list在多个命名空间 → 可读所有凭据。pods/exec、pods/attach→ 进入任意容器。*on*→ 集群管理员。escalate、bind、impersonate→ 权限提升。
bash
kubectl get clusterroles -o json \
| jq -r '.items[] | select(.rules[]?.resources[]?=="secrets") | .metadata.name'
kubectl get roles,clusterroles -A -o json \
| jq -r '.items[] | select(.rules[]?.verbs[]?=="*") | "\(.kind)/\(.metadata.name)"'1
2
3
4
2
3
4
7. 不要用 cluster-admin 给应用
把 cluster-admin 绑给 ServiceAccount 是集群最大的安全隐患之一
Pod 一旦被 RCE,攻击者立即获得整个集群权限。应用一律用命名空间内的 Role。
正确做法:命名空间内 Role + 明确资源清单;跨命名空间只读需求用 ClusterRole + RoleBinding(注意这是"降级"绑定,只在指定命名空间生效)。
8. 定期回收与审计
bash
# 找出长期未使用的 SA 与绑定
kubectl get sa -A
kubectl get rolebindings,clusterrolebindings -A -o wide | wc -l
# 开启审计日志(kube-apiserver 参数)
# --audit-policy-file=/etc/kubernetes/audit-policy.yaml1
2
3
4
5
2
3
4
5
验证
bash
kubectl auth can-i get secrets -n prod --as=system:serviceaccount:prod:app-sa # yes
kubectl auth can-i delete secrets -n prod --as=system:serviceaccount:prod:app-sa # no
kubectl auth can-i create pods -n kube-system --as=system:serviceaccount:prod:app-sa # no
kubectl -n prod get rolebinding app-config-reader-binding -o yaml | grep -A3 roleRef1
2
3
4
2
3
4
判定标准:每个 SA 的权限可枚举且最小;无应用持有 cluster-admin;can-i 结果与预期一致。
常见坑
用 ClusterRoleBinding 绑定 cluster-admin
这是最典型的越权配置。需要集群级权限时也要自定义 ClusterRole,只放开必要动词。
给 secrets 的 list 权限等于给了全部读权限
list 无法按名字限制,等于可读该命名空间所有 Secret。改为精确 get + 资源名(resourceNames)。
忘记关 automountServiceAccountToken
不需要调 API 的 Pod 应设为 false,否则容器里 /var/run/secrets/.../token 可被窃取。
删除命名空间后 ClusterRoleBinding 仍指向不存在的 SA
绑定悬空会造成权限误判。定期清理无效的 binding 与 SA。
只配了 RBAC 没做准入控制
RBAC 管"能不能",Pod Security Admission / OPA 管"以什么方式运行"。两者要配合。