Skip to content

第 7 章:服务不保存密钥,启动时怎么证明“我就是我”? ​

本章主线:从 Git 仓库里的云密钥出发,走到工作负载证明、短期身份、SPIFFE/SPIRE、云 IAM 与零信任策略。

开场:删掉 Secret 后服务还能启动吗 ​

安全扫描发现订单服务镜像里有长期云密钥。小安准备把它移到 Kubernetes Secret,评审却问:只是换了保存位置,泄漏和轮换问题真的解决了吗?

更好的问题是:平台能否依据 Pod、节点、镜像、命名空间等不可轻易伪造的证据确认工作负载,并动态发放短期凭证?这就是工作负载身份的起点。

学习目标 ​

能盘点机器身份;区分节点、Pod、服务和任务;配置短期云联邦;解释 SPIFFE attestation;设计 mTLS 后的授权;制定静态密钥迁移与回滚。

身份层次不要混用 ​

层次示例能证明什么不能自动证明什么
节点VM instance identity哪台受管主机主机上哪个进程
编排工作负载Kubernetes ServiceAccount哪类 Pod/命名空间具体业务权限
服务身份SPIFFE ID哪个逻辑服务当前代表哪个用户
任务身份CI job/run ID哪次构建/部署制品一定可信
Agent 实例agent run ID + workload哪次 Agent 运行用户委托范围

7.1 为什么静态密钥不适合云原生 ​

容器快速创建、销毁和迁移,IP 不稳定;长期 API Key 容易进代码、镜像、CI 日志或备份,泄漏后难定位实例和撤销。目标是让运行环境证明“我是什么工作负载”,自动获得短期、受限凭证。

7.2 云 IAM 心智模型 ​

云授权通常由身份策略、资源策略、组织边界、会话策略和显式 deny 组合。必须理解实际有效权限,而非只看某个角色页面。

  • 长期用户密钥:尽量消除。
  • Role/Service Account:代表工作负载或任务。
  • Assume Role/Federation:用已有可信身份换短期会话。
  • Resource Policy:资源端限制谁可访问。
  • Permission Boundary/SCP:限制最大权限,不主动授予。

跨账号信任需限制 principal、外部 ID/条件、source identity、session duration 和可承担链。

7.2.1 有效权限计算 ​

不要假设“角色策略允许即允许”。资源策略、身份策略、组织级限制、permission boundary、会话策略和显式 deny 共同决定。建立 policy simulator/访问分析,并用真实拒绝日志验证。

示例风险:信任策略允许任意仓库的 CI OIDC subject 承担生产角色;攻击者在自己仓库构造合法平台 token 即可进入。必须约束 organization/repository/ref/environment 与 audience。

7.3 Kubernetes 身份 ​

Pod 通常通过 ServiceAccount 获得投射 token。控制点:每工作负载独立 SA;关闭不必要自动挂载;短期、audience-bound token;最小 RBAC;限制 secret 读取;使用 admission policy 防危险配置。

Kubernetes RBAC 对 namespaced/cluster resource 授权,不等于云 IAM 或业务 API 授权。三层身份需要明确映射,不能让一个节点角色代表所有 Pod。

7.3.1 投射 ServiceAccount Token ​

Token 应有目标 audience 和短有效期,由 kubelet 轮换。应用通过标准文件读取并处理轮换,不把 token 打进日志。目标服务验证 issuer、audience、时间,并将 SA 映射到明确工作负载,而非把整个 namespace 当同一身份。

7.3.2 最小 RBAC ​

避免 cluster-admin、通配 verb/resource 和读取全命名空间 Secret。使用权限检查与审计日志验证实际能力;控制谁能创建 Pod,因为能创建使用高权 SA 的 Pod 常等于获得该身份。

7.4 SPIFFE/SPIRE ​

SPIFFE 定义工作负载身份标准:

  • SPIFFE ID:spiffe://trust-domain/workload-path;
  • SVID:可验证身份文档,常见 X.509 或 JWT;
  • Workload API:工作负载本地获取和更新身份;
  • Trust Bundle:验证信任域签发者;
  • Federation:跨信任域建立互信。

图 7-1:7.4 SPIFFE/SPIRE

图 7-1:7.4 SPIFFE/SPIRE · 可编辑 Mermaid 源码

工作负载无需携带 bootstrap secret;Agent 通过内核/平台属性证明调用者。生产设计要保护 SPIRE Server/Agent、注册权限、信任域、联邦 bundle 和轮换。

7.4.1 Selector 与注册 ​

Kubernetes selector 可组合 namespace、ServiceAccount、Pod label、container image 等。选择过宽会让同节点/同 namespace 的恶意 workload 获得身份;选择过细会导致部署变更后身份中断。把 selector schema 当 API 管理并测试。

7.4.2 Trust domain 设计 ​

生产与开发、不同监管区域或安全管理边界通常分 trust domain。跨域 federation 只交换 bundle,不自动授权;双方仍按对方 SPIFFE ID 和资源策略决定。

7.5 mTLS 不等于授权 ​

mTLS 回答连接方持有什么证书;业务仍需判断该 SPIFFE ID 能否调用 POST /payments。把证书 DN 硬编码在代码会造成迁移困难,应统一 identity mapping 与策略。

7.5.1 代理终止问题 ​

若 sidecar 终止 mTLS,应用收到的是本地代理连接。代理必须通过受保护元数据传递已验证身份,应用只信任本地受控通道;防止外部请求直接注入同名头。高风险服务可让授权在代理和应用双层执行。

7.6 CI/CD 与供应链身份 ​

流水线应以 OIDC/工作负载联邦换取短期云权限;每个仓库、分支、环境限制 trust claims。生产部署要求受保护分支、审批、构建证明、制品签名和部署者身份审计。

不要给所有 CI job 一个组织级云 secret。Fork PR、第三方 Action、缓存和日志都是泄漏面。

7.6.1 发布证明链 ​

text
开发者身份 → 受保护代码评审 → CI 工作负载身份
→ 构建 provenance → 签名制品 → 部署工作负载身份
→ 目标环境策略验证

身份不仅决定“谁能部署”,还用于证明“哪个源码、哪个构建器产生了当前制品”。部署系统验证证明和签名,不能只信镜像标签。

7.7 零信任原则 ​

零信任不是“永不信任”,而是不因网络位置或资产归属隐式信任;每次访问基于主体、设备/工作负载、资源、策略和动态信号做明确判断。

图 7-2:7.7 零信任原则

图 7-2:7.7 零信任原则 · 可编辑 Mermaid 源码

落地顺序:盘点主体和资源;建立强身份;定义分层策略;把 PEP 放在不可绕过处;接入遥测;逐步缩小隐式网络信任;持续验证。

7.8 服务网格与 API Gateway ​

Service Mesh 适合东西向服务身份、mTLS 和粗粒度策略;API Gateway 适合南北向认证、限速、路由。对象级权限仍在服务或统一授权层执行。

Sidecar/ambient 模式有不同运维和攻击面。任何代理代为传递身份时,都要确保下游身份头不可由外部伪造,并绑定受保护连接。

7.9 密钥与 Secret 迁移路线 ​

  1. 盘点 secret、owner、使用和权限;
  2. 集中保管与自动轮换;
  3. 应用启动时动态获取,不写镜像/仓库;
  4. 用工作负载身份换短期凭证;
  5. 删除旧 secret 并监控复用;
  6. 阻止新增长期 secret 的策略门禁。

7.9.1 双轨迁移 ​

先让应用同时支持静态 secret 和工作负载身份;影子验证新身份;小流量切换;监控拒绝和延迟;确认后撤销旧 secret。回滚只能在短窗口恢复受控旧凭证,不能长期“双轨永久化”。

记录每个 secret 的最后使用时间,撤销后监控任何复用尝试,这往往能发现遗漏的消费者。

7.10 本章实验与验收 ​

部署两个 Kubernetes 服务与 SPIRE,使其用 X.509-SVID mTLS;策略只允许 frontend 调用 orders 的只读接口;轮换 SVID、撤销注册、模拟 Agent 故障。

验收:说明节点身份与 Pod 身份差异;为何 JWT-SVID 更易重放;怎样无长期云密钥部署;零信任为何不是 VPN 替代品。

7.10.1 生产验收清单 ​

  • 工作负载重建后自动获得相同逻辑身份,但实例凭证不同;
  • 私钥不可从 Workload API 导出到其他进程使用;
  • SVID 自动轮换不中断连接;
  • 删除注册后新凭证停止签发,旧凭证暴露窗口有界;
  • 错 trust domain、错 SPIFFE ID 和过期证书被拒;
  • 业务授权日志保留 caller workload ID 与动作。

工程复盘:把云密钥移进 Vault,为什么还不能宣布完成 ​

小安把代码仓库里的长期云密钥迁入 Vault,扫描告警清零了。但服务仍在启动时取出同一把长期密钥,多个副本共享,轮换还需要人工重启。密钥只是换了存放位置,身份、最小权限和撤销问题都没有消失。

第二版方案让平台根据命名空间、ServiceAccount、镜像和节点证明工作负载,签发短期、限定 audience 的凭证。迁移没有一步切换:先让旧密钥与新身份双轨运行,在影子模式比较授权结果;按服务灰度;监控签发失败、凭证年龄和权限差异;确认回滚路径后再撤销旧 secret。

真正的验收证据包括:仓库和镜像中无静态密钥;凭证寿命符合策略;错误工作负载无法领取;目标 API 校验身份后仍执行资源授权;节点或工作负载被撤销后,暴露时间有明确上界。

零信任不是“用了 mTLS”这一行配置,而是每次访问都能回答主体从哪里被证明、凭证为何仍有效、当前动作为什么被允许。

面试与设计评审 ​

  • 把 secret 放进 Vault 是否就完成 NHI 治理?没有;仍需 owner、用途、最小权限、动态获取、轮换和撤销。
  • SPIFFE 怎样避免 bootstrap secret?说明本地 Workload API、平台 selectors、注册条目和短期 SVID。
  • mTLS 与零信任是什么关系?mTLS 提供连接身份,策略仍结合资源、动作和动态信号授权。

本章小结 ​

静态密钥的根本替代是“可证明运行环境 + 自动短期凭证 + 资源端授权”,而不是把秘密从代码搬到另一个盒子。零信任让这种身份成为每次访问决策的一项输入。