cottage 是一款面向团队的 GitOps 工具,用于在 git 仓库中管理 age 加密的机密信息。
它提供了一套简单的工作流来加密/解密机密信息、管理接收者,并确保机密信息不进入仓库,同时仍可通过 VCS 轻松共享。cottage 还会为加密的机密信息生成脱敏预览,以便更好地查看,并同时支持持久化和临时解密工作流,同时确保机密信息永远不会以明文形式提交。

.gitignore,确保未加密的机密信息不进入仓库。ctg diff 显示本地修改的机密信息与已跟踪的加密对应文件之间的差异。ctg decrypt/sync 将解密的机密信息保留在磁盘上。ctg run(快捷方式 ctgx)和 ctg edit 在操作前解密机密信息,如果之前已存在于磁盘上则保留,否则在操作后自动清理。ctg encrypt --clean、ctg run --clean 和 ctg edit --clean 确保即使解密文件之前已存在,也会从磁盘上清理。ctg env 将解密的机密信息作为环境变量注入以运行命令,完全不写入磁盘。# rust: cargo-binstall/cargo
cargo binstall --locked cottage
cargo install --locked cottage
# python: pip/uv/uvx
pip install cottage
uv pip install cottage
uvx --from cottage ctg --version
# node: yarn/pnpm/npx
yarn global add @sayanarijit/cottage
pnpm add -g @sayanarijit/cottage
npx -p @sayanarijit/cottage ctg --version
也可作为 docker 镜像使用:
# Docker
docker run --rm -v $PWD:/app sayanarijit/cottage --version
# Podman
podman run --rm -v $PWD:/app quay.io/sayanarijit/cottage --version
或者从 GitHub 下载最新版本。
使用 Cottage VS Code 扩展 来安装 ctg、添加 Copilot 安全钩子、从资源管理器中加密文件,并通过编辑器工作流打开 .cott.age 文件。
从 Visual Studio Marketplace 安装,或从 vscode-plugin-cottage 本地构建并安装。
下载 VSX 文件 并在你的 Cursor 或 Eclipse IDE 中安装。其工作方式与 VS Code 扩展类似。
使用 cottage.vim 插件从 Vim 或 Neovim 中加密/解密机密信息。
以下所有集成都防止 AI 代理直接运行 ctg/ctgx,以及查看或编辑机密文件:.cottage/ 内的任何内容、任何 *.cott.* 文件(加密的 *.cott.age 二进制文件和脱敏的 *.cott.toml 预览),以及任何在磁盘上仍有 *.cott.age 对应文件的解密文件。
如果你使用 Claude Code,请将 .claude/settings.json 和 .claude/hooks/deny-secrets.py 添加到包含机密信息的仓库中,以便 Claude Code 会话安全地处理机密信息,或者安装 claude-plugin-cottage 插件。
如果你在 VS Code 中使用 GitHub Copilot,请将 .github/hooks/ctg-policy.json 和 .github/hooks/scripts/deny_ctg_command.py 添加到包含机密信息的仓库中,以便 Copilot 会话清理解密文件、阻止直接的 ctg shell 命令并阻止访问机密文件,或者安装 vscode-plugin-cottage 扩展来从 VS Code 中进行设置。
VS Code 也会加载 .claude/settings.json 中的钩子定义。如果你在同一仓库中同时保留 Claude 和 Copilot 的钩子文件,请确保不会意外运行两次相同的清理钩子。
如果你使用 Codex,请将 .codex/hooks.json 和 .codex/hooks/deny-ctg.py 添加到包含机密信息的仓库中,以便 Codex 会话安全地处理机密信息,或者安装 codex-plugin-cottage 插件。
Codex 要求本地钩子在运行前经过审查。添加文件后,在仓库中启动 Codex 并使用 /hooks 来审查并信任项目钩子。
如果你使用 Antigravity (agy),请将 .agents/hooks.json 和 .agents/scripts/deny-ctg.py 添加到包含机密信息的仓库中,以便 Antigravity 会话安全地处理机密信息,或者安装 agy-plugin-cottage 插件。
如果你使用 Cursor,请将 .cursor/hooks.json、.cursor/hooks/deny-ctg.py、.cursor/hooks/deny-read-secrets.py、.cursor/rules/deny-ctg.mdc 和 .cursorignore 添加到包含机密信息的仓库中,以便 Cursor 会话安全地处理机密信息。
Cursor 要求先启用钩子。打开 Cursor 设置 > 钩子并启用钩子,然后重启代理会话以使项目钩子生效。.cursorignore 另外将机密文件排除在 Cursor 的索引和代理的上下文之外。
初始化项目:
mkdir project && cd project
git init # 可选,cottage 与 git 配合效果更好,但并非必需
ctg init # 设置 .cottage 目录和必要文件
tree -a
# .
# ├ .cottage/ <- 由 `ctg init` 自动生成
# │ ├ identity <- 你的私钥,请妥善保管。将其移动到 `~/.config/cottage/identity` 以全局使用,或将其替换为指向你现有私钥之一的软链接。
# │ └ recipients/ <- 这是你的团队存放所有接收者公钥的地方。
# │ └ sayanarijit <- 你的公钥。提交它。要使用现有的公钥,只需将该密钥复制(不要软链接)到这里。
# ├ .git/...
# ├ .gitattributes <- 添加了 `*.cott.age binary linguist-generated filter=cottage-encrypted -diff` 以避免污染 git diff
# └ .gitignore <- 出于显而易见的原因添加了 `/.cottage/identity`
# 你可以随时运行 `ctg clean --all` 来清理 cottage 曾经做过的所有事情。
创建或编辑机密信息:
# `ctg edit` 在 $EDITOR 中打开前解密文件,并在保存时重新加密。
# 如果在运行 `ctg edit` 之前解密文件不在磁盘上,则之后会被清理。
# 如果之前已存在,则会保留在磁盘上。
ctg edit secret.yml
# 使用 `--clean` 与 `ctg edit` 或 `ctg encrypt` 一起使用,以确保即使解密文件之前存在也会被删除
ctg edit secret.yml --clean # 在 $EDITOR 中打开,保存时加密,并清理
ctg encrypt secret.yml --clean # 加密 secret.yml 并清理
# encrypt secret.yml
# into secret.yml.cott.age
# edit secret.yml.cott.toml
# edit .gitignore
# delete secret.yml
使用解密的机密信息运行命令:
cat secret.yml
# cat: secret.yml: No such file or directory
# `ctg run`(或快捷方式 `ctgx`)在运行命令前解密机密信息。
# 如果解密文件之前不在磁盘上,则命令结束后会自动清理。
# 如果之前已存在,则会保留在磁盘上。
ctg run -- kubectl apply -f secret.yml # 将 secret.yml.cott.age 解密为 secret.yml 并运行命令
ctg run -- kubectl apply -f secret.yml.cott.age # 也会将路径参数替换为解密后的文件路径
ctg run -- kubectl apply -f . # 解密 . 中的所有 .cott.age 文件并运行命令
ctg run -- ./deploy.sh # 解密仓库中的所有 .cott.age 文件并运行命令
cat secret.yml
# cat: secret.yml: No such file or directory
# 使用 `--clean` 确保即使解密文件之前存在也会被清理
ctg run --clean ./deploy.sh
或者使用快捷方式:
ctgx -- ./deploy.sh
ctgx --clean -- ./deploy.sh
使用注入为环境变量的机密信息运行命令,完全不写入磁盘:
ctg env -- ./deploy.sh # 从 .env.cott.age(默认)导出机密信息而不写入磁盘,然后运行 deploy.sh
ctg env -F .env.prod.cott.age -- ./deploy.sh # 从 .env.prod.cott.age 而不是 .env.cott.age 导出
ctg env -F secrets.json.cott.age -- printenv COTTAGE_SECRET # 也支持非 dotenv 文件。
要与团队成员共享机密信息,只需推送到 git 仓库即可。
git add .
git commit -m "Add secret.yml"
git push origin main
请你的队友将他们的公钥添加到 .cottage/recipients 并推送更改。然后你可以拉取并为他们重新加密机密信息。
git pull origin main
ctg decrypt --skip-verify-recipients # 解密缺失的机密信息以便重新加密
ctg encrypt # 重新加密所有机密信息
# encrypt secret.yml
# into secret.yml.cott.age
# edit secret.yml.cott.toml
ctg clean # 可选
# delete secret.yml
# 审查更改,提交并推送
git add .
git commit -m "Add new recipient to secrets"
git push origin main
现在你的队友可以拉取最新更改并自行解密机密信息。
你可以使用 prek 或 pre-commit 来设置 git 钩子,在提交前自动检查/加密机密信息,并在检出后解密。
参见 此处的示例 prek 配置。
添加 prek.toml 文件后,运行:
prek install
prek install --hook-type post-checkout
prek install --hook-type post-merge
prek install --hook-type post-rewrite
在元数据文件中,你可以标注该机密信息应为哪些接收者加密。这允许你为不同环境(例如暂存环境与生产环境)设置不同的机密信息,并且只针对相关的接收者进行加密。
# secret.yml.cott.toml
[secret]
allow = ["sayanarijit"] # 仅为 sayanarijit 加密
# secret.yml.cott.toml
[secret]
deny = ["sayanarijit"] # 为除 sayanarijit 之外的所有人加密
# secret.yml.cott.toml
[secret]
allow = ["env/staging/*"] # 支持 glob 模式,仅为 env/staging 中的接收者加密
deny = ["env/staging/badservice"] # 为 env/staging 中除 badservice 之外的所有人加密
拒绝规则优先于允许规则。
更多详情请参见 元数据规范。
你可以在 CI 中运行 ctg verify 来验证加密的机密信息和接收者列表是否与元数据规则匹配,以防止篡改。
# .github/workflows/cottage-verify.yml
name: Cottage Verify
on: [push, pull_request]
permissions:
contents: read
jobs:
verify-secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify secrets
run: docker run --rm -v "${{ github.workspace }}:/app" ghcr.io/sayanarijit/cottage verify
使用 cottage,你可以与任何具有 API 的提供商同步机密信息,而不仅仅是 git。
为此,在项目根目录创建一个名为 cottage.toml 的文件并配置上游设置。
参见 此处的示例 cottage.toml 和 此处的机密信息特定上游配置。
参见 此处的示例插件实现。
工作流与 git 类似,但不是运行 git pull 和 git push,而是运行 ctg pull 和 ctg push 来与配置的上游同步机密信息。
示例:
# 将最新更改拉取到本地加密的机密信息中
# 类似于 `git pull origin`
ctg pull myvault
# 与本地解密的机密信息比较差异
ctg diff
# 将本地解密的机密信息与本地加密的机密信息同步
ctg sync
# 将本地加密的机密信息的更改推送到上游
# 类似于 `git push origin main`
ctg push myvault
更多详情请参见 上游配置规范。
Cottage 支持各种插件提供商来同步你的机密信息。现成的插件脚本可在 examples/plugins 目录中找到:
使用 Cottage Sync 在你的设备之间同步机密信息,无需 CLI 即可浏览。
参见 examples 目录获取更多使用示例。
# 使用 -v、-vv 或 -vvv 查看调试日志
ctg run -vvv -- ./deploy.sh
age 使用一种现代、简单的算法,针对安全的文件加密进行了优化,专注于易用性和最小的攻击面。它还支持 SSH RSA 和 Ed25519 密钥,但建议为不同的用途和范围使用不同的密钥。
虽然 SOPS 和 cottage 有许多重叠的功能,但 cottage 具有以下优势:
cottage 借鉴了 dotenvx 的 ctg env API。
ctg cleanctg init 将任何目录变成机密信息存储库。git pull/diff/push 一样使用 ctg pull/diff/push。