- 前言
- RBAC 核心概念
- ServiceAccount 与令牌管理
- RBAC 设计模式
- OPA Gatekeeper 架构
- ConstraintTemplate 与 Rego 策略编写
- 实战策略案例
- RBAC 审计(Audit)与监控
- 对比表:RBAC vs OPA Gatekeeper vs PSA vs Kyverno
- 故障案例与恢复流程
- 运维检查清单
- 结语

前言
在生产环境运维 Kubernetes 集群时,最先需要建立体系的领域就是访问控制(Access Control)。集群管理员、开发者、CI/CD 流水线、监控代理等各类主体都会向 API Server 发送请求,而这些请求必须按谁(Subject)能对哪些资源(Resource)执行哪些动作(Verb)这一维度进行精细控制。仅靠 Kubernetes 提供的默认授权机制 RBAC(Role-Based Access Control)就已经能实现相当程度的访问控制,但诸如“只允许特定的镜像仓库”“所有 Pod 必须设置资源限制”“禁止创建没有特定标签的命名空间”这类基于策略(Policy)的控制已经超出了 RBAC 的能力范围。
填补这一空白的正是OPA Gatekeeper。它是基于 Open Policy Agent(OPA)的 Kubernetes 准入控制器,通过 ConstraintTemplate 和 Constraint CRD 把用 Rego 语言编写的策略应用到集群。如果说 RBAC 解决的是“给谁授予什么权限”,那么 OPA Gatekeeper 就是验证“即使请求被允许,它是否遵守了策略”的补充层。
本文将全面讲解 RBAC 的核心组成要素、ServiceAccount 令牌管理、按命名空间隔离权限的设计模式、OPA Gatekeeper 架构与 Rego 策略编写、实战策略案例、审计(Audit)策略、主流策略引擎对比,以及故障案例与恢复流程。
RBAC 核心概念
Kubernetes RBAC 由四种 API 对象构成。准确理解这四者之间的关系,是访问控制设计的起点。
Role 与 ClusterRole
Role用于定义特定命名空间内针对资源的权限规则(rules)。ClusterRole则不局限于某个命名空间,适用于定义集群级资源(nodes、persistentvolumes 等)的权限,或者需要跨多个命名空间复用的权限集合。
# 命名空间级 Role:dev 命名空间内的 Pod 读取权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: pod-reader
rules:
- apiGroups: ['']
resources: ['pods']
verbs: ['get', 'watch', 'list']
- apiGroups: ['']
resources: ['pods/log']
verbs: ['get']
# 集群级 ClusterRole:在所有命名空间中管理 Deployment
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-manager
rules:
- apiGroups: ['apps']
resources: ['deployments']
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch']
- apiGroups: ['apps']
resources: ['deployments/scale']
verbs: ['update', 'patch']
核心原则是尽最大可能避免使用通配符(*)。一旦使用 resources: ["*"] 或 verbs: ["*"],就等于对当前乃至未来新增的资源都放开了无限制访问,安全风险会急剧上升。
RoleBinding 与 ClusterRoleBinding
把定义好的 Role/ClusterRole 关联到实际主体(Subject)上的,就是 RoleBinding 和 ClusterRoleBinding。
# RoleBinding:在 dev 命名空间中把 pod-reader Role 授予 frontend-team 组
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: frontend-pod-reader
namespace: dev
subjects:
- kind: Group
name: frontend-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
注意事项:绝对要避免把用户添加到 system:masters 组。该组成员会绕过所有 RBAC 检查,而且即使删除 RoleBinding 或 ClusterRoleBinding 也无法收回其权限。
Subject 类型
在 RBAC 中被授予权限的主体(Subject)有三种类型。
- User:由外部认证系统(OIDC、证书等)提供的用户身份
- Group:用户的逻辑分组,由认证系统传递组信息
- ServiceAccount:由 Kubernetes 直接管理、供 Pod 内部工作负载使用的账号
ServiceAccount 与令牌管理
从 Kubernetes 1.24 起,ServiceAccount 不再自动生成永久令牌。默认行为改为通过TokenRequest API签发带有时间限制的令牌,这在安全层面是一项重要改进。
# 创建 ServiceAccount
kubectl create serviceaccount ci-deployer -n staging
# 签发限时令牌(有效期 1 小时)
kubectl create token ci-deployer -n staging --duration=3600s
# 确认 ServiceAccount 权限
kubectl auth can-i create deployments --as=system:serviceaccount:staging:ci-deployer -n staging
# 查看绑定到指定 ServiceAccount 的 Role
kubectl get rolebindings -n staging -o json | \
jq '.items[] | select(.subjects[]? | .name=="ci-deployer" and .kind=="ServiceAccount")'
设计 CI/CD 流水线专用的 ServiceAccount 时,请遵循以下原则。
- 为每条流水线创建专属 ServiceAccount:不要让多条流水线共用同一个 ServiceAccount
- 只在必要的命名空间创建 RoleBinding:用按命名空间划分的 RoleBinding 取代 ClusterRoleBinding
- 令牌有效期最小化:按流水线的实际执行时长设置令牌有效期
- 禁用 automountServiceAccountToken:避免 Pod 中挂载不必要的 ServiceAccount 令牌
# 禁用 automountServiceAccountToken 的示例
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service
namespace: production
automountServiceAccountToken: false
RBAC 设计模式
按命名空间隔离
在多租户环境中,按团队或环境维度拆分命名空间,并为每个命名空间应用独立的 RBAC 策略。
# 按团队划分命名空间 + RBAC 一体化配置示例
---
apiVersion: v1
kind: Namespace
metadata:
name: team-alpha
labels:
team: alpha
environment: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: team-alpha
name: team-alpha-developer
rules:
- apiGroups: ['', 'apps', 'batch']
resources: ['pods', 'deployments', 'services', 'configmaps', 'jobs']
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete']
- apiGroups: ['']
resources: ['secrets']
verbs: ['get', 'list'] # 限制 Secret 的写入权限
- apiGroups: ['']
resources: ['pods/exec']
verbs: ['create'] # 为调试放开 exec
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-alpha-developer-binding
namespace: team-alpha
subjects:
- kind: Group
name: team-alpha-devs
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: team-alpha-developer
apiGroup: rbac.authorization.k8s.io
防止权限提升
RBAC 设计中最需要警惕的,就是切断权限提升(Privilege Escalation)的路径。下面这些权限尤其需要留意。
pods/exec:可以在 Pod 内部执行任意命令,从而窃取该 Pod 的 ServiceAccount 令牌secrets读取权限:存在泄露其他 ServiceAccount 令牌或数据库凭据的风险- 对
rolebindings/clusterrolebindings的create:可以给自己授予更高权限 escalate/bind动词:能够修改或绑定 Role/ClusterRole 的元权限
OPA Gatekeeper 架构
OPA Gatekeeper 以 Kubernetes 准入 Webhook(Admission Webhook)的形式运行,在 API Server 创建/修改/删除资源之前执行策略校验。
组成要素
- Gatekeeper Controller Manager:处理准入 Webhook 请求并评估 Rego 策略的核心组件
- Audit Controller:周期性检查已经部署的资源是否遵守策略
- ConstraintTemplate CRD:定义 Rego 策略逻辑与参数 schema 的模板
- Constraint CRD:把 ConstraintTemplate 实例化,指定具体的策略作用对象与参数
安装
# 安装 Gatekeeper(Helm)
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install gatekeeper gatekeeper/gatekeeper \
--namespace gatekeeper-system \
--create-namespace \
--set audit.interval=60 \
--set constraintViolationsLimit=50 \
--set audit.fromCache=true
# 确认安装结果
kubectl get pods -n gatekeeper-system
kubectl get crd | grep gatekeeper
工作流程
Gatekeeper 的策略评估流程如下。
- 用户或控制器向 API Server 发送资源创建/修改请求
- API Server 执行认证(AuthN)与授权(AuthZ、RBAC)
- 在准入阶段把请求转发给 Gatekeeper Webhook
- Gatekeeper 找出与该资源匹配的 Constraint 并评估 Rego 策略
- 若存在违规,拒绝请求(Deny)并返回违规信息
- 若无违规,批准请求(Allow)并写入 etcd
ConstraintTemplate 与 Rego 策略编写
基本结构
ConstraintTemplate 由两部分组成:CRD 规格(参数 schema)与 Rego 代码(策略逻辑)。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: string
description: '必填标签列表'
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("资源缺少必填标签: %v", [missing])
}
Constraint 应用
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: ['']
kinds: ['Namespace']
excludedNamespaces:
- kube-system
- gatekeeper-system
parameters:
labels:
- 'team'
- 'cost-center'
实战策略案例
案例 1:限制镜像仓库
在生产集群中强制只能从被允许的容器仓库拉取镜像。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedrepos
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not image_from_allowed(container.image)
msg := sprintf("容器 '%v' 的镜像 '%v' 来自未被允许的仓库。允许的仓库: %v",
[container.name, container.image, input.parameters.repos])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
not image_from_allowed(container.image)
msg := sprintf("initContainer '%v' 的镜像 '%v' 来自未被允许的仓库。",
[container.name, container.image])
}
image_from_allowed(image) {
repo := input.parameters.repos[_]
startswith(image, repo)
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: prod-allowed-repos
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: ['']
kinds: ['Pod']
namespaces:
- production
- staging
parameters:
repos:
- 'gcr.io/my-company/'
- 'us-docker.pkg.dev/my-company/'
- 'registry.internal.company.com/'
案例 2:强制设置资源请求/限制
强制所有容器都必须设置 CPU 与内存的 requests/limits。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequireresourcelimits
spec:
crd:
spec:
names:
kind: K8sRequireResourceLimits
validation:
openAPIV3Schema:
type: object
properties:
requiredResources:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequireresourcelimits
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
resource := input.parameters.requiredResources[_]
not container.resources.limits[resource]
msg := sprintf("容器 '%v' 未设置 resources.limits.%v。", [container.name, resource])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
resource := input.parameters.requiredResources[_]
not container.resources.requests[resource]
msg := sprintf("容器 '%v' 未设置 resources.requests.%v。", [container.name, resource])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequireResourceLimits
metadata:
name: require-cpu-memory-limits
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: ['']
kinds: ['Pod']
excludedNamespaces:
- kube-system
- gatekeeper-system
parameters:
requiredResources:
- 'cpu'
- 'memory'
案例 3:阻止特权容器
阻止以特权模式(privileged)运行的容器。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sdisallowprivileged
spec:
crd:
spec:
names:
kind: K8sDisallowPrivileged
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sdisallowprivileged
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("不允许使用特权容器: '%v'", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
container.securityContext.privileged == true
msg := sprintf("不允许使用特权 initContainer: '%v'", [container.name])
}
RBAC 审计(Audit)与监控
基于 kubectl 的审计
# 确认当前用户的权限
kubectl auth can-i --list
# 确认指定 ServiceAccount 在命名空间内的权限
kubectl auth can-i --list --as=system:serviceaccount:production:app-deployer -n production
# 确认能否执行指定操作
kubectl auth can-i delete pods --as=system:serviceaccount:staging:ci-runner -n staging
# 排查全集群范围内可读取 secrets 的主体(kubectl-who-can 插件)
kubectl who-can get secrets --all-namespaces
# 排查权限过大的 ClusterRoleBinding
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name, .subjects'
利用 Gatekeeper 审计(Audit)
Gatekeeper 的 Audit 功能会对已经部署的资源同样检查是否违反策略。设置为 enforcementAction: dryrun 后,就可以只记录违规项而不做拦截。
# 查询策略违规现状
kubectl get k8sallowedrepos prod-allowed-repos -o yaml | \
grep -A 100 "status:" | head -50
# 汇总全部 Constraint 的违规情况
kubectl get constraints -o json | \
jq '.items[] | {name: .metadata.name, kind: .kind, violations: (.status.totalViolations // 0)}'
监控集成
Gatekeeper 默认会暴露 Prometheus 指标。
gatekeeper_violations:当前审计中发现的违规数量gatekeeper_request_duration_seconds:准入请求的处理耗时gatekeeper_request_count:准入请求总数(按允许/拒绝区分)gatekeeper_constraint_template_status:ConstraintTemplate 的状态
对比表:RBAC vs OPA Gatekeeper vs PSA vs Kyverno
下面对 Kubernetes 的访问控制与策略引擎做一次综合对比。
| 项目 | RBAC | OPA Gatekeeper | Pod Security Admission (PSA) | Kyverno |
|---|---|---|---|---|
| 工作层次 | 授权(Authorization) | 准入(Admission) | 准入(Admission) | 准入(Admission) |
| 策略语言 | YAML 声明式 | Rego | 内置 profile(Privileged/Baseline/Restricted) | YAML 声明式 |
| 学习曲线 | 低 | 高(需要学习 Rego) | 非常低 | 低 |
| 灵活性 | 低(只能授予/拒绝权限) | 非常高 | 低(仅 3 个 profile) | 高 |
| Mutation 支持 | 不适用 | 支持(Assign/Modify) | 不支持 | 支持(mutate) |
| 资源生成 | 不适用 | 不支持 | 不支持 | 支持(generate) |
| 审计(Audit) | 需要分析 audit log | 内置 Audit 功能 | audit/warn 模式 | PolicyReport CRD |
| CNCF 阶段 | Kubernetes 内置 | Graduated | Kubernetes 内置 | Incubating |
| 资源消耗 | 无(内置于 API Server) | 高(多个 Pod) | 非常低 | 中等 |
| 推荐用途 | 基础访问控制 | 复杂的策略逻辑 | 强制 Pod 安全基线 | Kubernetes 原生策略 |
推荐组合:把 RBAC(基础授权)+ PSA(Pod 安全基线)+ Gatekeeper 或 Kyverno(自定义策略)组合使用,是生产环境的最佳实践。简单策略适合用 Kyverno,复杂的跨资源校验则更适合 OPA Gatekeeper。
故障案例与恢复流程
案例 1:Gatekeeper Webhook 故障导致全部部署被阻止
症状:所有 Pod 创建都被拒绝,错误信息中出现 webhook "validation.gatekeeper.sh" denied the request 或连接超时。
原因:Gatekeeper Controller Pod 异常退出,或者因资源不足而无法响应。
恢复流程:
# 1. 确认 Gatekeeper Pod 状态
kubectl get pods -n gatekeeper-system
# 2. 紧急情况:临时禁用 Webhook(把 failurePolicy 改为 Ignore)
kubectl get validatingwebhookconfigurations gatekeeper-validating-webhook-configuration -o yaml > webhook-backup.yaml
kubectl patch validatingwebhookconfigurations gatekeeper-validating-webhook-configuration \
--type='json' -p='[{"op": "replace", "path": "/webhooks/0/failurePolicy", "value": "Ignore"}]'
# 3. 重启 Gatekeeper Pod
kubectl rollout restart deployment gatekeeper-controller-manager -n gatekeeper-system
# 4. 确认恢复正常后还原 failurePolicy
kubectl apply -f webhook-backup.yaml
预防措施:把 Gatekeeper 的 failurePolicy 从 Fail 改成 Ignore 虽然能提升可用性,但也让策略有被绕过的可能,因此生产环境应保持 Fail,同时为 Gatekeeper Pod 准备充足的资源与 replicas。
案例 2:过多的 ClusterRoleBinding 导致权限泄漏
症状:发现所有 ServiceAccount 都能读取集群资源这一异常状态。
诊断与恢复:
# 排查绑定到 cluster-admin 的主体
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") | {name: .metadata.name, subjects: .subjects}'
# 删除不必要的 ClusterRoleBinding
kubectl delete clusterrolebinding suspicious-admin-binding
# 审计全部 ClusterRoleBinding
kubectl get clusterrolebindings -o json | \
jq '.items[] | {name: .metadata.name, role: .roleRef.name, subjects: [.subjects[]? | .kind + ":" + .name]}'
案例 3:ConstraintTemplate 语法错误导致策略不生效
症状:已经创建了 Constraint,但策略没有生效。kubectl get constrainttemplates 中的 STATUS 显示异常。
诊断:
# 确认 ConstraintTemplate 状态
kubectl get constrainttemplate k8srequiredlabels -o json | jq '.status'
# 确认 Rego 语法错误
kubectl describe constrainttemplate k8srequiredlabels | grep -A 10 "Status:"
# 在 Gatekeeper 日志中确认错误
kubectl logs -n gatekeeper-system -l control-plane=controller-manager --tail=100
运维检查清单
这是一份用于检查生产 Kubernetes 集群访问控制状况的清单。
RBAC 检查清单
-
system:masters组中是否登记了不必要的用户 - 是否完全掌握了绑定
cluster-adminClusterRole 的所有主体 - 是否存在使用通配符(
*)权限的 Role/ClusterRole - ServiceAccount 是否默认设置了
automountServiceAccountToken: false - 是否按命名空间配置了恰当的 Role/RoleBinding
-
pods/exec、secrets、rolebindings等敏感权限是否已被压缩到最小 - 是否清理了不再使用的 ServiceAccount 与 RoleBinding
- RBAC 配置是否纳入 Git 管理(GitOps)
OPA Gatekeeper 检查清单
- Gatekeeper Controller 是否以高可用方式部署(replicas 2 以上)
-
failurePolicy是否按生产需求进行了设置 - kube-system、gatekeeper-system 等系统命名空间是否被恰当排除
- 是否有先用
dryrun模式测试新策略的流程 - 是否在定期复查 Audit 结果
- ConstraintTemplate 中的 Rego 代码是否通过了单元测试
- Gatekeeper 指标是否已集成到 Prometheus/Grafana
- Webhook 故障时的紧急恢复流程(Runbook)是否已文档化
定期审计项
- 每季度的 RBAC 权限复查:识别持有过高权限的主体
- 每月的 Gatekeeper Audit 报告:违反策略的资源现状
- ServiceAccount 令牌使用模式分析:清理未使用的令牌
- 引入新的 CRD/API 时同步更新 RBAC 与 Gatekeeper 策略
结语
Kubernetes 的访问控制不会因为有了 RBAC 就大功告成。RBAC 回答的是“给谁授予什么权限”,而要验证“被允许的操作是否遵守策略”,就离不开 OPA Gatekeeper 这样的准入控制器。同时使用这两种机制、用 Pod Security Admission 强制基础安全基线,并执行定期审计,才是在生产环境落实最小权限原则的方法。
尤其是把策略作为代码来管理(Policy as Code)、在变更前必定用 dryrun 模式评估影响、并提前准备好故障时的紧急恢复流程,这样的运维习惯才是预防安全事故的关键。RBAC 与 OPA Gatekeeper 虽然只是技术工具,但要把它们运营好,就必须与组织的访问控制治理联动起来——这一点不能忘记。
현재 단락 (1/381)
在生产环境运维 Kubernetes 集群时,最先需要建立体系的领域就是**访问控制**(Access Control)。集群管理员、开发者、CI/CD 流水线、监控代理等各类主体都会向 API Se...