Kubernetes RBAC 权限实战——多团队多项目的权限隔离方案
Kubernetes RBAC 权限实战——多团队多项目的权限隔离方案
适读人群:负责 K8s 集群权限管理的平台工程师/运维工程师 | 阅读时长:约 15 分钟 | 核心价值:从 RBAC 原理到多团队权限隔离落地方案,避开权限配置的典型错误
说说让我对 RBAC 有深刻认识的一件事。
公司有个年轻的同学,想给自己的开发环境调试一个 Bug,在 staging 集群执行了 kubectl delete deployment,结果误删了 production 命名空间的一个核心服务的 Deployment。因为 Deployment 被删后 Pod 也都没了,服务中断了 7 分钟,我们花了 40 分钟恢复(还原 YAML、等 Pod 启动、验证)。
事后复盘:那个同学有 cluster-admin 权限——"反正是内部集群,权限大点方便嘛。"
那次之后,我们全面重新梳理了集群的 RBAC 权限体系。
RBAC 的四个核心概念
Role/ClusterRole:定义"可以做什么"(权限规则)
Role:作用在某个命名空间内ClusterRole:作用在整个集群(或者跨命名空间)
RoleBinding/ClusterRoleBinding:把权限绑定给"谁"
RoleBinding:在某个命名空间内把 Role 或 ClusterRole 绑定给用户/组/ServiceAccountClusterRoleBinding:在整个集群层面绑定 ClusterRole
逻辑关系:
用户/组/ServiceAccount
↓ 通过 RoleBinding/ClusterRoleBinding 绑定
Role/ClusterRole(定义哪些资源的哪些操作)多团队权限隔离方案设计
我们公司的情况是:
- 3 个业务团队(用户组、订单组、推荐组)
- 1 个平台运维团队
- 1 个安全审计团队
对应的权限模型:
| 角色 | 权限范围 | 典型操作 |
|---|---|---|
| 业务开发(dev) | 自己命名空间,只读 + 有限操作 | 查看 Pod 日志、Port-forward、查看 ConfigMap |
| 业务 CI/CD(deploy) | 自己命名空间,部署权限 | 更新 Deployment 镜像、查看 Pod 状态 |
| 平台运维(ops) | 所有命名空间,全操作(除删集群级资源) | 日常运维所有操作 |
| 安全审计(auditor) | 所有命名空间,只读 | 合规检查 |
| cluster-admin | 不分配给具体人员 | 只在紧急操作时临时使用 |
完整的 RBAC 配置示例
# ====== 为每个团队创建命名空间 ======
apiVersion: v1
kind: Namespace
metadata:
name: team-order
labels:
team: order
env: production
---
# ====== 业务开发权限(dev-role)======
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dev-role
namespace: team-order
rules:
# Pod 相关:查看、日志、exec(调试用)
- apiGroups: [""]
resources: ["pods", "pods/log", "pods/exec", "pods/portforward"]
verbs: ["get", "list", "watch", "create"]
# Service 查看
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get", "list", "watch"]
# ConfigMap 查看(不能改)
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
# Deployment 查看
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch"]
# HPA 查看
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["get", "list", "watch"]
# 注意:不能删除任何资源,不能改 Secret
---
# ====== CI/CD 部署权限(deploy-role)======
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deploy-role
namespace: team-order
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "update", "patch"]
# 只允许 patch,不允许 delete
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "delete"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
# 注意:不允许创建/删除 Namespace、PV 等集群级资源
---
# ====== 把 dev-role 绑定给订单团队开发人员 ======
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: order-dev-binding
namespace: team-order
subjects:
# 绑定用户
- kind: User
name: "zhang.san@company.com"
apiGroup: rbac.authorization.k8s.io
- kind: User
name: "li.si@company.com"
apiGroup: rbac.authorization.k8s.io
# 或者绑定用户组(推荐,更容易管理)
- kind: Group
name: "order-team-devs" # 对应 LDAP/OIDC 里的组
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: dev-role
apiGroup: rbac.authorization.k8s.io
---
# ====== CI/CD ServiceAccount ======
apiVersion: v1
kind: ServiceAccount
metadata:
name: ci-cd-robot
namespace: team-order
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-cd-robot-binding
namespace: team-order
subjects:
- kind: ServiceAccount
name: ci-cd-robot
namespace: team-order
roleRef:
kind: Role
name: deploy-role
apiGroup: rbac.authorization.k8s.io
---
# ====== 平台运维全局权限(排除 cluster-admin)======
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: platform-ops-role
rules:
# 所有命名空间内的资源
- apiGroups: ["", "apps", "batch", "autoscaling", "networking.k8s.io"]
resources: ["*"]
verbs: ["*"]
# 查看集群级资源
- apiGroups: [""]
resources: ["nodes", "persistentvolumes", "namespaces"]
verbs: ["get", "list", "watch"]
# 不包含:创建/删除 ClusterRole、ClusterRoleBinding、Node
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: platform-ops-binding
subjects:
- kind: Group
name: "platform-ops-team"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: platform-ops-role
apiGroup: rbac.authorization.k8s.io
---
# ====== 只读审计角色 ======
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: auditor-binding
subjects:
- kind: Group
name: "security-auditors"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view # K8s 内置的只读角色
apiGroup: rbac.authorization.k8s.io踩坑实录一:ServiceAccount 权限泄露导致横向移动
现象:安全扫描发现,某个 Pod 的 ServiceAccount 有 cluster-admin 权限,这个 Pod 如果被攻击者获取控制权,可以控制整个集群。
原因:开发者在配置 GitLab Runner 时,为了省事给了 cluster-admin。
解法:
- 不要给 Pod 绑定 cluster-admin
- 每个服务使用独立的 ServiceAccount,而不是默认的
defaultSA - 不需要访问 K8s API 的 Pod,禁用 ServiceAccount token 自动挂载:
spec:
automountServiceAccountToken: false # 禁用 SA token 挂载
serviceAccountName: my-app-sa # 使用专用 SA- 需要访问 K8s API 的 Pod(如 controller、operator),按最小权限配置:
# 只允许读取自己命名空间的 ConfigMap
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: configmap-reader
namespace: myapp
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
resourceNames: ["app-config"] # 进一步限定只能读特定 ConfigMap踩坑实录二:RBAC 配置了但权限不生效
现象:明明给用户绑定了 Role,执行操作还是报 Forbidden。
排查步骤:
# 检查用户当前有哪些权限
kubectl auth can-i get pods --namespace=team-order --as=zhang.san@company.com
kubectl auth can-i delete deployments --namespace=team-order --as=zhang.san@company.com
# 查看用户所有权限
kubectl auth can-i --list --namespace=team-order --as=zhang.san@company.com
# 检查 RoleBinding 是否正确
kubectl get rolebinding -n team-order
kubectl describe rolebinding order-dev-binding -n team-order
# 检查 Role 的规则
kubectl describe role dev-role -n team-order常见问题:
- RoleBinding 里的
subjects.name和实际用户名不匹配(大小写、格式) - 用了 RoleBinding 绑定 ClusterRole,但 ClusterRole 里的规则操作的是集群级资源(需要 ClusterRoleBinding)
- apiGroups 配错了,比如 Deployment 在
apps组,不是""空组
踩坑实录三:默认 ServiceAccount 有过多权限
现象:新建命名空间后,默认 ServiceAccount 有访问 kube-system 里某些资源的权限,违反了最小权限原则。
解法:在每个命名空间创建一个 Role,明确禁止 default ServiceAccount 挂载 token,并且限制其权限:
# 创建命名空间时的标准化脚本
create_namespace() {
local NS=$1
local TEAM=$2
kubectl create namespace ${NS} --dry-run=client -o yaml | \
kubectl apply -f -
# 禁止 default ServiceAccount 自动挂载 token
kubectl patch serviceaccount default -n ${NS} \
-p '{"automountServiceAccountToken": false}'
# 设置 ResourceQuota
kubectl apply -f - <<EOF
apiVersion: v1
kind: ResourceQuota
metadata:
name: ${NS}-quota
namespace: ${NS}
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "30"
EOF
echo "命名空间 ${NS}(团队: ${TEAM})创建完成"
}
create_namespace "team-order" "订单组"RBAC 是 K8s 里最容易"配了但没真正用起来"的功能。最常见的两种极端:一是什么都给 cluster-admin("反正是内部");二是权限配得过细,开发者做不了事,各种绕路。
合理的 RBAC 需要结合团队结构和业务场景,一步到位很难,但从命名空间隔离 + 开发/部署/运维三级权限开始,是一个不错的起点。
