密钥、密码与敏感配置管理
凌晨的告警显示数据库认证持续失败,值班人员很快发现密码刚刚完成轮换。问题却没有止于“新密码没生效”:一个服务从 CI secret 取值,另一个仍读取节点上的 .env,定时任务把密码复制进了命令行参数,某位同事的密码库里还保留着旧副本。新旧凭据同时存在,没人知道哪些进程已经切换,也没人敢立即撤销旧值。密码本身没有失控,失控的是它的副本、身份和生命周期。
Secret 管理解决的不是“把字符串藏起来”,而是让敏感值始终有权威来源,只有经过认证和授权的工作负载能够在需要的时间取得它,使用过程不把它泄露到日志、构建产物或调试上下文,轮换后旧值能够确定失效,离职和系统退出时所有旁路副本都能被找到并清理。
从 secret 的使用方式选择入口
| 现场信号 | 工程入口 | 成功证据 |
|---|---|---|
| 服务需要短期数据库账号、云凭据、集中 policy、lease 和撤销能力 | Vault | 身份只能读取批准路径,动态凭据到期或撤销后确定失效 |
| 配置必须进入 Git,但敏感字段不能明文保存 | SOPS、age 与 GPG | 仓库只有密文,授权身份可解密,接收者变更和轮换有可审查 diff |
| 人员需要共享网站账号、恢复码、SSH 入口或少量受控自动化凭据 | 1Password、Bitwarden 与 KeePass | 共享对象有 owner 与权限,离职回收覆盖会话、设备、导出和离线副本 |
| 项目需要可运行的环境模板、本机覆盖和 CI 注入约定 | env 文件与敏感配置模板 | 新人能从模板启动,真实值不进入 Git、镜像层、日志和普通 artifact |
四种对象承担不同责任
动态 secret 平台把认证身份映射到 policy,再由 secret engine 返回静态值或按需生成带租约的短期凭据。它适合运行时访问和集中撤销,但引入服务可用性、seal、存储、审计和灾难恢复责任。
加密配置文件把密文与普通配置一起版本化。SOPS 生成数据密钥加密值,再用 age、GPG 或 KMS 等 recipient 包装数据密钥。Git 能审查结构和密文变化,却不能在没有授权 identity 的情况下得到明文。它适合部署前或启动时解密,不会自动提供动态租约和每次读取审计。
团队密码库围绕人员、共享 vault、item、设备和恢复流程组织访问。它擅长交互式使用与有限自动化,不应因为提供 CLI 就直接承担大规模工作负载凭据平台。离线客户端和导出能力带来可用性,也带来难以远程销毁的副本。
.env.example 是配置契约,不是 secret 存储。真实 .env 只是本机或某个运行入口的注入载体,无法提供集中轮换、撤销和审计。CI secret、Compose secret、Kubernetes Secret 与外部 secret 控制器又有各自的落盘、可见性和权限边界,不能因为最终都变成字符串就视为等价。
Secret 从产生到撤销怎样流动
这条链中的每一步都可能产生副本。签发接口会返回一次明文,CI runner 可能把它写入临时文件,应用可能把配置对象序列化到诊断日志,容器平台可能把环境变量暴露给 inspect,崩溃转储和 APM 标签也可能保留内存中的值。治理不能只检查 Git;需要同时检查产生端、传输端、运行时、观测系统、备份和人工协作工具。
身份比 secret 字符串更重要
长期共享密码把“谁在使用”压缩成同一个值,权限、审计和撤销都只能整体进行。更可靠的设计先区分人员身份、服务身份、构建身份和紧急身份,再让它们取得不同路径、环境、有效期和操作能力。自动化优先使用受约束的工作负载身份交换短期凭据;个人 CLI 登录不能悄悄成为生产服务的长期依赖。
最小权限要在真实读取结果上验证。路径命名、vault 名称或 collection 名称只是组织方式,不天然形成访问控制。正向实验必须证明批准身份能读到目标合成 secret;反向实验还要证明它不能列举相邻路径、读取其他环境、导出整个库、延长超出 policy 的租约或绕过审计入口。
轮换不是生成一个新值
完整轮换至少经历:签发新值、让消费者同时接受或分批切换、验证新链路、停止旧值被继续分发、撤销旧值、观察失败与重试、清理缓存和离线副本、最终证明旧值失效。数据库、第三方 API 和加密密钥不一定支持双值窗口;无法并行时,要设计可回滚的停机或代理切换,而不是在生产窗口临时决定。
加密文件的 recipient 变更也不是自动撤销。离职成员如果保存了旧 Git 提交和旧私钥,仍能解密历史密文;要根据数据敏感度决定是否重新生成数据密钥、轮换底层 secret、缩短 Git 历史访问、处理备份并更新审计结论。撤销未来访问与收回已经复制的明文是两件事。
开发体验不能靠降低安全边界换取
安全工具如果让本地启动需要十几次手工复制,开发者最终会建立旁路。团队模板应提供统一命令:检查所需工具和身份,验证 secret 名称但不回显值,按需取得短期凭据,启动目标进程,退出时清理临时文件和会话。故障信息要说清是“身份无效、路径未授权、secret 缺失、版本不兼容还是后端不可用”,不能把所有失败都包装成“请检查环境变量”。
同时要给无网络、平台故障和紧急恢复设计有限路径。离线缓存必须有加密、有效期、设备边界和撤销后的处置;break-glass 凭据要封存、双人启用、短时有效、全程审计并在使用后轮换。为了可用性建立的副本,不能变成永久绕过权威平台的第二套系统。
团队运行底线
每个 secret 都有 owner、用途、环境、消费者、权威存储、有效期、轮换方式、撤销入口和退出责任。真实值不进入源码、模板、聊天、工单、截图、普通日志、构建参数、镜像层、测试数据或 AI 上下文。人员、服务、CI 与紧急身份分离;生产自动化不依赖个人长期 token。
正向读取和负向拒绝同时验证,日志只记录主体、路径、版本、结果和关联 ID,不记录 secret 值。轮换包含消费者切换、旧值撤销和旁路副本清理,不能以“平台里已经生成新值”作为完成标准。加密文件、密码库、env 载体和动态 secret 平台按对象特性组合,资源所有权和解密责任保持唯一。
退出时同时处理账号、设备、会话、recipient、恢复密钥、导出、离线缓存、备份、CI 变量和运行时残留。
当团队能在不查看真实 secret 的前提下,证明谁能取得什么、值如何进入进程、轮换到哪一步、旧值为何已经失效,以及所有副本由谁清理,敏感配置才真正成为可维护的工程资产。
