Technical documentation

Pod 有 Token 却删不掉资源?K8s 认证和授权的根本区别

Pod 有 Token 却删不掉资源?K8s 认证和授权的根本区别

在 Kubernetes 中,拥有有效的 ServiceAccount 凭据仅表示通过身份认证,实际能执行的操作完全取决于 RBAC 授权策略,而非凭据本身。

为什么在 Kubernetes 里拿到凭证不等于能访问所有资源

Kubernetes 将身份验证与资源授权物理隔离,导致 Pod 即使持有有效凭证被系统识别,仍因缺乏特定权限绑定而无法访问具体资源。

很多运维人员都遇到过这种尴尬场景:明明 Pod 里挂载了有效的 ServiceAccount Token,调用 API Server 也返回了 200 OK,可一旦尝试删除某个资源或读取 Secret,立刻被拒绝。这种“能进门却进不了房间”的现象,根源在于 Kubernetes 将身份验证与资源授权做了物理隔离[1]。

从“你是谁”到“你能做什么”的安全分水岭

认证只是第一道关卡。当 Pod 内的进程带着凭据向 API Server 发起请求时,系统只负责核对令牌是否有效。只要令牌没过期、签名对得上,这个请求就被标记为 system:authenticated[2]。这仅仅回答了“你是谁”,确认你拥有合法的身份,并不代表你有权操作任何数据。

真正的权限控制发生在第二道关卡——授权。Kubernetes 此时会调取 RBAC(基于角色的访问控制)策略,检查该主体是否被明确允许对特定资源执行特定动作[1]。如果缺少对应的 RoleBinding 或 ClusterRoleBinding,哪怕凭据完美无缺,系统也会直接拦截写操作或敏感数据的读取。

这里有一个常被外行误解的环节:很多人以为 ServiceAccount Token 就像一把万能钥匙,只要拿到了就能开所有的门。事实恰恰相反,Kubernetes 的认证机制并不传递“能力”,它只传递“合法性”。当你拿到 Token 时,你只是向系统证明“我是合法的进程”,但系统随后会立即问:“既然你是合法的,那你具体能干什么?”如果 RBAC 策略里没有把你和“删除 Pod”或“读取 Secret”这两个动作关联起来,Token 再完美也无法触发这些操作。这种设计意味着:身份层的作用是把“无主体请求”挡在门外,而授权层才决定了事故的爆炸半径[2]。若审计时只盯着 Token 的有效性,却忽略了 RBAC 绑定配置,就会把“可认证”误判为“最小权限”。实际上,取得凭据只代表通过了身份核验,离获得任意 API 权限还有巨大的鸿沟。

阶段 核心问题 判定依据 结果状态
认证 你是谁? ServiceAccount Token 有效性 system:authenticated
授权 你能做什么? RBAC Role/RoleBinding 绑定 Allow / Deny
审计误区 以为有身份就有权限 仅检查 Token 存在性 错误的高估风险

只有当这两层逻辑同时通过,Pod 才能真正执行操作。否则,那个看似强大的凭证,不过是一张没有具体房间钥匙的通用门禁卡。

Kubernetes 如何区分人与机器的身份模型

Kubernetes 采用双轨模型区分身份,普通用户需手动维护,而机器账号则通过 API 动态生成随应用部署边界自动产生的临时实体。

你在集群里看到的普通用户账号,根本没法通过 API 直接创建。能由 API 动态生成的,只有 ServiceAccount。这种设计把“人”和“机器”切成了两条平行的线。前者是管理员手动维护的静态实体,后者是随应用部署边界自动诞生的临时身份。[1][2]

ServiceAccount 作为机器主体的独特性

ServiceAccount 的核心特征在于它的“命名空间作用域”。它不像人类账户那样全局存在,而是被死死锁定在特定的 Namespace 内。[1][2] 这意味着一个在 dev 命名空间创建的 ServiceAccount,天然无法触碰 prod 环境的数据。这种隔离不是靠配置锁死的,而是对象本身的属性。

对比维度 普通用户账户 (User) ServiceAccount (机器主体)
创建方式 外部管理,不可由 K8s API 生成 完全由 API 动态创建与管理
作用域范围 通常跨集群或全局有效 严格限定在单个命名空间内
生命周期 长期稳定,依赖人工轮换 随 Pod 部署/销毁动态流转
绑定对象 关联具体的人或运维流程 直接挂载给 Pod 进程使用
主要用途 人类交互式操作 应用进程间认证与通信

这种架构差异解决了工程上的大麻烦:防止将人员账户、共享静态密钥与进程访问混为一谈。[1][2] 如果把所有东西都塞进同一个模型,一旦某个开发人员的 Token 泄露,或者某个旧脚本还在用硬编码的密钥,整个集群的爆炸半径就会瞬间失控。

Pod 启动时,会自动把关联的 ServiceAccount 凭据挂载到容器内部。进程拿到这个凭据去请求 API Server,系统会先确认它是 system:authenticated(已认证),但这只是第一步。[1][2] 接下来的授权环节,RBAC 才会根据该 ServiceAccount 的具体角色定义,决定它能读写哪些资源。

机器身份不强调“你是谁”,而强调“你在哪个上下文”。人类账户看重个人属性,ServiceAccount 看重的是部署边界。这种两段式结构——先降低无主体请求的风险,再通过授权层控制爆炸半径——才是工作负载安全治理的真正边界。[1][2]

RBAC 绑定策略如何决定 Pod 的实际权限范围

RBAC 绑定策略是连接已认证身份与操作权限的唯一桥梁,它决定同一个 ServiceAccount 在不同命名空间下能执行的具体动作范围。

同一个 ServiceAccount,换个命名空间或换一套 RoleBinding,它手里的刀就能从“切菜”变成“拆家”。[1][2] 这并非因为凭据变了,而是背后的授权规则变了。在 Kubernetes 里,拿到凭证只是拿到了入场券,RBAC(基于角色的访问控制)才是那张真正决定你能去哪个房间、能拿什么物品的地图。[1][2] 它是连接“已认证身份”与“具体操作权限”的唯一桥梁。[1][2]

Pod 里的进程拿着 ServiceAccount 的 Token 向 API Server 发起请求,这一步叫认证。认证通过后,系统确认你属于 system:authenticated 组,但这并不代表你可以为所欲为。[1][2] 接下来的每一步动作——读配置、删节点、扩容副本——都要经过 RBAC 的二次拦截。[1][2] 如果这张地图上没画你的路线,哪怕你手里有最完美的钥匙,门也不会开。[1][2] 这种两段式结构是机器身份治理的共同边界:身份层负责降低“无主体请求”的风险,而授权层才真正决定了事故的爆炸半径。[1][2]

很多审计工作容易在这里栽跟头。审核员看到 Pod 持有有效的 ServiceAccount 凭据,就默认该账号拥有集群内的所有能力。[1][2] 这是一种典型的“可认证即全权”陷阱。[1][2] 仅仅确认身份有效,却不去检查它绑定了什么 Role 或 ClusterRole,就会把“能进门”误判为“能进保险柜”。[1][2] 正确的做法必须把 ServiceAccount 本身和它的绑定关系拆开看:前者证明你是谁,后者定义你能做什么。[1][2]

为了看清这种差异,我们可以对比不同绑定场景下的实际权限表现:

场景特征 ServiceAccount 状态 RoleBinding 指向 实际权限结果
默认配置 已创建且有效 无绑定或仅基础只读 只能读取少量资源,无法修改任何对象
跨命名空间部署 同一账号复用 绑定至特定 Namespace 的 Role 仅在该命名空间内拥有定义的操作权
错误的高权绑定 同一账号复用 绑定至 ClusterRole (admin) 获得整个集群的读写权限,风险极大
审计盲区 凭据有效 未检查绑定关系 误判为拥有全部权限,掩盖真实风险

这种差异揭示了为什么不能只看凭证。[1][2] 即使两个 Pod 使用完全相同的 ServiceAccount Token,只要它们所在的命名空间不同,或者挂载的 RoleBinding 不同,它们的实际能力就是天壤之别。[1][2] 这种设计不是偶然的特性,而是 Kubernetes 认证后进入授权流程的必然结果。[1][2] 如果你只盯着 Token 的有效性,却忽略了 RBAC 的精细度,就等于在评估资产风险时,只看了锁有没有坏,却没看钥匙孔到底通向哪里。[1][2]

最终,整个安全链条是这样运转的:ServiceAccount 提供身份锚点,API Server 验证其合法性,RBAC 引擎根据当前的绑定策略计算具体的 Action-Resource 对。[1][2] 只有当这三者严丝合缝地配合时,才能界定出真正的最小权限。[1][2] 忽略其中任何一环,尤其是 RBAC 绑定策略,都会让“有凭证不等于能访问所有资源”这句原则失效,留下巨大的安全缺口。[1][2]

实操建议:如何快速定位“隐形高权”账号 不要依赖肉眼排查 YAML 文件,建议编写一个简单的自动化脚本或利用 kubectl auth can-i 命令进行批量扫描。具体步骤如下:首先列出集群中所有非默认的 ServiceAccount;其次,对每个账号执行 kubectl auth can-i --list --as=system:serviceaccount:<namespace>:<sa-name> 命令;最后,将输出结果与业务需求文档比对。如果发现某个仅用于“日志收集”的 Pod 拥有 delete 权限,或者某个测试环境的账号绑定了 cluster-admin,这就是典型的“隐形高权”,应立即切断其不必要的绑定。这种基于“能力清单”而非“凭据存在性”的审计方法,能精准识别出那些持有有效 Token 却越权的隐患。


常见问题解答 (FAQ)

Q: 既然 ServiceAccount 是机器账号,为什么还需要像人类一样进行复杂的授权配置? A: 正是因为它是机器账号,所以更容易被自动化脚本批量利用。如果不做精细的 RBAC 限制,一旦某个 Pod 被攻破,攻击者就能利用其高权限凭证横向移动,造成比人类账号泄露更严重的后果。

Q: 如何快速发现那些“有凭证但权限过大”的 ServiceAccount? A: 不要只看 Token 是否存在。应该定期扫描集群中的 RoleBinding 和 ClusterRoleBinding,找出那些绑定了 admin 或 cluster-admin 等宽泛角色的 ServiceAccount,并对照业务需求进行裁剪。

Q: ServiceAccount 和普通 User 账号在安全性上最大的区别是什么? A: 最大的区别在于作用域和生命周期。User 通常是全局的、长期的;而 ServiceAccount 严格限定在命名空间内,且随 Pod 的生命周期动态产生和销毁,这大大减少了密钥泄露后的暴露窗口。


参考来源

  1. Authenticating | Kubernetes · https://kubernetes.io/docs/reference/access-authn-authz/authentication/(A级)
  2. Managing Service Accounts | Kubernetes · https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/(A级)