Last updated on

别再把 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 Manager1Password。你只需在 .env 里放一个启动用的 bootstrap token,其余 key 全部交给 vault 管理。API key 终于不用塞满 .env 了。

本文给出一个可落地的 5 步迁移方案。你不需要一次性重构整个配置,而是可以逐步把高风险 key 搬出去,同时保留回滚能力。

想先了解 v0.19.0 的全部更新,可以参考我们的 v0.19.0 发布说明Skill 连招指南


为什么 .env 不是长期答案

.env 在原型阶段很方便,但当 Hermes 需要连接十几个工具和服务时,它会暴露出三个结构性问题:

  1. 扩散风险:每复制一份 .env 到另一台机器、容器或 CI 环境,就多一个泄露面。GitHub 每年都会扫描到数百万个误提交的秘密。
  2. 缺少审计.env 不会告诉你谁在什么时候改了哪个 key。一个 key 被换掉了,其他同事可能直到服务报错才发现。
  3. 轮换痛苦: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。也支持一个通用 command source,适配任何能输出 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

输出里应该能看到 bitwardenonepassword 等 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 专为非交互式工作负载设计。

  1. Bitwarden web app 切换到 Secrets Manager
  2. 创建一个 Project(例如 Hermes keys)。
  3. 把 provider key 作为 secret 加进去。secret 的 Name 就是 Hermes 要用的环境变量名,例如 OPENAI_API_KEYANTHROPIC_API_KEYTELEGRAM_BOT_TOKEN 等。
  4. 进入 Machine accounts → New machine account,给该 account 授予项目的读取权限。
  5. Access tokens 下创建一个 token(以 0. 开头,创建后无法再次查看),复制下来。

把这个 token 放到 ~/.hermes/.env 里,命名为 BWS_ACCESS_TOKEN

BWS_ACCESS_TOKEN=0.xxx...

bws 二进制文件会在 Hermes 第一次需要时自动下载到 ~/.hermes/bin/,不需要 brewaptsudo

方案 B:1Password

安装官方 1Password CLIop),并验证可用:

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_TOKENOP_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 keyOPENAI_API_KEYANTHROPIC_API_KEYGEMINI_API_KEY
  • 平台 tokenTELEGRAM_BOT_TOKENDISCORD_BOT_TOKENSLACK_BOT_TOKEN
  • 云服务凭证AWS_ACCESS_KEY_IDCLOUDFLARE_API_TOKENGCP_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 全搬出去之前,建议分阶段进行:

  1. 灰度迁移:只把一个非关键 key(如某个 read-only 搜索 API)放进 vault,验证流程。
  2. 双写观察期:vault 和 .env 同时保留,但把 source 的 override_existing 设为 true。观察几天确认没问题。
  3. 彻底删除:确认稳定后,再从 .env 删除对应真实 key,只保留 bootstrap token。

如果遇到问题,最简单的回滚是关闭 source:

hermes secrets bitwarden disable
hermes secrets onepassword disable

Hermes 会立即回到只使用 .env 凭据的状态。


常见陷阱

  1. 把真实 secret 写进 config.yaml config.yaml 里应该只放引用(如 op://...)和 project ID,真实值必须留在 vault 里。

  2. 把 vault 的 bootstrap token 放进共享 .env 又提交进仓库。 BWS_ACCESS_TOKENOP_SERVICE_ACCOUNT_TOKEN 都是高价值 bearer token。.env 要排除在版本控制之外,并限制文件权限。

  3. 以为 .env 会自动失效。 默认情况下,.env 和 shell 变量优先。如果 source 的 override_existingfalse,而 .env 里还有旧 key,Hermes 会继续用 .env 的值。想让 vault 成为唯一真相时,要设 override_existing: true

  4. 忽略冲突警告。 当多个 source 提供同名变量时,Hermes 会提示。不要习惯性关掉提示,先确认哪个 source 应该胜出,或用 secrets.preserve_existing 把特定变量固定留在 .env

  5. 在服务器上用交互式解锁。 op signinBW_SESSION 笔记本用没问题,但 cron、gateway、CI 应该用 service account 或 machine account 的非交互式 token。

  6. 忘了更新 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 步:

  1. 升级到 v0.19.0,并确认 hermes secrets 子命令存在;
  2. 完成 Bitwarden Secrets Manager1Password 认证,把 bootstrap token 放进 .env
  3. 运行设置向导,在 config.yaml 中配置 source;
  4. .env 中的真实 key 迁移到 vault,只保留 bootstrap token;
  5. status/sync 验证,在 vault 侧轮换,并保留回滚路径。

这样你的 .env 可以从几十行密文压缩成一个 bootstrap token,而 Hermes 依然能在启动时拿到所有需要的 secret。团队协同时不再需要传来传去,密钥轮换时也不再怕漏改某个文件。

参考链接: