13.4 密钥与凭证管理

一句话

密钥管理的目标不是 “把密码藏好”,而是让凭证短期、可轮换、可审计、可吊销:长期密钥一旦泄露就是永久后门,短期凭证 + 最小权限才把 “泄露的影响面” 压到可接受。

生命周期五步

阶段 要回答 工程手段
生成 谁生成、强度多少 KMS/HSM 生成,不落盘到代码
分发 怎么到达使用方 运行时注入(Secret/CSI)、STS 短期凭证
使用 谁能读、能做什么 最小权限、按工作负载隔离
轮换 多久换、怎么不中断 自动轮换 + 双密钥过渡
吊销与审计 泄露后多久失效、谁用过 一键吊销、访问日志留存

三种方案,按成熟度排

方案 做法 适合 代价
平台 Secret(K8s/云 Secrets Manager) 静态密钥,运行时挂载 起步阶段 轮换靠人;静态密钥仍是长期凭证
集中密钥系统(Vault 类) 动态凭证、租约、审计 中大型 多一个高可用组件
无静态密钥(STS/OIDC 联邦) 工作负载换取短期 token 云上生产 需要身份平台与权限模型

信封加密是绕不开的模式:数据用 DEK 加密,DEK 用 KMS 的 KEK 加密后随数据存放——这样大量数据加密不必每次调 KMS,KEK 泄露风险也集中在 KMS。

落到数字:轮换与泄露窗口

项 常用值 说明
静态密钥有效期 90 天(合规常见上限) 越长泄露窗口越大
STS 临时凭证 15 分钟–12 小时 按任务时长取最小值
双密钥过渡期 ≥ 2× 缓存 TTL 缓存仍持有旧凭证的时间
审计日志留存 ≥ 180 天 与等保/行业要求对齐
aws sts get-caller-identity                    # 确认当前身份(短期凭证会有 session)
vault token lookup 2>/dev/null || echo "无 Vault 环境"
openssl rand -base64 32                        # 生成高熵密钥(不要用密码派生)

实测:单密钥切换 vs 双密钥过渡

2 万次客户端调用、凭证缓存 TTL 60 秒(本机模拟轮换瞬间):

方式 轮换瞬间失败 失败率
单密钥切换 20,000 100%
双密钥过渡 0 0%

单密钥切换的失败率必然是 100%:所有缓存了旧凭证的客户端在切换瞬间全部鉴权失败。双密钥过渡让新旧并存,旧凭证按 TTL 自然过期,失败为 0——这就是 “轮换必须双密钥” 的量化理由。

旧密钥下线时间 ≥ 最大缓存 TTL + 时钟/网络余量
(本例 TTL 60s → 至少保留 5–10 分钟,保守按 2×TTL)

反模式

反模式 后果
密钥硬编码进代码/镜像 一旦推到仓库或镜像,等于公开;docker history 可查(见 6.4 Dockerfile 与构建优化)
长期 AK 发给所有人 无法定位泄露源,吊销影响全部
共享一套密钥给所有环境 测试环境泄露 = 生产沦陷
轮换不做双密钥过渡 轮换瞬间全站鉴权失败
只加密不审计 泄露后无法回答 “谁在什么时候用过”
密钥与配置放同一仓库 一次泄露同时暴露配置与凭证

三条铁律

🔑 优先短期凭证:能换 token 就不要发长期密钥。

🔑 轮换要能在线完成:双密钥并存 + 灰度切换。

🔑 审计日志与密钥同等级保护;没有审计就无法追责与止损。

自检

Q1 为什么 “把密钥放进 K8s Secret” 不算完整的密钥管理?

▸ 答案:因为 Secret 默认只是 base64 + RBAC,仍是静态长期凭证:不会自动轮换、泄露后长期有效、etcd 未加密时可直接读(见 7.4 配置与密钥 (ConfigMap / Secret))。完整方案要补 “加密存储 + 自动轮换 + 审计”,或改用 STS/动态凭证。

Q2 信封加密解决什么问题?

▸ 答案:解决 “大量数据加密时不必每次调用 KMS”:每条数据用本地生成的 DEK 加密,DEK 用 KEK(存在 KMS)加密后随数据保存。收益是性能与密钥分层(KEK 极少使用、泄露面小),代价是多一层密钥管理逻辑。

Q3 密钥轮换如何做到 “用户无感”?

▸ 答案:双密钥并存 + 版本号:新密钥生效后,服务端同时接受旧密钥一段时间(校验时按 key id 选),数据逐步用新密钥重加密,最后停用旧密钥。没有 key id 的体系无法平滑轮换——这是设计时就要留的字段。

Q4 团队用一套 AK 跑所有服务,最大的风险是什么?

▸ 答案:影响面与不可追溯:任何一处泄露都等于全部权限泄露,且日志里只能看到一个身份,无法判断是哪台机器/哪个服务在用。修法是按工作负载发独立凭证(或直接上 STS),做到 “吊销一个不影响其他”。

Q6 为什么 “90 天轮换” 必须配 “双密钥过渡”,否则会出事故?

▸ 答案:因为下游可能缓存了旧凭证(连接池、SDK、sidecar)。单密钥切换瞬间,仍持旧凭证的客户端立即全部鉴权失败。双密钥过渡让 “新旧并行 → 逐步淘汰”,把切换窗口从 “一秒” 拉长到 “一个缓存周期”。

Q5 为什么单密钥轮换 “必然” 100% 失败?

▸ 答案:因为凭证不是 “每次请求都重新获取”,而是缓存在客户端/SDK/连接池里:切换瞬间,所有持有旧凭证的调用方都还没刷新,服务端却已只认新凭证。失败率等于 “缓存旧凭证的调用占比”,在轮换瞬间接近 100%。

Q6 双密钥过渡什么时候可以撤掉旧密钥?

▸ 答案:旧密钥的下线时间 ≥ 最大缓存 TTL + 余量(时钟漂移、网络重试、发布窗口)。经验值是 2×TTL;撤之前看监控:旧 key id 的使用量应衰减到 0 并持续一段时间,再下线。

Q7 轮换期间的审计日志该看什么?

▸ 答案:看三条曲线:新旧 key id 的使用比例(是否在按预期迁移)、鉴权失败率(是否出现异常尖峰)、异常来源分布(是否有未登记的系统还在用旧密钥)。这三条能提前发现 “漏刷新的客户端”,避免在旧密钥下线的瞬间才爆。

关联