Kubernetes Tips:RBAC 最小权限(可落地版本)
用 ServiceAccount / Role / Binding 把权限收敛到“刚好够用”,既安全又不把团队卡死在 cluster-admin。
RBAC 是 Kubernetes 里最有杠杆的安全控制之一:它能把“一个小失误”限制在命名空间内,而不是扩散成集群级事故。但 RBAC 也最容易走向另一个极端——大家被权限折腾到崩溃,最后一句“直接给 cluster-admin 吧”。
这篇 tips 的目标是:实用最小权限。不是追求理论完美,而是让权限体系可运营、可审计、可迭代。
三个概念先搞清楚
- Subject(主体):谁在发起请求(用户/用户组/ServiceAccount)。
- Role / ClusterRole:允许做什么(对哪些资源做哪些动词)。
- RoleBinding / ClusterRoleBinding:把角色绑定给主体(真正生效的地方)。
记住一句话:
Role 只是规则,Binding 才让规则生效。
命名空间权限 vs 集群权限
- Role/RoleBinding:命名空间级别,推荐给业务应用使用。
- ClusterRole/ClusterRoleBinding:可能是集群范围,谨慎使用,主要给平台组件/控制器/运维工具。
生产最佳实践:
- 业务应用优先用 Role + RoleBinding
- 只有确实需要跨命名空间/集群范围时才上 ClusterRole
ServiceAccount:别再用 default 了
Pod 不指定 serviceAccountName 时会用 namespace 的 default ServiceAccount。很多团队的默认 SA 被不小心绑定了高权限,风险非常大。
推荐:
- 每个应用使用独立 ServiceAccount
- 默认关闭 token 挂载(除非真的需要访问 K8s API)
apiVersion: v1
kind: ServiceAccount
metadata:
name: api
namespace: app
automountServiceAccountToken: false
Deployment 里也显式写:
spec:
template:
spec:
serviceAccountName: api
automountServiceAccountToken: false
如果应用确实需要访问 API(比如 leader election、watch 资源),再把 token 挂载打开,并严格审核 RBAC。
Role 规则怎么写:先从“可用的只读”开始
RBAC 规则由三部分组成:
apiGroupsresourcesverbs
一个常见的“排障只读” Role(给人用):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ns-observer
namespace: app
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "services", "endpoints", "configmaps", "events"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch"]
注意 pods/log:很多人只给了 pods,却发现看不了日志,就是因为漏了子资源。
子资源是 RBAC 的高频坑
常见子资源:
- 看日志:
pods/log - 远程执行:
pods/exec - 端口转发:
pods/portforward - 写 status:
deployments/status、pods/status
当你看到 “forbidden” 时,不要只盯着 pods,也要检查子资源权限。
绑定策略:把“人”和“应用”分开
不要把人和应用随便绑在同一个 Role 上。推荐做法:
- 应用 SA:只给程序真正需要的最小权限
- 人(运维/开发):默认只读;需要写权限时走升级 Role(更严格、可审计)
这样你才能在审计里说清楚:
- “应用代码能做什么”
- “某个用户在什么情况下能做什么”
用 kubectl auth can-i 做权限验算
这是最实用的 RBAC 调试工具:
kubectl auth can-i get pods -n app
kubectl auth can-i get pods/log -n app
kubectl auth can-i create pods/exec -n app
支持模拟某个 ServiceAccount:
kubectl auth can-i get secrets -n app --as system:serviceaccount:app:api
这能让你在上线前就验证权限是否“刚好够用”,而不是靠线上报错摸索。
常见最小权限配方
1)只读 ConfigMap(watch 热更新)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cm-reader
namespace: app
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
2)leader election(leases)
很多控制器通过 coordination.k8s.io 的 leases 做 leader election:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: leader-election
namespace: app
rules:
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
3)允许创建 Pods(高风险权限)
“能创建 Pod”通常意味着很强的能力:可能拉任意镜像、尝试访问服务、消耗资源等。它应被视为高危权限,需要:
- 严格限定命名空间
- 结合 Pod Security / Admission Policy 限制 Pod 能做什么
- 尽量用固定模板的控制器,而不是让业务任意创建 Pod
红旗(能避免很多事故)
- 给应用 ServiceAccount 绑定
cluster-admin resources: ["*"]+verbs: ["*"]的通配角色- 广泛授予读取
secrets(secrets 常常就是“钥匙”) - 把 break-glass 权限变成长期常态
让升级权限“可控”(break-glass)
真实世界里你总会遇到需要更高权限的场景。关键是把升级变成:
- 有时效(临时)
- 可审计(关联工单/事故)
- 有范围(限定 namespace/动作)
即使只是流程+日志记录,也比“永久 cluster-admin”强很多。
进阶:更成熟团队会用的技巧
用 resourceNames 做“点状权限”
比如只允许读一个 ConfigMap:
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["api-config"]
verbs: ["get"]
把 pods/exec、pods/portforward 当成高权限
exec/port-forward 基本等价于“进入容器”,风险很高。建议单独做一个 debug Role,由值班/运维组按需申请,而不是默认给所有人。
Checklist
- 每个应用都有独立 ServiceAccount
- 默认关闭
automountServiceAccountToken,除非需要访问 API - 业务优先 Role/RoleBinding,不乱用 ClusterRoleBinding
- 子资源(pods/log、pods/exec)按需显式授权
- 用
kubectl auth can-i+ impersonation 做上线前验算 - break-glass 权限临时、可审计、可回收
参考链接
FAQ
Q: Role 和 ClusterRole 有什么区别? A: Role 只在命名空间内生效;ClusterRole 可用于集群范围或非命名空间资源。
Q: 为什么 Pod 权限超出预期? A: 可能绑定了默认 ServiceAccount 或过宽的 ClusterRoleBinding,检查 SA 与绑定关系。
Q: 如何验证权限?
A: 用 kubectl auth can-i 并指定对应 ServiceAccount。