首页 / Hermes Agent 教程 / 安全、密钥与凭据管理

Hermes Agent 教程

安全、密钥与凭据管理

本教程共 25 篇 · 第 24 篇 · 更新于 2026-07-26 · 约 16 分钟阅读

Hermes AgentHermes Agent 教程安全密钥管理审批Bitwarden1Passwordiron-proxy

24. 安全、密钥与凭据管理

本节目标:理解 Hermes Agent 的八层安全模型,掌握危险命令审批机制,学会用外部密钥管理器替代明文 .env,了解容器隔离和出口代理如何保护你的 API Key 不被沙盒里的 Agent 偷走。

让 Agent 帮你干活很爽,但 Agent 能跑终端命令、能读写文件、能发网络请求—这意味着一旦判断失误,它可能删掉重要文件、泄露 API Key、或者执行不可逆的破坏性操作。这一章讲 Hermes Agent 怎么在”让 Agent 有能力做事”和”不让 Agent 搞出灾难”之间找平衡。

安全模型总览

Hermes Agent 采用纵深防御(defense-in-depth)策略,八层安全边界从外到内:

  1. 用户授权:谁能跟 Agent 说话(允许列表、DM 配对)
  2. 危险命令审批:破坏性操作需要人工确认
  3. 文件写入安全:黑名单 + 可选写入沙盒
  4. 容器隔离:Docker / Singularity / Modal 沙盒加硬化设置
  5. MCP 凭据过滤:MCP 子进程的环境变量隔离
  6. 上下文文件扫描:项目文件的提示注入检测
  7. 跨会话隔离:会话间不能互相访问数据和状态
  8. 输入净化:终端工具的工作目录参数经过允许列表验证,防 shell 注入

危险命令审批

三种审批模式

Agent 每次执行终端命令前,Hermes 会拿命令去匹配一张危险模式列表。命中了就拦下来,根据审批模式决定怎么处理。

approvals:
  mode: smart                     # smart | manual | off
  timeout: 300                    # 等用户回复的秒数(默认 300)
  cron_mode: deny                 # deny | approve - 定时任务碰到危险命令怎么办
  mcp_reload_confirm: true        # /reload-mcp 前先问
  destructive_slash_confirm: true # /clear /new /reset /undo 前先问

三种模式:

模式行为
smart(默认)用辅助 LLM 评估风险。低风险命令(如 python -c "print('hello')") 自动放行。真正危险的自动拒绝。不确定的问人
manual命中危险模式就问用户
off关闭所有审批检查,所有命令直接执行
Warning

approvals.mode: off 关闭所有安全提示。只在可信环境(CI/CD、容器等)里用。

YOLO 模式

YOLO 模式跳过当前会话的所有危险命令审批。三种激活方式:

# CLI 标志
hermes --yolo
hermes chat --yolo

# 会话内切换(开关式,再输一次关闭)
/yolo

# 环境变量
HERMES_YOLO_MODE=1

开启后会有两个持续视觉提醒:会话开始时的红色横幅和状态栏里的 ⚠ YOLO 标记,让你不容易忘记自己跳过了审批。

Warning

YOLO 模式跳过所有危险命令安全检查—除了硬线黑名单(下面讲)。只在完全信任命令的场景用(比如一次性环境里的测试脚本)。

硬线黑名单(永远开着)

有些命令太灾难性了—不可逆的文件系统擦除、fork bomb、直接写块设备—Hermes 拒绝执行它们,不管你是不是开了 YOLO、是不是设了 approvals.mode: off、是不是 cron 在无头模式跑。

黑名单在审批层看到命令之前就拦截,没有覆盖开关:

模式为什么硬线
rm -rf / 及变体擦除文件系统根
rm -rf --no-preserve-root /明确”我要删根”的变体
:(){ :|:& };:(bash fork bomb)把主机钉死到重启
mkfs.* 挂载的根设备格式化正在运行的系统
dd if=/dev/zero of=/dev/sd*清零物理磁盘
管道不可信 URL 到 sh远程代码执行,攻击面太广

碰到黑名单,工具调用返回解释性错误给 Agent,什么都不执行。

用户自定义拒绝规则

硬线黑名单是代码里固定的。approvals.deny 是它的用户可编辑版本—一组 glob 模式,匹配的终端命令无条件阻止,在 YOLO 和 off 模式之前生效。

approvals:
  deny:
    - "git push --force*"
    - "*curl*|*sh*"
    - "dd if=* of=/dev/*"

适合”YOLO 加例外”的场景:让 Agent 啥都能做,但这几样永远不行。

Note

拒绝规则防的是”诚实但犯错”的 Agent,不是恶意进程。要防恶意进程,用隔离后端(Docker、Modal)或出口受限环境。

审批流程

CLI 里碰到危险命令,弹出内联提示:

  ⚠️  DANGEROUS COMMAND: recursive delete
      rm -rf /tmp/old-project

      [o]nce  |  [s]ession  |  [a]lways  |  [d]eny

      Choice [o/s/a/D]:

四个选项:

  • once:放行这一次
  • session:本会话内同类操作都放行
  • always:加到永久允许列表(写入 config.yaml
  • deny(默认):拒绝

消息平台(Telegram、Discord 等)上,Agent 把命令详情发到聊天,等你回复 yes / no。

选了 always 的模式会存到配置文件:

command_allowlist:
  - rm
  - systemctl

以后所有会话自动放行这些模式。

Tip

hermes config edit 可以查看或删除永久允许列表里的模式。

什么会触发审批

30 多条危险模式覆盖了:

  • 递归删除(rm -r
  • 磁盘操作(mkfsdd
  • SQL 破坏(DROP TABLEDELETE FROM 不带 WHERETRUNCATE
  • 系统服务(systemctl stop/restart/disable
  • 进程管理(kill -9 -1pkill -9
  • fork bomb
  • 远程脚本执行(curl ... | sh
  • 系统配置覆写(> /etc/tee~/.ssh/
  • Git 破坏性操作(git reset --hard
  • Shell 脚本执行(bash -cpython -e
Note

在 Docker / Singularity / Modal / Daytona 后端里,危险命令检查跳过,因为容器本身就是安全边界。容器里的破坏性命令伤不到宿主机。

文件写入安全

write_filepatch 在写磁盘前,会检查目标路径。被阻止的写入直接返回错误给 Agent—没有审批提示,没有聊天界面的覆盖方式。

受保护路径(永远阻止)

类别例子
OS 凭据存储~/.ssh/~/.aws/~/.kube//etc/sudoers~/.netrc
Hermes 凭据存储auth.json.envmcp-tokens/pairing/
项目密钥文件任意位置的 .env.env.local.env.production.envrc

可选写入沙盒

设了 HERMES_WRITE_SAFE_ROOT 后,write_filepatch 只能写这个目录前缀内的路径。外面的硬阻止。

# 允许项目目录和 Hermes 主目录
export HERMES_WRITE_SAFE_ROOT=/path/to/project:/home/you/.hermes

官方 Docker 镜像自动设了 HERMES_WRITE_SAFE_ROOT=/opt/data

Warning

写入保护只管 write_filepatchterminal 工具以同一个 OS 用户身份运行,仍然能通过 shell 命令 cat 或覆盖被拒绝的路径。黑名单减少意外损害,不沙盒恶意 Agent。

用户授权(网关)

跑消息网关时,Hermes 控制谁能跟 Bot 交互。授权检查顺序:

  1. 平台级全允许标志(如 DISCORD_ALLOW_ALL_USERS=true
  2. DM 配对已批准列表(通过配对码批准的用户)
  3. 平台专属允许列表(如 TELEGRAM_ALLOWED_USERS=12345,67890
  4. 全局允许列表GATEWAY_ALLOWED_USERS
  5. 全局全允许GATEWAY_ALLOW_ALL_USERS=true
  6. 默认:拒绝
# 平台专属允许列表
TELEGRAM_ALLOWED_USERS=123456789,987654321
DISCORD_ALLOWED_USERS=111222333444555666

# 跨平台允许列表
GATEWAY_ALLOWED_USERS=123456789

# 平台级全允许(慎用)
DISCORD_ALLOW_ALL_USERS=true

# 全局全允许(极度慎用)
GATEWAY_ALLOW_ALL_USERS=true
Warning

如果没配任何允许列表且没设 GATEWAY_ALLOW_ALL_USERS所有用户都被拒绝。网关启动时会打印警告提示你配置。

DM 配对系统

不用提前收集用户 ID,用配对码流程:

  1. 陌生用户给 Bot 发私信
  2. Bot 回复一个 8 字符配对码
  3. Bot 主人在 CLI 批准:hermes pairing approve telegram ABC12DEF
  4. 该用户被永久批准

安全特性(基于 OWASP + NIST SP 800-63-4):

特性细节
码格式32 字符无歧义字母表(无 0/O/1/I)取 8 字符
随机性密码学安全(secrets.choice()
码有效期1 小时
速率限制每用户每 10 分钟 1 次请求
待处理上限每平台最多 3 个待处理码
锁定5 次失败批准 -> 锁 1 小时
文件安全所有配对数据文件 chmod 0600
日志码永远不输出到 stdout

容器隔离

用 Docker 终端后端时,Hermes 给每个容器加严格的安全硬化:

_BASE_SECURITY_ARGS = [
    "--cap-drop", "ALL",                    # 丢弃所有 Linux 能力
    "--cap-add", "DAC_OVERRIDE",            # Root 能写绑定挂载目录
    "--cap-add", "CHOWN",                   # 包管理器需要改文件属主
    "--cap-add", "FOWNER",                  # 包管理器需要改文件属主
    "--security-opt", "no-new-privileges",  # 阻止提权
    "--pids-limit", "256",                  # 限制进程数
    "--tmpfs", "/tmp:rw,nosuid,size=512m",  # 限制 /tmp 大小
    "--tmpfs", "/var/tmp:rw,noexec,nosuid,size=256m",  # /var/tmp 不可执行
]

资源限制可配置:

terminal:
  backend: docker
  docker_image: "nikolaik/python-nodejs:python3.11-nodejs20"
  docker_forward_env: []    # 显式允许列表,空 = 密钥不进容器
  container_cpu: 1          # CPU 核数
  container_memory: 5120    # MB(默认 5GB)
  container_disk: 51200     # MB(默认 50GB)
  container_persistent: true
Tip

生产网关部署用 dockermodaldaytona 后端隔离 Agent 命令,彻底消除危险命令审批的需要。

密钥后端:不用明文存 .env

为什么要用密钥管理器

默认情况下,所有 API Key 都存在 ~/.hermes/.env 里。小规模用没问题,但一旦你需要轮换密钥、团队共享、或者避免明文存储,就该上密钥管理器了。

Hermes 支持在进程启动时从外部密钥管理器拉取 API Key,替换 .env 里的明文存储。引导令牌(密钥管理器的访问凭证)留在 .env,其他所有提供商的密钥可以全部放管理器里集中轮换。

三种内置后端:

后端工具特点
Bitwarden Secrets Managerbws CLI(自动下载)免费层可用,机器账户无需 2FA
1Passwordop CLI(需自行安装)op:// 引用,服务账户或桌面会话认证
Command helper任意 CLI 金库通过用户配置的辅助脚本输出 KEY=VALUE

多源组合与优先级

可以同时启用多个密钥源。优先级规则:

  1. 你的 .env / shell 默认优先。源只有设了 override_existing: true 才覆盖已有值(Bitwarden 默认 true,方便集中轮换)
  2. 映射源胜过批量源。显式绑定环境变量到引用的源(env: 映射)优先于注入整个项目密钥的源
  3. 先到先得。同一类型内,secrets.sources 列表顺序决定,后来的对已声明变量的声明被跳过(带启动警告)

每个注入的凭据都标注来源—hermes model 会显示 (from Bitwarden) 告诉你值从哪来。

Bitwarden Secrets Manager

工作流程:

  1. 在 Bitwarden 网页应用创建机器账户,给它读权限,生成访问令牌
  2. Hermes 把令牌存到 ~/.hermes/.env 作为 BWS_ACCESS_TOKEN
  3. 每次 hermes 启动时,调 bws secret list <project_id> 拉取密钥注入环境变量
  4. 默认覆盖已有值,在网页应用轮换一次所有 Hermes 进程下次启动就生效

bws 二进制首次使用时自动下载到 ~/.hermes/bin/,不用 apt / brew / sudo。

设置向导:

hermes secrets bitwarden setup

向导会:

  1. 下载并验证 bws 二进制
  2. 提示输入访问令牌(隐藏输入)
  3. 问你的 Bitwarden 区域(US Cloud / EU Cloud / 自托管)
  4. 列出机器账户可见的项目,选一个
  5. 测试拉取并显示哪些环境变量会被解析
  6. 开启 secrets.bitwarden.enabled: true

非交互式设置:

hermes secrets bitwarden setup \
  --access-token "$BWS_ACCESS_TOKEN" \
  --server-url https://vault.bitwarden.eu \
  --project-id <project-uuid>

确认状态:

hermes secrets bitwarden status

配置项:

secrets:
  bitwarden:
    enabled: false
    access_token_env: BWS_ACCESS_TOKEN
    project_id: ""
    server_url: ""
    cache_ttl_seconds: 300
    override_existing: true
    auto_install: true
Note

Bitwarden 永远不会阻塞 Hermes 启动。出问题时你在 stderr 看到一行警告,Hermes 继续用 .env 里已有的凭据。

1Password

工作流程:

  1. 安装官方 op CLI 并认证(服务账户令牌或桌面会话)
  2. config.yaml 里把环境变量名映射到 op:// 引用
  3. 每次 hermes 启动时,对每个引用跑 op read 解析值注入环境变量

设置:

# 1. 安装并登录 op
op whoami

# 2. 启用集成
hermes secrets onepassword setup

# 3. 映射凭据
hermes secrets onepassword set OPENAI_API_KEY    "op://Private/OpenAI/api key"
hermes secrets onepassword set ANTHROPIC_API_KEY "op://Private/Anthropic/credential"

# 4. 预览和确认
hermes secrets onepassword sync     # 试运行
hermes secrets onepassword status   # 查看状态

配置:

secrets:
  onepassword:
    enabled: false
    env:
      OPENAI_API_KEY: "op://Private/OpenAI/api key"
      ANTHROPIC_API_KEY: "op://Private/Anthropic/credential"
    account: ""
    service_account_token_env: OP_SERVICE_ACCOUNT_TOKEN
    cache_ttl_seconds: 300
    override_existing: true
Tip

服务器 / CI 环境推荐用服务账户令牌(OP_SERVICE_ACCOUNT_TOKEN)。笔记本可以用桌面会话(op signin)。Hermes 不会替你认证,也不会替你下载 op

Profile 别名

一个共享金库服务多个 Profile 时,Profile 别名功能让每个 Profile 自动拿到自己的密钥。金库里存 TELEGRAM_BOT_TOKEN_MILLAmilla Profile 的适配器读固定名 TELEGRAM_BOT_TOKEN 时自动拿到正确值。默认开启,secrets.profile_alias: false 关闭。

也可以用 preserve_existing 保护某些 Profile 专属密钥不被覆盖:

secrets:
  preserve_existing: [FEISHU_APP_SECRET, TELEGRAM_BOT_TOKEN]

出口代理:iron-proxy

沙盒里的 Agent 能偷你的 Key

Docker 终端沙盒里,Agent 拿着真实的上游 API Key。一个被提示注入的 Agent 可以 cat ~/.config/openrouter/auth.jsonprintenv | grep -i key 把密钥偷走。

出口代理(egress proxy)解决这个问题:沙盒里只放不透明的代理令牌,不是真实密钥。所有沙盒出站流量经过主机上的本地 iron-proxy 守护进程,它终止 TLS 并在转发请求前把代理令牌换成真实凭据。沙盒被攻破,攻击者拿到的令牌只在配置的可信代理边界内有效。

快速上手

# 1. 安装 iron-proxy 二进制(固定版本,SHA-256 验证)
hermes egress install

# 2. 运行向导:生成 CA、铸造代理令牌、写 proxy.yaml
hermes egress setup

# 3. 启动代理守护进程
hermes egress start

# 4. 检查状态
hermes egress status

运行后,Docker 终端后端自动:

  • ~/.hermes/proxy/ca.crt 挂载到沙盒
  • 设置 HTTPS_PROXYHTTP_PROXYREQUESTS_CA_BUNDLESSL_CERT_FILE 等环境变量让所有 HTTP 运行时走代理并信任 CA
  • 在标准提供商环境变量名下导出代理令牌(如 OPENROUTER_API_KEY 设为代理令牌)
  • 添加 --add-host=host.docker.internal:host-gateway 让沙盒能到达主机端代理

配置

proxy:
  enabled: false                  # 主开关
  tunnel_port: 9090               # 隧道监听端口
  auto_install: true              # 自动下载 iron-proxy
  credential_source: env          # env | bitwarden
  enforce_on_docker: true         # 代理没跑时拒绝启动沙盒
  allow_env_fallback: false       # BW 模式下是否回退到环境变量
  upstream_deny_cidrs: null       # SSRF 拒绝列表
  extra_allowed_hosts: []         # 额外允许的上游主机

默认允许的上游主机包括 OpenRouter、OpenAI、Anthropic、Google、xAI、Mistral、Groq、Together、DeepSeek、Nous Research。需要加自定义端点就加到 extra_allowed_hosts,支持通配符(*.foo.com)。

默认 SSRF 拒绝列表覆盖:环回地址、链路本地(含云元数据 IP 169.254.169.254)、RFC1918 私有网段、IPv6 ULA、IPv4 映射 IPv6、CGNAT。

支持的认证方案

提供商环境变量替换位置
OpenRouter、OpenAI、Groq、Together、DeepSeek、Mistral、xAI、Nous*_API_KEYAuthorization
AnthropicANTHROPIC_API_KEYx-api-key + Authorization
Azure OpenAIAZURE_OPENAI_API_KEYapi-key + Authorization
Google AI StudioGEMINI_API_KEY / GOOGLE_API_KEYx-goog-api-key 头或 ?key= 参数
Note

涉及请求签名或 SDK 生成的 OAuth 的提供商(AWS Bedrock 的 SigV4、GCP Vertex AI 的服务账户 OAuth)无法通过静态头替换。这些环境变量在沙盒里会保留真实凭据,出口隔离保证不完整。不用就 unset 掉这些变量清除警告。

Bitwarden 集成

如果你已经用了 Bitwarden Secrets Manager,出口代理可以直接从那里拉真实凭据:

hermes egress setup --from-bitwarden

轮换流程变成:

  1. 在 Bitwarden 网页应用轮换密钥
  2. 主机上 hermes egress stop && hermes egress start
  3. 之后启动的沙盒用新值

不用改 .env,不用重启主机上的 Hermes。


安全这一章到此为止。核心思路是纵深防御—不是靠单一机制,而是多层叠加:用户授权管谁能用,审批管能做什么,文件保护管能写哪里,容器隔离管能伤到什么,密钥管理器管凭据怎么存,出口代理管沙盒里能拿到什么。下一章是最后一章—排障、FAQ 和版本升级,帮你解决实际使用中碰到的问题。