4. Kubernetes RBAC 权限过度授予检测
场景搭建:一个被过度授权的 ServiceAccount
RBAC 过度授予的典型形态是:ServiceAccount 通过 ClusterRoleBinding 绑定了 cluster-admin,或通过 RoleBinding 绑定了包含 * 动词、* 资源的宽泛 Role。下面先构造一个可复现的检测对象。
# 1. 创建命名空间与 ServiceAccount
kubectl create namespace rbac-lab
kubectl -n rbac-lab create serviceaccount over-priv-sa
# 2. 绑定 cluster-admin(模拟过度授权)
kubectl create clusterrolebinding over-priv-binding \
--clusterrole=cluster-admin \
--serviceaccount=rbac-lab:over-priv-sa
# 3. 再创建一个"看似收敛"但实际过宽的自定义 Role
kubectl -n rbac-lab create role wide-role \
--verb=get,list,watch,create,delete \
--resource=pods,secrets,configmaps,serviceaccounts
kubectl -n rbac-lab create rolebinding wide-binding \
--role=wide-role \
--serviceaccount=rbac-lab:over-priv-sa
此时该 SA 同时持有集群级全权与命名空间级宽泛写权限,是检测脚本需要同时命中的两类风险。
权限边界探测:kubectl auth can-i
kubectl auth can-i 支持以任意身份模拟查询,是判断"实际能做什么"最直接的手段。关键是用 --as 指定 SA 的完整用户名格式:system:serviceaccount:<namespace>:<name>。
SA="system:serviceaccount:rbac-lab:over-priv-sa"
# 集群级高危动作探测
kubectl auth can-i create clusterrolebindings --as="$SA"
kubectl auth can-i delete nodes --as="$SA"
kubectl auth can-i '*' '*' --all-namespaces --as="$SA"
# 命名空间级探测
kubectl auth can-i delete secrets -n rbac-lab --as="$SA"
kubectl auth can-i get pods --all-namespaces --as="$SA"
# 列出该身份在全部命名空间下的全部权限(K8s 1.24+)
kubectl auth can-i --list --as="$SA" --all-namespaces
判读要点:yes 表示允许;no 表示无权限;no - <reason> 表示被显式拒绝规则拦截。若 create clusterrolebindings 返回 yes,说明该 SA 可自我提权,属于最高危信号。
结构化分析:rbac-tool 与权限图谱
kubectl auth can-i 是逐点探测,rbac-tool 则从集群整体视角枚举"谁对什么有什么权限",适合批量发现过度授权。
# 安装(Krew 方式)
kubectl krew install rbac-tool
# 1. 查看某 SA 的完整权限汇总
kubectl rbac-tool who-can get secrets
kubectl rbac-tool who-can '*' '*'
# 2. 导出全部 Role/ClusterRole 的权限矩阵
kubectl rbac-tool analysis --output json > rbac-analysis.json
# 3. 生成可视化权限图(输出 dot,可转 png)
kubectl rbac-tool viz --outformat dot > rbac.dot
dot -Tpng rbac.dot -o rbac.png
重点关注 who-can 结果中同时出现 cluster-admin 与普通 SA 的行,以及 analysis 输出里 rules 含 * 的条目。
检测脚本:批量识别过度授权
把上述探测固化为脚本,对命名空间内所有 SA 逐一评估,输出风险清单。
#!/usr/bin/env bash
# rbac-overgrant-check.sh —— 检测命名空间内 SA 的过度授权
set -euo pipefail
NS="${1:-rbac-lab}"
HIGH_RISK_VERBS=("create" "delete" "update" "patch")
HIGH_RISK_RES=("clusterrolebindings" "rolebindings" "secrets" "nodes" "pods/exec")
echo "== 命名空间 $NS 下 ServiceAccount 权限审计 =="
for sa in $(kubectl -n "$NS" get sa -o jsonpath='{.items[*].metadata.name}'); do
USER="system:serviceaccount:${NS}:${sa}"
echo "--- SA: $sa ---"
# 1. 是否具备集群级全权
if kubectl auth can-i '*' '*' --all-namespaces --as="$USER" 2>/dev/null | grep -q '^yes'; then
echo " [HIGH] 拥有集群级 */* 权限(疑似 cluster-admin)"
fi
# 2. 高危动词 × 高危资源组合
for v in "${HIGH_RISK_VERBS[@]}"; do
for r in "${HIGH_RISK_RES[@]}"; do
if kubectl auth can-i "$v" "$r" -n "$NS" --as="$USER" 2>/dev/null | grep -q '^yes'; then
echo " [MED ] 允许 $v $r"
fi
done
done
done
运行方式:bash rbac-overgrant-check.sh rbac-lab。预期输出中,over-priv-sa 会同时命中 [HIGH] 与多条 [MED ],其余未绑定宽泛角色的 SA 应无输出。
结果判读与修复方向
| 检测信号 | 含义 | 建议动作 |
|---|---|---|
can-i '*' '*' = yes | 集群级全权 | 移除 cluster-admin 绑定,改用最小权限 ClusterRole |
can-i create clusterrolebindings = yes | 可自我提权 | 禁止该动词,或改用受限 Role |
can-i delete secrets = yes | 可破坏/窃取凭据 | 收敛为只读或限定 resourceNames |
| rbac-tool who-can 命中多个 SA | 权限面过宽 | 按职责拆分 Role,避免共享宽泛角色 |
检测脚本仅做权限探测,不修改集群对象。修复前请先确认该 SA 的实际调用方,避免误删导致业务中断。