跳到主要内容
版本:1.8.x

在 AI Agent 参与开发时保护环境密钥

Claude Code、Codex 等 AI Agent 参与开发后,密钥安全不再只是“不要提交 .env”这么简单。Agent 可能能读取工作区文件、运行命令、查看命令输出;如果把长期有效的明文 secret 放在项目里,它们很容易被复制到日志、补丁、上下文或远端服务中。

Shine 的 env secret sealenv runage 后端用于降低这种扩散风险:把仓库中的 secret 保存为密文,只在需要运行命令时解密并注入子进程。但它们不是沙箱,也不能替代系统权限隔离。使用前应先明确密钥身份文件、硬件授权和 Agent 权限之间的边界。

Shine env 保护什么

shine env secret seal 把 workspace 环境文件中的待处理 secret 封存到加密 payload 中。封存后,团队仓库里保留的是密文,不再是明文 token、密码或 API key。

shine env secret seal

shine env run 在启动目标命令前合并环境文件、解密 secret,并只把结果提供给这个子进程:

shine env run --mode development -- bun run build

这种方式主要减少三类风险:

  • 明文 secret 长期留在项目文件中。
  • 开发者为了运行任务,把 secret 导出到整个 shell 会话。
  • AI Agent 修改代码时顺手读到、复制或提交 .env 明文。

但只要某个 Agent 被允许运行会读取环境变量的命令,它仍可能看到目标命令可见的 secret。env run 的安全边界是“按需注入”,不是“让不可信命令无法读取变量”。

偶尔执行一次需要凭据的操作时,建议由用户在可信终端通过单次 env run --with 注入。若某个 CLI 每次调用都需要同一个固定凭据变量,则可以安装透明命令代理,继续使用原来的调用方式:

shine env proxy install gh --with GH_TOKEN
gh pr list

如果 Agent 获准运行 gh,它仍然可以使用注入的 token,也能查看命令暴露的信息。透明代理 减少的是持久明文和整个 Shell 会话范围的导出,并不会让目标命令变成可信程序。设置方式、 启停语义和 Cargo 示例见选择单次注入还是透明代理

age identity 是解密能力

使用 age 后端时,age_recipients = ["age1..."] 表示密文要加密给谁。recipient 类似公钥地址:个人默认值可写入 ~/.shine/config.toml,项目团队共享的名单应写入 shine.workspace.toml[env.encryption],后者可以提交到仓库。

secret_backend = "age"
age_recipients = ["age1se1qexample...", "age1qteammate..."]
age_identity = "~/.shine/age/identity.txt"

~/.shine/age/identity.txt 则是解密 identity,等同于私钥身份,不能提交、不能共享,也不应放进 Agent 可随意读取的工作区。

shine env secret identity init
shine env secret identity list

Shine 在 Unix/macOS 上会把自己生成的 identity 文件权限设置为 0600,也就是仅当前用户可读写。这可以避免其他本机用户直接读取 identity 文件。

这个权限限制仍然挡不住已经以当前用户身份运行、并被授权读取该路径的 Agent、脚本或进程。普通 age identity 保护的是仓库和传输中的密文,不是完整保护本机运行环境。

Touch ID 改善什么

macOS 上可以生成 Secure Enclave / Touch ID identity:

shine env secret identity init --touch-id

这种身份由 age-plugin-se 生成。解密时需要本机 Secure Enclave,并触发 Touch ID 或系统 PIN 授权。即使 identity 文件被复制到另一台机器,通常也不能直接解密。

它带来的主要改进是:

  • identity 不容易被复制后离线滥用。
  • 解密需要用户在本机授权。
  • Agent 即使能读到 identity 文件,也不能仅靠文件在别处解密。

它不是绝对隔离。若 Agent 能在本机运行解密命令,仍可能触发系统授权提示。看到意外的 Touch ID/PIN 提示时,应取消授权并检查刚才运行的命令。

Windows 成员如何协作

Windows 成员可以使用普通 age identity 参与多 recipient 协作:

shine env secret identity init
shine env secret identity list

把输出中的 age1... recipient 加入 age_recipients 后,同一份密文可以同时加密给 macOS Touch ID recipient 和 Windows 普通 age recipient。

Windows 笔记本的指纹、Windows Hello、TPM 理论上可以通过 age plugin、Windows CNG/NCrypt 等机制实现类似体验。但目前没有像 macOS age-plugin-se 那样成熟通用的 age 社区方案,Shine 不把它写成当前稳定能力。

高安全 Windows 用户建议使用 YubiKey/PIV 或 GPG + YubiKey。普通团队开发协作可以使用普通 age identity,但要保护好 identity 文件和用户目录权限。

如何选择密钥后端

可以按下面的粗略顺序理解安全强度:

  1. GPG + YubiKey / 硬件智能卡
  2. age + Secure Enclave / Touch ID
  3. 普通 age identity 文件
  4. 明文 secret

age + Touch ID 通常比 GPG + YubiKey 更顺手,适合团队开发和预发环境。生产高价值 secret、长期凭据或需要强硬件隔离的场景,仍建议使用 GPG + YubiKey 或组织认可的硬件密钥方案。

给 AI Agent 的权限建议

把 Agent 当作一个有能力的本机协作者,而不是一个天然可信的安全边界。为它准备权限时,优先遵守这些规则:

  • 不把 ~/.shine/age/identity.txt、GPG 私钥、云厂商 credential 文件加入工作区。
  • 不让 Agent 长时间运行带有高权限 secret 的交互式 shell。
  • 需要 secret 时,优先让 Agent 修改代码,由用户在可信终端中执行 shine env run
  • 对低风险开发任务使用普通 age identity;对高敏感任务使用 Touch ID 或 YubiKey。
  • 看到非预期的 Touch ID、PIN、YubiKey 触摸提示时取消授权。

如果 identity 文件泄露、设备不再可信,或成员离开团队,仅从 age_recipients 删除 recipient 不会撤销它对历史密文的访问。需要重新封存或重新加密,并在必要时轮换上游服务中的真实 token。

shine env secret seal

不要提交含有尚未封存字符串的环境文件。个人覆盖文件应加入 .gitignore,团队共享文件中只保留已封存的密文。