别再把 API Key 塞满 .env:5 步接入 Hermes v0.19 新增的外部密钥保险箱

你的 ~/.hermes/.env 文件里躺着多少条 API key?OpenAI、Anthropic、GitHub、Telegram、Discord、Cloudflare、AWS…… 每次新增一个服务,你就复制一行 SOME_KEY=sk-... 进去。提交代码时战战兢兢地检查 .gitignore,换电脑时靠微信/Slack 把文件传给自己,CI/CD 里又得再塞一遍。更麻烦的是,团队里每个人本地都有一份副本,哪份是最新的、谁改过、有没有泄露,根本无从追溯。
Hermes Agent v0.19.0 把这个痛点变成了一个可插拔接口:SecretSource。它让 Hermes 在启动时直接从外部密钥保险箱读取 API key,首批支持 Bitwarden Secrets Manager 和 1Password。你只需在 .env 里放一个启动用的 bootstrap token,其余 key 全部交给 vault 管理。API key 终于不用塞满 .env 了。
本文给出一个可落地的 5 步迁移方案。你不需要一次性重构整个配置,而是可以逐步把高风险 key 搬出去,同时保留回滚能力。
想先了解 v0.19.0 的全部更新,可以参考我们的 v0.19.0 发布说明 和 Skill 连招指南。
为什么 .env 不是长期答案
.env 在原型阶段很方便,但当 Hermes 需要连接十几个工具和服务时,它会暴露出三个结构性问题:
- 扩散风险:每复制一份
.env到另一台机器、容器或 CI 环境,就多一个泄露面。GitHub 每年都会扫描到数百万个误提交的秘密。 - 缺少审计:
.env不会告诉你谁在什么时候改了哪个 key。一个 key 被换掉了,其他同事可能直到服务报错才发现。 - 轮换痛苦:quarterly token rotation 意味着你要同时改 N 个文件、N 个环境变量注入点,还要祈祷没有遗漏。
外部密钥保险箱解决的不是“把明文藏起来”,而是把 secret 变成受控的、可审计的、集中管理的资源。Hermes v0.19.0 的 SecretSource 把这个理念和 agent 的启动路径打通,让 agent 启动时就能像读取普通环境变量一样读取 vault 里的值。
Hermes v0.19.0 的 SecretSource 能做什么
根据 v0.19.0 发布说明 和官方 Secrets 文档,SecretSource 接口具备以下能力:
- 多 vault 并行:可以同时启用 Bitwarden Secrets Manager 和 1Password。也支持一个通用
commandsource,适配任何能输出KEY=VALUE的命令行 vault。 - 确定性优先级:Hermes 按明确规则解决冲突:显式的
env:映射(1Password、command source)优先于批量拉取(Bitwarden);同类型 source 之间按可选的secrets.sources列表顺序决定;.env和 shell 变量默认优先,除非 source 设置override_existing: true。 - 冲突警告:如果后一个 source 要覆盖前一个 source 已经提供的同名变量,Hermes 会明确提示,而不是静默选择。
- 变量来源追踪:每个注入的变量都记录来自哪个 source,status 命令和启动日志会显示清楚。
- 启动不阻塞:如果 vault 无法访问或认证失败,Hermes 会打印一行 remediation 警告,然后继续使用
.env里已有的凭据启动。
这意味着你终于可以写出类似下面这样的配置,而不需要在 .env 里放任何 OPENAI_API_KEY:
secrets:
onepassword:
enabled: true
env:
OPENAI_API_KEY: "op://Private/OpenAI/api key"
ANTHROPIC_API_KEY: "op://Private/Anthropic/credential"
override_existing: true
下面我们就按 5 个步骤把它跑起来。
第 1 步:升级到 Hermes v0.19.0 并确认 CLI 状态
SecretSource 是 v0.19.0 引入的功能,所以先确认版本:
hermes --version
然后确认 secrets 子命令存在:
hermes secrets --help
输出里应该能看到 bitwarden、onepassword 等 source helper。如果版本低于 v0.19.0,执行安装脚本升级:
# macOS / Linux / WSL2
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
# Windows (PowerShell)
iex (irm https://hermes-agent.nousresearch.com/install.ps1)
第 2 步:选择 vault 并完成身份认证
Hermes 不替你完成身份认证,而是依赖对应 vault 的官方流程。你需要在本机或部署目标机器上完成。
方案 A:Bitwarden Secrets Manager
你需要在 Bitwarden Secrets Manager 里创建一个 machine account,而不是普通 Bitwarden 密码库的 account。Machine account 专为非交互式工作负载设计。
- 在 Bitwarden web app 切换到 Secrets Manager。
- 创建一个 Project(例如
Hermes keys)。 - 把 provider key 作为 secret 加进去。secret 的 Name 就是 Hermes 要用的环境变量名,例如
OPENAI_API_KEY、ANTHROPIC_API_KEY、TELEGRAM_BOT_TOKEN等。 - 进入 Machine accounts → New machine account,给该 account 授予项目的读取权限。
- 在 Access tokens 下创建一个 token(以
0.开头,创建后无法再次查看),复制下来。
把这个 token 放到 ~/.hermes/.env 里,命名为 BWS_ACCESS_TOKEN:
BWS_ACCESS_TOKEN=0.xxx...
bws 二进制文件会在 Hermes 第一次需要时自动下载到 ~/.hermes/bin/,不需要 brew、apt 或 sudo。
方案 B:1Password
安装官方 1Password CLI(op),并验证可用:
op --version
op whoami
笔记本/交互式场景:用 op signin 或在 1Password 应用里启用 CLI 集成。Hermes 会把你的 session 变量透传给 op 子进程。
服务器/CI/cron 场景:创建一个 service account,授予它相关 vault 的读取权限,然后把 token 放到 ~/.hermes/.env:
OP_SERVICE_ACCOUNT_TOKEN=ops_...
安全提示:bootstrap token(
BWS_ACCESS_TOKEN或OP_SERVICE_ACCOUNT_TOKEN)本身就是高价值凭据。把它放在~/.hermes/.env里,不要放到config.yaml,也绝对不要把.env提交进仓库。
第 3 步:运行设置向导并配置 source
Hermes 为每个 source 提供了独立的 CLI。向导会把配置写入 ~/.hermes/config.yaml(如果你使用 named profile,则写入 ~/.hermes/profiles/<profile>/config.yaml)。
Bitwarden
交互式运行:
hermes secrets bitwarden setup
也可以非交互式执行:
hermes secrets bitwarden setup \
--access-token "$BWS_ACCESS_TOKEN" \
--server-url https://vault.bitwarden.com \
--project-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
生成的配置类似这样:
secrets:
bitwarden:
enabled: true
project_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
server_url: "https://vault.bitwarden.com"
access_token_env: BWS_ACCESS_TOKEN
override_existing: true
cache_ttl_seconds: 300
1Password
运行向导:
hermes secrets onepassword setup
如果使用 service account token:
hermes secrets onepassword setup \
--account my.1password.com \
--token-env OP_SERVICE_ACCOUNT_TOKEN \
--token "$OP_SERVICE_ACCOUNT_TOKEN"
然后逐个环境变量映射到 op:// 引用:
hermes secrets onepassword set OPENAI_API_KEY "op://Private/OpenAI/api key"
hermes secrets onepassword set ANTHROPIC_API_KEY "op://Private/Anthropic/credential"
hermes secrets onepassword set TELEGRAM_BOT_TOKEN "op://Private/Telegram/token"
生成的配置:
secrets:
onepassword:
enabled: true
env:
OPENAI_API_KEY: "op://Private/OpenAI/api key"
ANTHROPIC_API_KEY: "op://Private/Anthropic/credential"
TELEGRAM_BOT_TOKEN: "op://Private/Telegram/token"
service_account_token_env: OP_SERVICE_ACCOUNT_TOKEN
override_existing: true
cache_ttl_seconds: 300
同时启用两个 source
你可以同时启用 Bitwarden 和 1Password。用 sources 列表控制顺序:
secrets:
sources: [onepassword, bitwarden]
onepassword:
enabled: true
env:
OPENAI_API_KEY: "op://Private/OpenAI/api key"
bitwarden:
enabled: true
project_id: "..."
注意:对于同名变量,显式映射 source(1Password)自动优先于批量拉取 source(Bitwarden),这与顺序无关。同类型 source 之间按顺序决定,先匹配者胜出。
第 4 步:把明文 API key 迁移到外部 vault
4.1 梳理当前 .env 中的 key
先把 Hermes 当前使用的 key 按风险分类,避免遗漏:
- 模型 API key:
OPENAI_API_KEY、ANTHROPIC_API_KEY、GEMINI_API_KEY等 - 平台 token:
TELEGRAM_BOT_TOKEN、DISCORD_BOT_TOKEN、SLACK_BOT_TOKEN - 云服务凭证:
AWS_ACCESS_KEY_ID、CLOUDFLARE_API_TOKEN、GCP_API_KEY - 第三方工具:GitHub PAT、Sentry DSN、Stripe key 等
4.2 在 vault 中创建 secret
Bitwarden:在你选定的 project 里,每个环境变量对应一个 secret。secret 名称必须和 Hermes 期望的变量名完全一致,例如 OPENAI_API_KEY。运行 hermes secrets bitwarden sync 时,Hermes 会列出它能解析的变量。
1Password:根据 op://vault/item/field 引用创建对应的 item 和字段。例如你把 OPENAI_API_KEY 映射到 op://Private/OpenAI/api key,就要在 Private vault 里创建名为 OpenAI 的 item,字段名为 api key。
迁移顺序建议:先搬那些一旦泄露损失最大的 key(如 Stripe、AWS 根账号、模型 provider 的主 key),再处理相对低风险的 read-only key。
4.3 精简 .env 并创建 example.env
完成迁移后,把 .env 里对应的真实 key 删除或注释掉,只保留 source 需要的 bootstrap token:
# ~/.hermes/.env
BWS_ACCESS_TOKEN=0.xxx...
# 或者 1Password:
# OP_SERVICE_ACCOUNT_TOKEN=ops_...
再创建一个 example.env,只写变量名和用途,不写真实值:
# example.env — 把真实值放到你的外部 vault 中
OPENAI_API_KEY=see-vault
ANTHROPIC_API_KEY=see-vault
TELEGRAM_BOT_TOKEN=see-vault
这样新成员入职时,只需知道该去哪个 vault 找 key,而不需要你把 .env 发给他。
第 5 步:验证、轮换与回滚
5.1 验证 secret 是否正确注入
Bitwarden:
hermes secrets bitwarden status
hermes secrets bitwarden sync # 干跑:预览会注入哪些变量
hermes secrets bitwarden sync --apply # 实际导出到当前 shell
1Password:
hermes secrets onepassword status
hermes secrets onepassword sync # 干跑
hermes secrets onepassword sync --apply # 实际导出到当前 shell
启动一个新的 hermes 进程(或 cron job、gateway 服务),新 key 就会自动生效。你可以在启动日志或 source 的 status 命令里确认变量来源。
5.2 设置轮换提醒
大多数 vault 都支持自定义字段或 note。你可以在每个 item 里加上 rotation_date,然后在日历里设置 90 天提醒。provider key 更新时,只需在 vault 里改值,不需要改任何本地文件,下一次启动 Hermes 就会用上新值。
如果 bootstrap token 本身泄露或过期,不需要重跑整个向导,用专用命令轮换:
hermes secrets bitwarden token
hermes secrets onepassword token
这两个命令都会先验证 token 再写入,所以贴错了不会破坏现有配置。
5.3 保留回滚路径
激进地把所有 key 全搬出去之前,建议分阶段进行:
- 灰度迁移:只把一个非关键 key(如某个 read-only 搜索 API)放进 vault,验证流程。
- 双写观察期:vault 和
.env同时保留,但把 source 的override_existing设为true。观察几天确认没问题。 - 彻底删除:确认稳定后,再从
.env删除对应真实 key,只保留 bootstrap token。
如果遇到问题,最简单的回滚是关闭 source:
hermes secrets bitwarden disable
hermes secrets onepassword disable
Hermes 会立即回到只使用 .env 凭据的状态。
常见陷阱
-
把真实 secret 写进
config.yaml。config.yaml里应该只放引用(如op://...)和 project ID,真实值必须留在 vault 里。 -
把 vault 的 bootstrap token 放进共享
.env又提交进仓库。BWS_ACCESS_TOKEN和OP_SERVICE_ACCOUNT_TOKEN都是高价值 bearer token。.env要排除在版本控制之外,并限制文件权限。 -
以为
.env会自动失效。 默认情况下,.env和 shell 变量优先。如果 source 的override_existing是false,而.env里还有旧 key,Hermes 会继续用.env的值。想让 vault 成为唯一真相时,要设override_existing: true。 -
忽略冲突警告。 当多个 source 提供同名变量时,Hermes 会提示。不要习惯性关掉提示,先确认哪个 source 应该胜出,或用
secrets.preserve_existing把特定变量固定留在.env。 -
在服务器上用交互式解锁。
op signin或BW_SESSION笔记本用没问题,但 cron、gateway、CI 应该用 service account 或 machine account 的非交互式 token。 -
忘了更新
example.env。 外部化之后,example.env成了唯一的“文档”,要让它和真实 vault 结构保持一致。
让审批层也更安全
把 key 搬出 .env 只是第一步。v0.19.0 还默认启用了 Smart Approvals,当 Hermes 要执行敏感命令时,会由独立的 LLM reviewer 评估,而不是每次都要你手动点同意。结合外部密钥保险箱,你相当于给 agent 上了两道锁:
- 静态安全:secret 不落地、不扩散、可审计。
- 动态安全:高风险操作需要二次评判,避免一个越权调用把 key 泄露出去。
总结
Hermes v0.19.0 的 SecretSource 让 API key 管理从“复制粘贴到 .env“进化到”从外部 vault 按需注入“。只需 5 步:
- 升级到 v0.19.0,并确认
hermes secrets子命令存在; - 完成 Bitwarden Secrets Manager 或 1Password 认证,把 bootstrap token 放进
.env; - 运行设置向导,在
config.yaml中配置 source; - 把
.env中的真实 key 迁移到 vault,只保留 bootstrap token; - 用
status/sync验证,在 vault 侧轮换,并保留回滚路径。
这样你的 .env 可以从几十行密文压缩成一个 bootstrap token,而 Hermes 依然能在启动时拿到所有需要的 secret。团队协同时不再需要传来传去,密钥轮换时也不再怕漏改某个文件。
参考链接: