问题背景
在一次常规的集群巡检中,安全团队发现某业务命名空间下存在异常的跨命名空间 API 调用日志。进一步分析发现,攻击者通过获取 Pod 内默认 ServiceAccount 的 Token,成功列举了整个集群的 Secret 资源,并尝试读取敏感配置。幸运的是,由于 RBAC 收敛及时,未造成实质数据泄露,但暴露了集群在 ServiceAccount Token 管理上的系统性风险。
故障现象
- 某业务 Pod 的 stdout 中频繁出现
kubectl get secrets --all-namespaces的执行记录 - 审计日志显示
system:serviceaccount:prod:default用户在短时间内发起大量 LIST 请求 - 部分 Secret 资源被尝试读取,但因 RBAC 限制返回 403
- 安全扫描工具报出多处 Pod 使用了默认 ServiceAccount 且
automountServiceAccountToken: true
排查过程
1. 定位异常 Token 使用
首先通过 Kubernetes 审计日志定位异常主体:
|
|
发现该 ServiceAccount 在 2 小时内发起了 1800+ 次 LIST 请求,目标资源包括 secrets、configmaps、serviceaccounts 等。
2. 确认 Token 来源
进入可疑 Pod 检查挂载情况:
|
|
确认 Pod 确实自动挂载了 default ServiceAccount 的 Token,且该 Token 具备 system:serviceaccount:prod:default 身份。
3. 枚举该 Token 的实际权限
使用 Token 进行权限自检:
|
|
返回结果显示该 Token 对多个命名空间的 secrets 资源具备 list 权限,确认存在权限过大问题。
4. 追溯 Token 被滥用的路径
通过 Falco 规则捕获异常进程:
|
|
最终发现异常进程为业务容器内的一个 Python 脚本,通过 kubernetes SDK 使用默认 Token 进行服务发现。
解决方案
-
立即禁用自动挂载:在受影响的 Deployment 中显式设置
automountServiceAccountToken: false -
创建最小权限 ServiceAccount:为业务 Pod 单独创建 SA,并绑定仅包含必要权限的 Role/ClusterRole
-
启用 Token 投影:配置
projectedvolume,使用expirationSeconds限制 Token 有效期(建议 1h 以内) -
审计并清理默认 SA 的权限:执行
kubectl get rolebinding,clusterrolebinding --all-namespaces -o yaml | grep -B5 'system:serviceaccount:.*:default',逐一收紧
根因分析
根本原因是 Kubernetes 早期版本默认行为允许 Pod 自动挂载 default ServiceAccount Token,且该 Token 继承了命名空间内默认的宽松 RBAC 策略。在多租户或敏感业务场景下,这一设计导致任意 Pod 都可能成为横向移动的起点。
预防措施
- 在集群级别通过 Admission Controller 强制要求所有 Pod 显式声明
automountServiceAccountToken - 定期运行
kubectl auth can-i --list --as=system:serviceaccount:<ns>:default进行权限巡检 - 对高敏感命名空间启用
PodSecurityPolicy或Pod Security Standards,禁止使用 default SA - 在 CI/CD 流水线中加入 Token 权限扫描步骤,阻止宽权限配置上线
- 考虑启用
BoundServiceAccountTokenVolume(GA 后默认开启),并设置合理的audience和过期时间
总结
一次看似普通的「默认 Token 自动挂载」配置,最终演变为潜在的横向权限泄露入口。通过本次排查,我们深刻认识到:在 Kubernetes 安全实践中,「默认即安全」往往是最大的误区。只有坚持最小权限原则、持续审计 ServiceAccount 权限,才能真正筑牢集群的身份防线。