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