sops 解决什么问题#
sops 不是「加密钱包/保险箱」,而是「git 友好的 secrets 版本控制方案」。 核心痛点:需要版本化或 review 的秘密配置可以以密文进入 git,而明文和解密密钥应留在仓库外。
围绕这个目标,sops 提供三件事:
- 把密文当普通文件管理 —
secrets.yaml是普通 YAML,git diff、git log、PR review 都能做。 - 密钥与仓库解耦 — 密文进 git,解密密钥留在机器上,多人/多机共享仓库但各用自己的私钥。
- 加密细节标准化 —
sops edit、sops -d封装底层算法。
| 加密钱包/保险箱 | sops | |
|---|---|---|
| 核心问题 | 怎么安全存放一份秘密 | 怎么安全版本化/分发秘密 |
| 谁持有 | 一个人,一个设备 | 一群人/多台机器,共享仓库 |
| 关注点 | 加密强度 | 密钥管理、协作、审计、变更追踪 |
一句话:sops = 把 secrets 从「git 里的明文」变成「git 里的密文」,解密能力(私钥)留在机器上。
混合加密:两层结构#
sops 不是用公钥直接加密 secrets,而是混合加密:
1. 生成一把随机的对称 AES 数据密钥
2. 用 AES 密钥加密每个 value(数据层)
3. 用你的 age 公钥加密那把 AES 密钥(密钥层)这解释了 secrets.yaml 的两层:
app_env: "SOPS_CIPHERTEXT_PLACEHOLDER_NOT_VALID" # 数据层(AES)
sops:
age:
- enc: "AGE_WRAPPED_DATA_KEY_PLACEHOLDER_NOT_VALID" # 密钥层(age)
recipient: "AGE_RECIPIENT_PLACEHOLDER_NOT_VALID" # 接收者公钥数据层字段:AES256_GCM(对称加密)、data(密文)、iv(初始化向量,保证相同明文密文不同)、tag(GCM 认证标签防篡改)、type(原数据类型)。
密钥层 + 元数据:age(用 age 公钥体系)、enc(AES 密钥用你公钥加密的结果)、recipient(你的公钥)、lastmodified、mac(整个文件完整性校验)、unencrypted_suffix、version。
加密对象与格式:sops 加密的是"值/字节流",不是"格式"#
sops 加密内容,并依据所选格式决定如何解析、保存和解密。 结构化模式需要理解 YAML、JSON、dotenv 或 INI,解密输出可能经过重新序列化,不能保证原始排版逐字节保留。binary 模式把原文件视为字节流,适合需要还原任意文件内容的场景。
两种加密粒度(关键区分):
| 模式 | sops 怎么处理 | 何时用 |
|---|---|---|
| 结构化(yaml/json/dotenv/ini) | 解析文件 → 分成多个键 → 每个键一个值加密 | 想要"一个文件多个机密、可单独引用" |
| binary(万能兜底) | 整个文件当作一段字节流整体加密,不解析内部 | 任意格式文件想整体加密 |
binary 可用于任意字节内容:例如将 .conf 整体加密,再以 binary 输出解密,并用 cmp 检查还原。此处是验证方法,不代表当前已运行验证。所以"文件格式不支持"不是问题——用 binary 通吃;只有想要"一个文件拆多个键"时才用结构化格式。
age 和 ed25519 的关系#
它们是完全不同的密码学工具,但在同一个曲线家族。
- ed25519:数字签名算法(Edwards25519 曲线)。SSH、Git 做身份认证。
- age:加密工具/格式。底层用 Curve25519(X25519) 做公钥加密。
两者都源自 25519 曲线家族,但格式不同、用途不同、不能互换。ssh-to-age 能把 SSH ed25519 host key 转成 age 格式(工具按其支持的 Ed25519 密钥编码完成转换;不能把两种文件格式直接互换)——这也是 sops 能直接用 SSH host key 解密的原因。
recipient 登记制:为什么加公钥就能解密#
一对多授权模型:
sops:
age:
- enc: <AES 密钥用旧公钥加密>
recipient: AGE_RECIPIENT_PLACEHOLDER_NOT_VALID
- enc: <同一把 AES 密钥用新公钥加密>
recipient: AGE_RECIPIENT_PLACEHOLDER_NOT_VALID- AES 数据密钥只有一把,但对每个 recipient 各生成一个加密副本
- 旧机器用自己私钥解开第一个块 → 拿到 AES 密钥 → 解密数据
- 新机器解开第二个块 → 拿到同一把 AES 密钥 → 解密数据
所以「把新机器公钥加进 recipient 就能解密」——每台机器用自己私钥解开属于自己的密钥块,不需要拷贝私钥。
为什么「clone 仓库 + 加公钥」拿不到明文#
关键安全边界:
- 公钥只能加密,不能解密(单向门)
- B clone 仓库后没有你的私钥 → 解不开你已加密的数据
- B 加自己的公钥 → sops 需「已有私钥解开现有文件」才能重加密 → 没有你的私钥直接 FAILED
- B 重新加密一份新文件 → 只是 B 自己写的内容,不含你的明文
明文泄露并不只来自私钥泄露。 编辑器临时文件、日志、备份、运行时文件、进程环境、已有授权接收者或被控制的解密机器都可能暴露秘密。密文提交也会保留键名、结构和某些元数据。
相关#
- 运行时怎么用 → sops-nix 集成
- 命令行操作 → sops 使用指南
- 参考:sops 手册 | age 格式讨论
参考与延伸
根据技术笔记重新整理,示例使用通用名称。