展开主题导航
工程验证记录

只禁了 get secret 还不够?创建 Pod 权限也能间接偷走机密

阅读说明与证据边界

正文中的规范规定、官方实现行为、工程建议与待验证假设应分别判断;请结合版本与适用范围阅读。

只禁了 get secret 还不够?创建 Pod 权限也能间接偷走机密

在 Kubernetes 同一命名空间内,拥有创建 Pod 权限的主体可通过挂载 Secret 实现间接读取,这打破了仅凭缺乏直接获取权限即认为数据安全的误区。

揭开权限背后的真相:创建即读取的隐形陷阱

RBAC 审查中误将创建 Pod 与读取密钥视为独立关卡是安全盲区,实际上赋予工作负载创建权往往等同于授予了该命名空间内机密的访问能力。

很多管理员在审查 Kubernetes Secret 安全边界 时,常有一种直觉上的安全感:只要没给谁 get secret 的权限,数据就是安全的。这种想法源于对 RBAC 权限审查 的机械理解,误以为“谁能创建 Pod”和“谁能读取密钥”是两道互不相关的关卡。然而,官方安全说明直接打破了这一迷思 [1]。

事实往往比想象更棘手。在同一命名空间内,获准创建 Pod 的主体,通常可以指挥新创建的 Pod 引用该命名空间的 Secret。这就形成了一条隐蔽的间接读取路径。当允许创建一个 Pod 时,实际上也赋予了该工作负载挂载并读取同命名空间下所有可用资源的潜在能力。这就像只锁了保险柜,却忘了把启动运钞车的钥匙交给别人一样危险。当然,这条路径的实际利用仍受限于准入控制、服务账户策略及具体的工作负载配置 [1],但这足以证明,任何拥有创建 Pod 能力的主体,都构成了一个潜在的机密读取入口。

为什么会有这个误解?

这种误判的根源,在于传统安全模型习惯将“数据访问”与“计算执行”割裂看待。人们认为只要锁住数据文件(Secret),运行代码的容器(Pod)就进不去。但在 Kubernetes 的实际风险模型中,这两个领域并非独立存在 [1]。

官方明确指出,“允许创建工作负载”与“允许读取机密”在风险逻辑上紧密耦合,不能简单视为独立的授权域 [1]。这意味着,仅审查针对 Secret 的直接访问权限是远远不够的。如果只盯着谁有 get secret 权限,而忽略了谁拥有 create pod 权限,防御体系就会出现巨大的盲区。这种间接读取路径的实际利用,虽然受限于准入控制、服务账户策略及具体的工作负载配置 [1],但风险依然真实存在。

这里有一个常被忽视的语境差异:RBAC 的“对象级”限制与 Pod 运行时“上下文级”执行的错位。 许多管理员在配置 Role 时,会精确地禁止某个 ServiceAccount 对 secrets 资源进行 get/list/watch 操作,这在 API 层面确实生效了。然而,Kubernetes 的机制设计让 Pod 本身成为了一个“特权代理”。一旦攻击者拥有了创建 Pod 的权限,他们不需要通过 API 去请求 Secret,而是直接在 Pod 的 YAML 定义中声明“我要挂载名为 my-secret 的卷”。此时,API Server 在创建 Pod 时的校验逻辑,关注的是“该用户是否有权创建这个 Pod 对象”,而不是“这个 Pod 内部引用的资源是否被该用户直接访问过”。这种校验维度的错位,使得基于“拒绝获取 Secret”的传统 RBAC 规则在面对“创建 Pod”这一动作时瞬间失效。攻击者利用了系统对“创建行为”的放行,绕过了对“数据内容”的拦截,这正是许多合规审计中容易遗漏的深层逻辑漏洞。

机制深度拆解:载体角色的误判与攻击链

Kubernetes 的安全机制存在隐蔽路径,允许创建 Pod 的权限足以让新工作负载自动挂载并读取同命名空间内的机密,无需具备直接的 API 获取权限。

很多人以为,只要没有直接调用 API 获取 Secret 的权限,数据就是安全的。这种想法忽略了 Kubernetes 中一个隐蔽的“后门”:创建 Pod 的权限本身,就足以打开读取机密的大门。

载体角色的误判:Secret 不是绝对边界

Secret 的本质是受保护的数据载体,而非不可逾越的安全边界。官方文档明确指出,Secret 默认以未加密形式存储在 API server 底层的 etcd 中 [1]。这意味着,一旦攻击者获得访问 API 或 etcd 的能力,静态存储的数据即刻暴露。但这并非意味着集群必然被攻破,而是强调了一个设计基线:静态加密应作为集群侧的标配,而非可选的加固项。

当我们将目光从存储层移向运行时,风险路径变得更加清晰。在同一命名空间内,获准创建 Pod 的主体,通常可以令新部署的工作负载引用该命名空间的 Secret [1]。Pod 在启动阶段即可通过挂载卷或环境变量直接获取这些敏感信息,完全无需再调用 API 进行二次请求。这就像你虽然没拿到保险柜的钥匙,但你有权把整个保险柜搬进自己的房间,然后在里面随意取用财物。

为了更直观地理解不同配置下的风险差异,我们对比一下两种典型场景:

对比维度 场景 A:默认配置 场景 B:严格限制配置
Pod 创建权限 拥有 拥有
Volume 挂载策略 允许挂载 Secret 卷 禁止挂载非白名单资源
ServiceAccount 权限 默认高权或无限制 最小权限原则(No-attach)
Secret 访问结果 成功间接读取 部署失败或被拒绝
风险等级 高危(路径畅通) 低危(路径阻断)

表格中的数据表明,单纯的“允许创建”并不等同于“允许读取”,中间还隔着准入控制和策略配置的关卡。然而,现实中的许多集群并未默认开启严格的限制。因此,审查 RBAC 权限时,不能只盯着谁有 get secret 的权限。必须同时审视工作负载的创建权限,因为这两者在实际风险模型中并非独立的授权域 [1]。只有将静态加密、最小权限 RBAC 以及限制 Secret 暴露范围视为设计基线,才能真正堵住这个由“创建”引发的间接读取漏洞。

如何审查权限?打破‘允许创建即允许读取’的盲区

要打破允许创建即允许读取的盲区,必须建立组合权限风险评估模型,不再单一依赖拒绝获取机密的规则,而是同时审查工作负载创建权限。

很多人认为只要没给“获取机密”的权限,数据就是安全的。这种想法忽略了 Kubernetes 中一条隐蔽的路径:拥有创建 Pod 权限的主体,往往能间接读取同一命名空间内的机密 [1]。当工作负载被创建并挂载了 Secret 时,访问控制列表上的“拒绝”可能瞬间失效。要打破这个误区,不能只看单一权限,必须建立组合权限的风险评估模型。

实战中的防御策略

审查过程需要覆盖从存储层到应用层的多个环节。首先检查 API server 的加密配置和 etcd 的访问控制,这是防止底层数据裸奔的最后一道防线 [1]。其次,必须核对 Role 和 RoleBinding 的具体定义,确认 ServiceAccount 是否被错误地赋予了过宽的权限。这些措施并非可选的加固项,而是官方推荐的安全设计基线 [1]。

检查维度 传统误区做法 正确的审查动作
权限范围 仅关注 get secret 权限 同步审查 create pod 及部署类权限
数据存储 假设集群默认安全 核验 API server 与 etcd 的静态加密状态
暴露方式 全量挂载所有密钥 限制 Secret 仅暴露给必要容器
存储方案 依赖原生 Secret 在适用场景采用外部机密存储(如 Vault)
监控机制 忽略审计日志 定期分析异常创建工作负载的行为记录

除了静态配置,动态防御同样关键。建议将 Secret 的暴露范围严格限制在必要的容器内,避免全量挂载带来的扩散风险。对于高敏感场景,应优先采用外部机密存储替代原生 Secret,将控制权移出集群边界。同时,必须开启并持续监控审计日志,任何异常的创建工作负载行为都可能是攻击者试图绕过权限控制的信号 [1]。

真正的安全不在于某一项权限的缺失,而在于对“创建”与“读取”关联性的全面认知。只有当加密配置、RBAC 定义、服务账户绑定以及审计记录全部通过核验,才能确认这套防御体系真正生效 [1]。

常见问题解答 (FAQ)

Q: 如果我只禁用了 get secret 权限,是否就安全了? A: 不一定。如果攻击者拥有 create pod 权限,他们可以通过创建新的 Pod 来挂载并读取同命名空间下的 Secret,从而绕过直接的 API 读取限制。

Q: 如何彻底阻断这种间接读取路径? A: 需要实施最小权限原则,不仅限制 get secret,还要严格控制 create pod 权限,并结合 Pod Security Policies (PSP) 或 OPA Gatekeeper 等工具,禁止非白名单的资源挂载。

Q: 静态加密能解决所有问题吗? A: 静态加密能保护 etcd 中的数据不被离线窃取,但如果攻击者已经获得了在集群内创建 Pod 的权限,他们可以在运行时解密并读取数据,因此静态加密只是防御体系中的一环,而非全部。


参考来源

  1. Secrets | Kubernetes · https://kubernetes.io/docs/concepts/configuration/secret/(A级)