别把 API Key 交给 Agent:用 Harbinger 把身份、策略与密钥注入拆到网关两侧
给 AI 编程 Agent 配 GitHub、Slack、云平台或内部 API 凭据,最常见的做法仍是把长效 Token 写进环境变量。它足够省事,却把两类本应独立的问题绑到了一起:正在发起请求的进程是谁,以及它在什么条件下可以使用哪一份秘密。
一旦 Agent 被提示注入诱导、插件读取了环境,或某段工具调用被带往错误的域名,静态 Token 很难再提供“只允许这一次、只允许去这个地方”的边界。撤销时也往往只能轮换共享密钥,影响范围很大。
Harbinger 是一个 Apache-2.0 许可的自托管非人类身份(NHI)安全平台。它把 Agent 的出口流量导向 mTLS 网关:网关先验证 Agent 证书、再评估策略,最后才在受控的目标站点边缘替换秘密占位符。重点不是让 Agent 学一套新 SDK,而是把已有命令包在代理守护进程下运行。对于需要保留现有 Agent、又想逐步收紧凭据边界的小团队,这是一条值得评估的路径。
先拆清楚:身份不是密钥,代理也不等于放行
Harbinger 的结构分为管理面和数据面。harbinger_admin 保存用户、组织、RBAC、策略、保险库/目标映射、证书颁发机构与签名的边缘配置;harbinger_gateway 面对 Agent 流量,完成证书验证、逐请求策略判断与可选的秘密替换。二者刻意分成不同进程:前者持有管理与 CA 权限,后者面对不可信的 Agent 流量和实时取密需求。
Agent 并不直接拿到真实 Token。它首先完成一次证书注册:本地产生密钥对和 CSR,管理员审批后签发 mTLS 证书;随后由 harbinger_agentd 启动目标进程并通过 HTTPS_PROXY 将流量转发给网关。这样,策略可以以证书所代表的 Agent 为主体,而不必把“谁在调用”退化为“谁拿到了同一串 API Key”。
更关键的是,目标映射同时绑定秘密来源与允许的主机。即使某个提示诱导 Agent 把原本用于 Slack 的请求改发到攻击者域名,网关仍会同时检查:该 Agent 是否被允许使用这个目标,以及请求的实际目的地是否就是登记主机。两项不同时满足,真实值不应被替换进请求。
这不是万能沙箱。Harbinger 当前主要治理网络出口和凭据使用;它的 README 也明确把“拦截宿主机命令”列为后续路线图。因此,文件系统权限、容器隔离、代码审查和最小化云端 IAM 仍是独立防线,不能因为有了网关而取消。
最小可运行链路:先把控制面和客户端装起来
官方 Docker Compose 流程会构建服务,并在 deploy/docker/client-bundle/ 生成 hbg_cli、harbinger_agentd 与部署专属的 root_ca.crt。先复制环境文件,在 .env 中设置真实且妥善保管的 ADMIN_PASSWORD,再启动服务:
cd deploy/docker cp .env.example .env docker compose up --build
服务就绪后,将客户端包放到实际运行 Agent 的机器。下面的命令先安装根证书并提交 Agent 注册;管理员可在本地 Web UI 的 Agent Enrollment 页面审批,也可以使用 CLI 完成审批。审批后再次运行安装命令,客户端会写入该 Agent 的证书、私钥、根证书缓存和 agentd.yml。
cd deploy/docker/client-bundle ./hbg_cli cert install --cert root_ca.crt ./hbg_cli agent install --agent code-reviewer --ip 10.0.0.5 --user admin # 完成审批后,再次执行: ./hbg_cli agent install --agent code-reviewer
这里有一个运维取舍:证书与配置属于运行时身份材料,应像生产凭据一样限制权限、设置备份和轮换流程;不要把客户端目录提交进仓库,也不要为了图方便让所有自动化任务共用同一个 Agent 名称。按任务或环境拆分身份,策略和审计记录才有解释力。
用“包装运行”替换裸跑,并让真实密钥留在保险库侧
完成注册后,不需要修改 OpenCode 等既有程序的源码。通过 harbinger_agentd run 拉起子进程,守护进程负责把它的 HTTPS 流量经网关发送:
harbinger_agentd run --agent code-reviewer -- opencode
若工作流确实需要调用 Slack,可先建立一个“秘密—目标主机”的映射。示例中的 local: 表示本地保险库引用;生产环境应根据团队的密钥管理体系评估官方支持的保险库接入方式,并避免将真实值打印到终端或 CI 日志。
hbg_cli admin target create \ --name slack-bot-token \ --secret-ref local:slack-bot-token \ --host slack.com
随后在 Agent 原先读取 Token 的位置放入 Harbinger 的占位符,而不是 Token 本身:
export SLACK_BOT_TOKEN='hbg-secret:slack-bot-token:' harbinger_agentd run --agent code-reviewer -- opencode
占位符本身并不等同于凭据。只有策略明确允许 code-reviewer 使用该目标、且请求实际前往 slack.com 时,网关才会向外发出的请求填入真实秘密。实践中,应将“目标名”设计为业务能力而不是泛化的“prod-token”:例如区分只读工单、通知机器人与发布流水线;同时为不同环境建立不同映射,减少误用一把万能密钥的机会。
把策略写成可审计的边界,而不是一张“允许列表”
Harbinger 的价值不在于“代理存在”,而在于把一次请求拆成可检查的决策链。建议为每个 Agent 记录至少四个维度:身份名称、业务用途、可访问的目标主机、允许使用的目标映射。这样,当代码审查 Agent 只需要向 slack.com 发送通知时,它不应天然继承访问代码托管、云控制台或生产数据库的能力。
策略变更也应像基础设施变更一样进入审查:新增一个目标映射前,先确认秘密实际属于哪个系统、调用是否能改用短期凭据、请求是否必须出网;收集到的流量记录则用来复核规则是否过宽。若某个工具需要多个 API 域名,宁可先明确列出并逐项验证,也不要为了避免故障写成不受约束的宽泛规则。这个过程会增加一点初始化成本,却把“为什么此 Agent 能碰到此秘密”从口头约定变成可以复查的配置。
在事件响应中,优先级也更清晰:怀疑某个 Agent 会话受控时,先撤销或停止其身份,再检查该身份对应的目标与审计记录;怀疑某份上游凭据已泄漏时,则同时在供应商侧轮换它,并检查是否有其他目标映射引用同一秘密。两条处置线不能互相替代:mTLS 身份限制的是谁能进入网关,秘密轮换处理的是秘密本身的生命周期。
部署前要问的四个问题
第一,哪些流量确实走代理? harbinger_agentd 对无法自行配置代理的既有 Agent 很有价值,但部署后仍应做一次出站验证,确认目标进程没有绕过代理的替代网络路径。第二,策略默认是拒绝还是默认放行? 从最少的 Agent—目标组合开始,再按审计结果扩展,比先接入所有 Token 再补策略安全得多。
第三,证书吊销是否能及时生效? Harbinger 描述了四层 CA 分工,并通过签名边缘配置把 CRL 分发到网关。团队需要在演练中验证:禁用一个 Agent 后,旧证书的请求是否确实被拒绝;这比只确认管理界面显示“已撤销”更重要。
第四,泄漏后的动作是否可重复? 把注册审批、目标映射、策略变更和撤销流程写成操作记录;对高风险目标保留额外人工批准。网关能够缩小“秘密暴露给 Agent 进程”的面积,但它无法替代供应商侧的 Token 轮换、权限回收与异常调用告警。
Harbinger 适合的不是“给所有 Agent 再发一把密钥”,而是把网络身份、目的地约束和真实秘密分层处理。先挑一个低风险、明确域名的集成做试点,验证证书注册、代理链路、目标约束和撤销演练,再逐步覆盖更敏感的自动化工作流,通常比一次性改造整个 Agent 平台更可靠。
试点验收不应只看“请求成功”。至少保留三组反向测试:没有有效证书的进程能否被网关拒绝;已注册的 Agent 把请求改往未登记主机时是否拿不到秘密;撤销身份或删除目标映射后,原有会话是否会立即失去访问能力。再把这些测试放进升级和策略变更后的检查清单,才能避免安全边界只在首次部署时成立。对于生产自动化,另应限制管理面账号、备份 CA 与数据库,并将网关的可用性、证书到期和策略分发纳入监控;身份治理本身也是一项需要持续运行的服务。