Kubernetes集群RBAC审计 是做什么的?
使用场景
- 对Kubernetes集群(EKS、GKE、AKS或自管理集群)进行安全评估时
- 验证RBAC策略是否真正遵循了用户和服务账户的最小权限原则时
- 调查Kubernetes集群内潜在的横向移动或权限提升时
- 合规审计要求记录访问控制和权限时
- 为新团队接入共享集群并定义合适的RBAC策略时
请勿用于:网络策略审计(应使用Cilium或Calico网络策略工具)、容器镜像扫描(应使用Trivy或Grype)、运行时安全监控(应使用Falco或Sysdig Secure)。
前置条件
- kubectl已配置并可访问目标集群,具有cluster-admin或等效的读取权限
- 已安装rbac-tool(
kubectl krew install rbac-tool或从GitHub下载二进制文件) - 已安装KubiScan(
pip install kubiscan) - 已安装Kubeaudit(
brew install kubeaudit或从GitHub Releases下载) - 能够访问集群的审计日志,用于关联RBAC发现结果与实际API访问
工作流
步骤1:枚举拥有危险权限的ClusterRole和Role
识别具有通配符权限、Secret访问、pod exec或权限提升能力的角色。
# 列出所有拥有通配符动词的ClusterRole
kubectl get clusterroles -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for role in data['items']:
name = role['metadata']['name']
for rule in role.get('rules', []):
verbs = rule.get('verbs', [])
resources = rule.get('resources', [])
if '*' in verbs or '*' in resources:
print(f'ClusterRole: {name}')
print(f' Verbs: {verbs}')
print(f' Resources: {resources}')
print(f' API Groups: {rule.get(\"apiGroups\", [])}')
print()
"
# 查找可以读取Secret的角色
kubectl get clusterroles -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for role in data['items']:
name = role['metadata']['name']
for rule in role.get('rules', []):
resources = rule.get('resources', [])
verbs = rule.get('verbs', [])
if ('secrets' in resources or '*' in resources) and ('get' in verbs or 'list' in verbs or '*' in verbs):
if not name.startswith('system:'):
print(f'ClusterRole: {name} -> 可以访问Secret (verbs: {verbs})')
"
# 查找具有pod/exec权限的角色(容器逃逸风险)
kubectl get clusterroles -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for role in data['items']:
name = role['metadata']['name']
for rule in role.get('rules', []):
resources = rule.get('resources', [])
if 'pods/exec' in resources or 'pods/*' in resources:
print(f'ClusterRole: {name} -> 具有pods/exec访问权限')
"
步骤2:审计ClusterRoleBinding和RoleBinding
检查绑定关系,识别谁拥有提升的访问权限,并检测过于宽泛的组分配。
# 列出所有ClusterRoleBinding及其主体
kubectl get clusterrolebindings -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for binding in data['items']:
name = binding['metadata']['name']
role = binding['roleRef']['name']
subjects = binding.get('subjects', [])
for subject in subjects:
kind = subject.get('kind', '')
subj_name = subject.get('name', '')
ns = subject.get('namespace', 'cluster-wide')
print(f'{name} -> Role: {role} | {kind}: {subj_name} ({ns})')
" | sort
# 查找绑定到cluster-admin的绑定
kubectl get clusterrolebindings -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for binding in data['items']:
if binding['roleRef']['name'] == 'cluster-admin':
print(f'Binding: {binding[\"metadata\"][\"name\"]}')
for subject in binding.get('subjects', []):
print(f' {subject.get(\"kind\")}: {subject.get(\"name\")} (ns: {subject.get(\"namespace\", \"N/A\")})')
"
# 查找将访问权限授予所有已认证用户的绑定
kubectl get clusterrolebindings -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for binding in data['items']:
for subject in binding.get('subjects', []):
if subject.get('name') in ['system:authenticated', 'system:unauthenticated']:
print(f'WARNING: {binding[\"metadata\"][\"name\"]} 将 {binding[\"roleRef\"][\"name\"]} 授予了 {subject[\"name\"]}')
"
步骤3:使用rbac-tool进行全面分析
使用rbac-tool进行自动化的RBAC分析,包括who-can查询和策略生成。
# 谁可以在所有命名空间中获取Secret
kubectl rbac-tool who-can get secrets
# 谁可以创建Pod(潜在的容器逃逸)
kubectl rbac-tool who-can create pods
# 谁可以exec进入Pod
kubectl rbac-tool who-can create pods/exec
# 谁可以提升权限(bind/escalate动词)
kubectl rbac-tool who-can bind clusterroles
kubectl rbac-tool who-can escalate clusterroles
# 生成RBAC策略报告
kubectl rbac-tool analysis
# 可视化RBAC关系
kubectl rbac-tool viz --outformat dot > rbac-graph.dot
dot -Tpng rbac-graph.dot -o rbac-graph.png
步骤4:运行KubiScan检测危险权限
使用KubiScan自动识别危险的服务账户、Pod和RBAC配置。
# 运行KubiScan查找危险角色
python3 -m kubiscan -rroles # 列出危险Role
python3 -m kubiscan -rcr # 列出危险ClusterRole
python3 -m kubiscan -rrb # 列出危险RoleBinding
python3 -m kubiscan -rcrb # 列出危险ClusterRoleBinding
# 查找危险的服务账户
python3 -m kubiscan -rs # 危险的服务账户
# 查找使用危险服务账户运行的Pod
python3 -m kubiscan -rp # 危险的Pod
# 检查特权提升路径
python3 -m kubiscan -pe # 特权提升向量
# 生成完整报告
python3 -m kubiscan -a # 所有检查
步骤5:审计服务账户Token挂载与使用
检查不必要的服务账户Token挂载,这些挂载可能使Pod被攻破后能够进行横向移动。
# 查找启用了自动挂载服务账户Token的Pod
kubectl get pods --all-namespaces -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for pod in data['items']:
name = pod['metadata']['name']
ns = pod['metadata']['namespace']
sa = pod['spec'].get('serviceAccountName', 'default')
automount = pod['spec'].get('automountServiceAccountToken', True)
if automount and sa != 'default':
print(f'{ns}/{name} -> SA: {sa} (token已自动挂载)')
"
# 查找具有非默认Token Secret的服务账户
kubectl get serviceaccounts --all-namespaces -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for sa in data['items']:
name = sa['metadata']['name']
ns = sa['metadata']['namespace']
secrets = sa.get('secrets', [])
if name != 'default' and len(secrets) > 0:
print(f'{ns}/{name}: 绑定了 {len(secrets)} 个Secret')
"
# 检查是否以特权模式或具有主机访问权限运行的Pod
kubectl get pods --all-namespaces -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for pod in data['items']:
name = pod['metadata']['name']
ns = pod['metadata']['namespace']
for container in pod['spec'].get('containers', []):
sc = container.get('securityContext', {})
if sc.get('privileged', False) or sc.get('runAsUser', 1) == 0:
print(f'RISK: {ns}/{name}/{container[\"name\"]} - privileged={sc.get(\"privileged\",False)} runAsRoot={sc.get(\"runAsUser\",\"not set\")==0}')
"
步骤6:运行Kubeaudit进行RBAC与安全策略验证
执行Kubeaudit进行全面安全检查,包括RBAC相关的发现。
# 运行所有kubeaudit检查
kubeaudit all --kubeconfig ~/.kube/config
# 运行特定的RBAC相关检查
kubeaudit privesc # 检查allowPrivilegeEscalation
kubeaudit rootfs # 检查readOnlyRootFilesystem
kubeaudit nonroot # 检查runAsNonRoot
kubeaudit capabilities # 检查危险的capabilities
# 输出JSON格式便于处理
kubeaudit all --kubeconfig ~/.kube/config -f json > kubeaudit-results.json
关键概念
| 术语 | 定义 |
|---|---|
| RBAC | 基于角色的访问控制(Kubernetes中),一种根据用户或服务账户的角色来管理对集群资源访问的方法 |
| ClusterRole | 集群级角色定义,指定适用于所有命名空间的权限(对资源的动词操作) |
| ClusterRoleBinding | 将ClusterRole与主体(用户、组、服务账户)在集群范围内进行关联 |
| 服务账户 | 与Pod关联的身份,用于向Kubernetes API服务器进行认证,默认自动挂载除非禁用 |
| automountServiceAccountToken | Pod规约字段,控制是否自动将服务账户Token挂载到Pod文件系统中 |
| 特权提升 | RBAC动词(bind、escalate、impersonate),允许用户为自己或他人授予提升的权限 |
工具与系统
- kubectl:主要的CLI工具,用于查询Kubernetes RBAC资源(角色、绑定、服务账户)
- rbac-tool:kubectl插件,用于RBAC分析,包括who-can查询、可视化和策略生成
- KubiScan:Python工具,用于扫描Kubernetes RBAC中的危险权限和权限提升路径
- Kubeaudit:安全审计工具,检查Pod和工作负载中的安全反模式,包括RBAC问题
- rakkess:kubectl插件,显示当前用户对所有资源类型的访问矩阵
常见场景
场景:审计由多个开发团队共享的EKS集群
背景:一个共享的EKS集群服务于四个开发团队。RBAC在初始设置时配置,但已有12个月未审查。各团队反映可以访问其他团队的命名空间。
处理方法:
- 列出所有ClusterRoleBinding,识别授予已认证用户宽泛访问权限的绑定
- 运行
kubectl rbac-tool who-can get secrets查找能跨命名空间读取Secret的主体 - 发现某个ClusterRoleBinding将
edit角色授予了system:authenticated,导致所有用户在整个集群拥有写入权限 - 运行KubiScan识别拥有危险权限的服务账户以及使用高权限服务账户运行的Pod
- 将该ClusterRoleBinding替换为每个团队的命名空间级RoleBinding
- 为不需要API访问的工作负载禁用automountServiceAccountToken
- 创建NetworkPolicy隔离团队间的命名空间流量
陷阱:移除ClusterRoleBinding可能会破坏依赖集群级访问的CI/CD流水线和Operator。在移除绑定之前,务必审计哪些工作负载在使用它们。EKS通过aws-auth ConfigMap将IAM角色映射到Kubernetes组,因此RBAC更改必须与IAM角色映射协调。
输出格式
Kubernetes RBAC 审计报告
===============================
集群: production-eks (EKS 1.28)
审计日期: 2026-02-23
命名空间数: 12
RBAC 清单:
ClusterRole: 48 (18个自定义, 30个系统)
ClusterRoleBinding: 32 (12个自定义, 20个系统)
Role (命名空间级): 24
RoleBinding (命名空间级): 36
服务账户: 67
关键发现:
[RBAC-001] ClusterRoleBinding 将 edit 角色授予 system:authenticated
绑定: authenticated-edit
影响: 所有已认证用户在所有命名空间拥有编辑权限
风险: 任何用户都可以修改任意命名空间中的资源
修复: 替换为每个团队的命名空间级RoleBinding
[RBAC-002] 自定义ClusterRole具有通配符权限
ClusterRole: developer-admin
规则: verbs=["*"], resources=["*"], apiGroups=["*"]
绑定: 4个用户通过developer-admin-binding绑定
风险: 实际权限等价于cluster-admin但未使用该名称
修复: 将权限范围限定为所需的特定资源和动词
汇总:
具有cluster-admin权限的主体: 6 (建议: <= 3)
具有通配符权限的角色: 4
拥有Secret访问权限的服务账户: 12
自动挂载Token的Pod: 45 / 67
特权容器: 8