Technical documentation
手里攥着 ServiceAccount Token,不代表能随便删库:K8s 认证与授权是两码事
手里攥着 ServiceAccount Token,不代表能随便删库:K8s 认证与授权是两码事
Kubernetes 认证与授权分离机制指 ServiceAccount 凭据仅证明机器身份,而具体操作权限完全由 RBAC 规则独立判定,持有凭证不等于拥有全部资源访问权。
为什么持有 Token 不代表拥有全部操作权?
持有 Token 仅代表请求者通过了身份验证被识别为合法用户,但能否执行操作取决于后续 RBAC 规则是否授予了相应资源权限,二者是独立的两个步骤。
手里攥着 ServiceAccount 的 Token,并不代表能随意操作集群里的资源。这就像你持有酒店房卡,只能证明你是住客(身份),但能不能进总统套房或动用客房服务,还得看前台给你的具体授权(权限)。在 Kubernetes 里,这种区分是系统设计的基石:拿到机器身份不等于有所有权限。
ServiceAccount 与人类账户的根本差异
Kubernetes 严格区分了面向人的普通用户和面向应用进程的 ServiceAccount。普通用户不是通过 API 创建的账户对象,而是由外部身份源管理;ServiceAccount 则完全由 API 管理,且被限制在特定的命名空间内[1][2]。这一设计划定了清晰的边界:工作负载的身份应随部署上下文流动,绝不能把人员账号、共享静态密钥与进程访问混为一谈[1][2]。将两者混同,会导致权限失控,让本应隔离的进程拥有不该有的全局视野。
一个常被误解的细节是:许多开发者认为给 Pod 挂载了 ServiceAccount 令牌就自动拥有了该命名空间下的“管理员”能力,或者默认认为它拥有读取所有资源的权利。事实恰恰相反,如果没有显式的 RBAC 绑定,这个令牌甚至无法读取最基础的 ConfigMap 或 List 自己的 Deployment。这种“零权限默认值”的设计初衷,正是为了防止因配置疏忽导致的横向移动风险——哪怕攻击者拿到了 Token,如果缺乏对应的 RoleBinding,他们连查看当前命名空间下有什么资源都做不到。
认证成功后的真实状态:system:authenticated
当 Pod 内的进程使用关联的 ServiceAccount 向 API Server 发起认证时,一旦成功,该请求者仅仅被归入 system:authenticated 组[1][2]。这个状态只回答了“你是谁”,确认了请求方的合法性,却没有任何关于“你能做什么”的信息。随后的每一次资源访问请求,都必须经过 RBAC 授权机制 的二次校验[1][2]。取得凭据只是拿到了入场券,RBAC 才是决定你在场内能走哪条路的安检员。认证回答“是谁”,授权才决定“能做啥”。
值得注意的是,system:authenticated 组是一个巨大的“安全漏斗”,任何合法的用户或机器都会落入其中。这意味着,如果你只检查“谁在系统中”,你会看到成千上万个合法的实体,但这并不代表其中任何一个都有权限执行关键操作。真正的安全边界是在进入这个组之后,通过具体的 Rule 定义来切割的。
RBAC 如何决定你能做什么:两段式运作原理
RBAC 通过两段式运作将身份识别与权限判定拆分:Token 仅完成第一道认证关卡,真正的操作许可需由第二道 RBAC 规则引擎根据绑定关系独立决定。
一个 Pod 拿到了 ServiceAccount 的 Token,能直接操作集群里的所有资源吗?不能。它只是通过了第一道关卡,被标记为 system:authenticated [1][2]。真正的权限判定,发生在后续由 RBAC 规则执行的第二道关卡。这种设计将“你是谁”和“你能做啥”彻底拆分成两个独立步骤,避免了身份凭证成为万能钥匙。
从“我是谁”到“我能做啥”的完整流程
整个请求链路像两道安检门。第一道门是认证层(Authentication)。当 Pod 内的进程发起 API 请求时,API Server 会校验其携带的 Token 是否有效、是否属于某个合法的 ServiceAccount。这一步只负责确认主体身份,一旦通过,系统就承认“你存在且合法”,但此时你手里并没有打开任何资源的钥匙 [1][2]。
紧接着进入第二道门:授权层(Authorization)。这里运行着 RBAC 机制,它是决定动作范围的唯一依据。系统会拿着你的身份标签,去匹配预先配置好的 Role 或 ClusterRole 绑定规则。只有当规则明确允许你对特定资源执行特定动词(如 get、list、delete)时,请求才会放行 [1][2]。如果规则里没写,哪怕你有再有效的 Token,结果也是被拒绝。
为了看清这两层的分工,可以对比它们在处理请求时的不同关注点:
| 层级 | 核心任务 | 输入依赖 | 输出结果 |
|---|---|---|---|
| 认证层 | 验证身份真实性 | Token、证书、签名 | 确认 system:authenticated 状态 |
| 授权层 | 判定操作范围 | 身份标签 + RBAC 规则 | 允许或拒绝具体 API 动作 |
爆炸半径的控制逻辑
很多人误以为拿到凭证就等于拿到了权限,这其实混淆了“可认证”与最小权限原则。身份层的作用仅仅是降低“无主体请求”的风险,防止匿名流量混入;真正控制破坏范围的,是授权层划定的边界 [1][2]。
即使一个恶意攻击者窃取了有效的 ServiceAccount 凭据,只要该账户没有对应的 RBAC 绑定,或者绑定规则极其严格,它的实际破坏力就被限制在极小的范围内。反之,若审计时只检查身份是否有效,却忽略了 RBAC 绑定的缺失或宽泛配置,就会错误地认为系统遵循了最小权限原则[1][2]。这种结构性推论提醒我们:身份只是入场券,RBAC 才是锁门的钥匙。只有两层同时满足,才能确保机器身份既真实可信,又受控于安全边界。
在实际案例中,这种分离机制曾挽救过多次事故。例如某云服务商在迁移旧版项目时,发现多个生产环境 Pod 继承了默认的 ServiceAccount 令牌,这些令牌本身是有效的,但由于未及时清理旧的 ClusterRoleBinding,导致它们意外获得了 cluster-admin 级别的权限。如果仅靠检查 Token 有效性,这些 Pod 会被标记为“安全”,但实际上它们已经具备了删除整个集群的能力。正是通过深入分析 RBAC 绑定关系,团队才发现了这个隐蔽的“幽灵权限”,并及时将其降级为仅允许读写特定 Namespace 的 Role。
审计陷阱:只查身份有效会如何误判?
仅检查身份有效性会误判合规性,因为认证成功只代表能进门而未限制具体房间,跳过 RBAC 绑定检查会导致高权限漏洞因未被发现而漏报。
很多安全扫描工具在检查合规性时,只要发现 Pod 挂载了有效的 ServiceAccount 令牌,就标记为“通过”。这种判断存在致命盲区:它混淆了“能进门”和“能进哪间房”的区别。认证成功仅代表请求者被识别为 system:authenticated,此时系统并未开启任何资源访问限制。若审计流程止步于验证凭证有效性,却跳过 RBAC 绑定检查,就会把“可认证”错误等同于“已限制权限”,导致实际运行中的高权限漏洞被漏报[1][2]。
结构性推论 vs 普遍保证
这种两段式运作是 Kubernetes 架构的必然结果,而非通用规则。当请求通过认证后,API Server 必须进入独立的授权阶段,由 RBAC 引擎根据具体的 RoleBinding 或 ClusterRoleBinding 决定动作是否被允许[1][2]。这意味着,身份层仅负责降低“无主体请求”的风险,真正的爆炸半径控制完全依赖授权层。
需要明确的是,这一逻辑是对 Kubernetes 特定实现(ServiceAccount + RBAC)的结构性推论。不能将其泛化为所有认证器与授权器的通用行为。在其他系统中,认证与授权可能耦合,或者采用不同的模型。但在 K8s 中,持有令牌只是拿到了入场券,没有对应的角色绑定,这张票就是废纸;反之,若绑定宽松,令牌再完美也如同持有了万能钥匙[1][2]。
为了看清两者的差异,我们可以对比两种常见的审计视角:
| 审计关注点 | 仅检查凭证有效性 | 完整链路验证(身份+RBAC) |
|---|---|---|
| 判定依据 | Token 是否存在且未过期 | Token 有效 + 对应 RoleBinding 存在 |
| 覆盖范围 | 仅确认“我是谁” | 确认“我是谁”且“我能做什么” |
| 风险盲点 | 忽略过宽的角色绑定 | 无 |
| 误判结果 | 将高权限 Pod 视为合规 | 准确识别最小权限违规 |
| 适用场景 | 基础连通性测试 | 安全合规与权限评估 |
构建正确的安全评估模型
真正的安全评估不能止步于凭证的存在性检查。你必须建立覆盖“身份 - 角色 - 绑定”全链路的验证机制。具体做法是:先确认 ServiceAccount 凭据有效,随即查询该账户在命名空间内绑定的所有 Role 或 ClusterRole,最后核对这些角色的 Rule 定义是否包含敏感操作(如 delete、exec、secret 读取等)。只有当这三个环节全部闭环,才能认定符合最小权限原则[1][2]。忽略其中任何一环,都会让安全防线出现缺口。
针对这一需求,建议采取以下具体操作步骤:
- 自动化扫描:使用
kubectl auth can-i --list --as=system:serviceaccount:<namespace>:<sa-name>命令,模拟该 ServiceAccount 的视角,列出其所有实际拥有的权限。 - 通配符审查:在扫描结果中,重点排查包含
*的资源类型或动词,以及涉及secrets、pods/exec、nodes等高危对象的规则。 - 动态基线比对:定期将扫描结果与预定义的“最小权限基线”进行比对,任何新增的宽泛权限都应触发告警并强制人工复核。
常见问题解答 (FAQ)
Q: 如果 ServiceAccount 没有绑定任何 Role,它能做什么? A: 它什么都做不了。虽然它通过了认证(身份验证),但在授权阶段会被拒绝所有请求。这就是为什么“拿到机器身份不等于有所有权限”。
Q: 为什么有些教程建议给 ServiceAccount 绑定 ClusterRole? A: 通常是为了方便跨命名空间的管理,但这往往违反了最小权限原则。最佳实践是优先使用命名空间级别的 Role,仅在确实需要全局权限时才谨慎使用 ClusterRole。
Q: 如何快速检查我的 ServiceAccount 是否权限过大?
A: 不要只看 Token 是否有效。你需要检查该 ServiceAccount 绑定的 RoleBinding 指向的 Role 或 ClusterRole 中,是否包含了 * 这样的通配符,或者是否赋予了 secrets、pods/exec 等高危权限。此外,直接使用 kubectl auth can-i 模拟该 SA 的权限列表是最直观的方法。