安全¶
vault 装的是"丢一个毁一片"的东西。这页讲清楚安全模型,重点在两件事:
- 加密怎么做的 —— data/ 怎么保证即使仓库上云也不泄密
- 密钥怎么管 —— 丢了就全毁,必须备份
加密模型:git-crypt¶
data/ 目录下所有文件在 commit 时自动加密,在本地 checkout 时自动解密。你平时操作感知不到,但推上 GitHub 的是加密后的密文。
加密规则¶
来自仓库根目录 .gitattributes:
凡是匹配这两条的文件,git 都走 git-crypt 过滤器。其它文件(src/ / docs/ / schemas/ / pyproject.toml / ...)不加密。
验证已加密¶
# 远端看到的是密文(GITCRYPT 头部 + 乱码)
git show HEAD:data/credentials/aliyun-main.json | head -1
# 本地看到的是明文
cat data/credentials/aliyun-main.json | head -1
CI 能看到明文吗?¶
不能。GitHub Actions 拉代码时只拿到加密版。跑 vault check / pytest integration 这些需要真实数据的测试会失败,所以我们在 CI 里设 VAULT_SKIP_INTEGRATION=1 跳过它们。
CI 只做代码层面校验(ruff、schema 合法性、unit 测试、mkdocs build)。真实数据的验证留本地 pre-commit 做。
密钥管理:.git-crypt/keys/default¶
这一个文件就是整个 vault 的命门。
路径¶
这个文件不在 git 里(.git/ 本身就不跟踪),是初始化 git-crypt 时本地生成的对称密钥。
丢了会怎样¶
- 本地其它用户(新机器、新同事)永远没法解密
data/—— 仓库里看到的永远是GITCRYPT乱码 - 哪怕你还记得每个平台的密码,你也读不了 vault 里存的那些
- 唯一的自救:挨个平台手工轮换、手工重建 vault
结论:丢 key = vault 数据从此锁死。
必须做的备份¶
至少 3 备份原则:
| 位置 | 怎么做 |
|---|---|
| 本地 macOS | 原始文件已在(~/vault/.git-crypt/keys/default) |
| iCloud / Dropbox 加密目录 | 手动 cp .git-crypt/keys/default ~/Library/Mobile\ Documents/com~apple~CloudDocs/secure/git-crypt-vault.key |
| 外部介质(U 盘 / 纸质打印 base64) | 离线备份,长期存放 |
建议定期验证备份能解锁:
# 新目录模拟恢复
cd /tmp && git clone git@github.com:yarnovo/vault.git vault-restore
cd vault-restore
git-crypt unlock /path/to/backup/default # 用备份的 key 解锁
cat data/credentials/aliyun-main.json # 能看到明文就算成功
新机器怎么 unlock¶
git clone git@github.com:yarnovo/vault.git
cd vault
git-crypt unlock /path/to/your/backup.key
# 之后 data/ 自动可读
密钥本身能不能上云?¶
绝对不要。git-crypt key 上云 = 加密白做。
最小权限原则¶
当 vault 里的凭证要被外部系统使用时(比如 GitHub Actions 跑部署),不要直接把 main/root token 给它。另建一个权限最小的专用 token。
现成案例:cloudflare-pages-deploy
cloudflare-main kind=api_token (有 DNS / Zone / Workers 等全套权限)
cloudflare-pages-deploy kind=api_token (只有 Cloudflare Pages:Edit 权限)
← 这个才给 GitHub Actions
好处:
- pages-deploy token 泄漏,别人只能搞 Pages,不能删你域名 DNS 记录
- 轮换独立,不影响另一个
- vault credential show cloudflare-pages-deploy 看到 metadata 里记录了它的 consumers(GitHub Actions secret 名字),一眼知道在哪用
设计上所有"外部可见"的 token 都应走这个模式,在 credential.metadata 里记:
- scopes: 实际授予的权限列表
- consumers: 谁在用(哪个项目的哪个 secret)
- created_at: 何时创建
消费方项目的本地 secrets¶
vault install 在消费方项目生成两个文件:
权限约定¶
CLI 自动:
- .vault/ 目录 chmod 700
- .vault/secrets.json chmod 600
- .env chmod 600
这些是本地文件权限,防止同机器其他用户读到。
gitignore¶
vault install 自动往项目 .gitignore 追加:
这两行绝不能漏,漏了直接 push 会把明文上 GitHub。
删除¶
消费方项目不用了:
直接删,没历史包袱(vault 里的原 credential 还在)。
威胁模型清单¶
| 威胁 | 对抗 | 残余风险 |
|---|---|---|
| GitHub 仓库被看到 | git-crypt 加密 data/ |
低:攻击者看到密文 |
| 本地 mac 被盗 | FileVault + git-crypt key 不在仓库里 | 中:若 mac 未锁 + key 文件可读 |
| token 泄漏 | 最小权限原则 + 按 consumer 拆 credential | 中:泄漏到期前可能被滥用 |
| CI log 泄漏 | CI 不接触明文 data/;GitHub Secret 自动脱敏 | 低 |
| 消费方 secrets.json 被别的进程读 | chmod 600 + gitignore | 中:同机器其他 root 进程可读 |
| git-crypt key 丢失 | 3-重备份 | 高:数据永久锁死 |
最大的风险是 key 丢失,远大于 key 泄漏。
轮换¶
凭证轮换(日常)¶
# 比如 aliyun-main AK 轮换
vault credential edit aliyun-main # 打开 $EDITOR 改 values.access_key_secret
# 所有引用这把 AK 的消费方项目
cd ~/xiangqin && vault sync # 重拉最新值
git-crypt key 轮换(罕见 —— 只在疑似 key 泄漏时)¶
git-crypt 本身不支持原地换 key。你只能:
1. 导出所有明文 data/
2. 删仓库,重新 git-crypt init 生成新 key
3. 重新 add + commit + push
4. 所有备份 + 新机器用新 key
大动作,非必要不做。
速查¶
| 事件 | 做什么 |
|---|---|
| 新 mac 第一次用 vault | git clone + git-crypt unlock <备份 key> |
| GitHub 仓库被意外 public | 立刻轮换所有 credential + 考虑 revoke git-crypt key |
| Mac 丢了 | 确认 FileVault 开了 → 轮换所有 credential(保险) → 新 mac 用备份 key 恢复 |
发现 .env 被 commit 了 |
git rm --cached .env + git commit + 立刻轮换该 env 里的所有值(已进 git history) |
| 忘了 mac 密码 | key 还在,但进不去 → 找苹果 recovery |
| 忘了 key 放哪 | 挨个备份位置翻(macOS mdfind -name git-crypt-vault.key);都没就进入重建流程 |