16. Secrets 管理:CI/CD 中的密钥、权限与最小授权
安全是默认:密钥永不进代码,权限默认最小。
本章目标
把密钥从“散落的玻璃渣”变成“可管理资产”:最小权限、短期凭证、可审计、可轮换。
你会掌握
Secrets 分类与泄露路径、CI/CD 权限模型、OIDC 换取短期凭证、轮换与审计策略、事故响应与门禁联动。
真实收益
即使仓库被误提交、Runner 被入侵、日志被泄露,你的系统也能把损失控制在最小范围,并能快速追溯与止血。
密钥泄露的可怕之处不在于“会不会发生”,而在于“发生一次会毁掉什么”。
成熟的 DevOps 体系默认假设:密钥终有一天会泄露。
所以我们要做的不是祈祷,而是设计:最小权限、短期凭证、轮换与审计、可快速止血。
成熟的 DevOps 体系默认假设:密钥终有一天会泄露。
所以我们要做的不是祈祷,而是设计:最小权限、短期凭证、轮换与审计、可快速止血。
1) Secrets 到底是什么?先把范围划清楚
在 CI/CD 里,secrets 通常包含:
- 身份凭证:云账号、API token、SSH key、数据库密码
- 加密材料:证书私钥、KMS key 引用
- 敏感配置:第三方服务密钥、Webhook secrets
注意:“配置”不等于“密钥”。配置可以公开版本化;密钥必须最小暴露、可轮换、可审计。
2) 泄露路径:密钥通常是怎么漏出去的?
- 代码库:误提交到 git(最常见)
- CI 日志:echo/stacktrace 把 token 打出来
- 构建产物:镜像层里写死了密钥
- 权限过大:一个 token 拿到整个云账号权限
- 长生命周期凭证:永不过期、从不轮换
两条铁律:
1) 密钥永不进仓库(包括历史)。
2) 密钥永不进日志(包括失败栈)。
1) 密钥永不进仓库(包括历史)。
2) 密钥永不进日志(包括失败栈)。
3) 最小权限(Least Privilege):不是口号,是工程策略
最小权限要解决的是“爆炸半径”(blast radius)。把权限拆小,你就能把一次泄露的损失限制在:
- 某个环境(例如 staging)
- 某个资源(例如一个 bucket)
- 某个动作(只读 vs 可写 vs 可删)
- 某段时间(短期凭证)
图 1:密钥生命周期与爆炸半径(动态)
成熟策略不是“藏得更深”,而是“权限更小 + 时间更短 + 可追溯更强”。
4) OIDC 与短期凭证:用“临时通行证”替代“永久钥匙”
传统做法是在 CI 里放一个长生命周期云密钥:一旦泄露,后果严重。
更现代的做法是:CI 平台通过 OIDC 向云厂商交换短期凭证,有效期通常只有几分钟到一小时。
图 2:OIDC 换取短期凭证链路(动态)
CI 不再保管长期密钥,而是凭“身份声明”换取临时权限,天然更安全、更可审计。
OIDC 的关键收益:密钥不再“长期存在”,攻击窗口大幅缩小;并且可以把权限绑定到 repo/分支/环境,形成更细粒度的最小授权。
5) 轮换与审计:把“不可控”变成“可运营”
密钥治理最终是运营问题:你要能回答两个问题:
- 这个密钥谁在用?用来访问什么?
- 如果现在泄露了,我多久能止血?
建议的基本制度:
- 定期轮换:按风险等级设周期(高风险更短)
- 强制过期:临时凭证默认过期,减少长期悬挂
- 审计日志:访问记录可追溯(谁/何时/做了什么)
图 3:最小权限与边界模型(动态)
权限要按环境/资源/动作/时间切开边界:边界越清晰,爆炸半径越小。
6) 事故响应:密钥泄露时你该怎么做?
把响应过程写成 SOP,会比“临场发挥”可靠得多。典型步骤:
- 止血:立即吊销/禁用相关凭证(或撤销角色信任关系)。
- 定位:查审计日志:发生了什么调用?是否有数据访问/删除?
- 轮换:替换密钥、更新配置、发布新版本。
- 补护栏:加 secret scanning、加门禁、减少权限、缩短有效期。
本章小结:把密钥当作“可运营系统”
- 默认假设密钥会泄露:靠最小权限、短期凭证与审计把损失控制住。
- OIDC 是 CI/CD 的关键升级:用临时通行证替代永久钥匙。
- 轮换与豁免同样重要:能止血、能追溯、能持续收敛。