目标
仓库适合存放配置的“形状”,却是存放秘密的糟糕地方。SOPS 加 age 把两者拆开:文件留在 git 里、键名可读、值是密文,评审能看到结构上改了什么,而只有持有正确私钥的环境才能看到值。轮换只需原地重包数据密钥,明文永不回到工作区。
步骤要点
- 为每个环境生成 age 密钥对,只有公钥进仓库,私钥走密钥分发流程。
- sops –encrypt –age 各环境公钥 –in-place 加密 secrets.yaml,键名可读、值变密文、可 diff 可合并。
- git grep 确认工作区再无明文,本机持有 staging 私钥时可正常解密验证。
- CI 用注入的 SOPS_AGE_KEY(完整私钥文件内容)解密后部署,密钥永不入库。
- 环境密钥泄漏时跑 sops –rotate –in-place:数据密钥重包给新接收者,秘密本身不动、无需重录。
排错提示
新机器克隆后解不开是私钥没分发到位,私钥走环境分发渠道而不是仓库;CI 报 keyring 错误多半是 SOPS_AGE_KEY 没存完整文件内容(含换行);加密文件合并冲突时解密两侧、合并明文映射、重新加密即可,因为按键加密保留了结构可读性。
适用边界
git 静态加密的前提是私钥本身被严守,仓库从来不是密钥保险箱而是数据柜;SOPS 保护的是值不是键名与结构,后者有意保持可见以支持评审。
代码示例
# Encrypt for the environments that may read it
sops --encrypt --age age1stagingpub,age1prodpub \
--in-place config/secrets.yaml
# CI decrypts with an injected private key
SOPS_AGE_KEY="$KEY_FILE" sops --decrypt config/secrets.yaml