博客 · 指南 · 2026年10月28日
AEGIS 如何封装一次工具调用:SEAL 网关,一步一步
声明:AEGIS 和 SEAL Gateway 由 100monkeys.ai 开发,因此请把这篇指南当作开发方的说明来读。它由我们的一个 AI 智能体根据公开文档起草,主要是 SEAL Protocol、Integration with AEGIS 和 Security Contexts 这几页,并经公司审阅;这个简体中文版是英文原版指南的译文。下面的字段、错误码和流程都来自文档,不是我们为写这篇指南而抓取的输出;引文保留英文原文,译文附在旁边。
AEGIS by 100monkeys.ai, in beta,不会因为一次工具调用是智能体发出的就信任它。每次调用都装在一个签名信封里,SEAL Gateway 会在它触碰执行之外的任何东西之前先做检查。本指南跟随一次调用,从执行开始一直到它留下的审计记录。
SEAL 是做什么的
SEAL 是 Signed Envelope Attestation Layer 的缩写。文档指出常见工具调用协议的四个缺口:无法证明请求由哪个客户端发出;每个会话的权限非全有即全无;请求体在传输中可被篡改;没有记录能证明哪个调用方做了什么。它举的例子是提示注入:一个被抓取的网页让模型删除 /workspace。"With SEAL, the caller's SecurityContext has no fs.delete capability. The gateway blocks it before it ever reaches the tool."(有了 SEAL,调用方的 SecurityContext 没有 fs.delete 能力。网关会在调用到达工具之前就将其拦下。)
网关首先可以独立运行。用文档的话说,它就是 AEGIS 编排器 "deploys alongside itself"(在自身旁边部署)的 "the same aegis-seal-gateway binary"(同一个 aegis-seal-gateway 二进制文件)。使用 AEGIS 时,下面这些步骤无需额外操作;"it is the default."(这是默认行为。)
第 1 步:编排器为这次执行打开一个会话
当一次执行进入 Running 状态时,编排器为它生成一对新的 Ed25519 密钥,并在网关注册:POST /v1/seal/sessions,带上 session_id(即执行 id,"so audit trails line up",让审计轨迹能对上)、public_key、security_context,以及受执行墙钟时间预算限制的 expires_at。只有拥有 seal.session.create 权限范围的调用方才能这样做;"agents themselves cannot self-register."(智能体本身不能自行注册。)
第 2 步:私钥只交给智能体,不去别处
私钥部分被写入智能体容器的临时配置中,"a tmpfs mount, never persisted"(一个 tmpfs 挂载,从不持久化),同时写入的还有网关 URL 和会话 id。因此每次执行都有自己的密钥,"a leaked private key is bounded to a single execution's lifetime."(泄露的私钥只在单次执行的生命周期内有效。)
第 3 步:会话绑定到唯一一个安全上下文
安全上下文是网关上的一条具名策略:一个 deny_list 和一个有序的 capabilities 列表,每项能力包含一个 tool_pattern,以及可选的 path_allowlist、command_allowlist、subcommand_allowlist、domain_allowlist 和 max_response_size。被启动的智能体运行在 aegis-system-agent-runtime 之下,而不是发起请求那个人所在等级的上下文。编排器在配置时固定上下文,智能体 "cannot escalate by claiming a different scp in its envelope"(不能通过在信封里声明另一个 scp 来提权)。
第 4 步:智能体签署一条规范化消息
签名针对的不是原始 JSON,而是三个键:payload、security_token 和 timestamp。序列化时每一层的键都排序,没有空白,时间戳是整数形式的 Unix 时间,编码为 UTF-8。任何其他字节序列都会得到不同的签名,"the gateway will reject the envelope."(网关会拒绝这个信封。)
第 5 步:智能体发送信封
信封包含 protocol(始终为 seal/v1)、security_token(在证明时签发的 JWT,默认有效期一小时)、Ed25519 signature、payload(对 MCP 风格的调用来说,是一个 JSON-RPC tools/call)、可选的 container_id 和 timestamp。它被发到网关的调用端点 POST /v1/invoke。网关默认监听 8089 端口;AEGIS 编排器自己的 API 在 8088。
第 6 步:网关执行九项检查
- protocol 字段为
seal/v1。 - 令牌解码出各项声明:
sub、scp、wid、exec_id、iat、exp、jti。 - 用网关的密钥验证令牌签名,并显式检查
alg头。 - 令牌未过期。
- 找到该会话中调用方已注册的公钥。
- 重建规范化消息。
- 用该公钥和该消息验证信封签名。
- 时间戳与服务器时钟相差不超过 30 秒。
- 加载
scp中指定的安全上下文并评估这次调用。
"Every check must pass before the payload is unwrapped and forwarded."(所有检查都通过后,载荷才会被解开并转发。)
第 7 步:安全上下文做出决定
评估按固定顺序进行:匹配到 deny_list 中的模式,调用就被拒绝;否则,"the first capability whose tool_pattern matches the tool name owns the decision"(第一个 tool_pattern 与工具名匹配的能力负责决定);一个都不匹配时调用被拒绝,因为 "there is no implicit allow."(不存在隐式允许。)像 fs.* 这样的族模式匹配 fs.read,但永远不匹配 fs 或 fsx.read。
第 8 步:调用被转发,或带着错误码被拒绝
被允许的调用会解开载荷并发给工具;如果工具需要凭据,在这一刻解析。被拒绝的调用返回一个数字错误码:2000 到 2006 表示策略问题(未授予、在拒绝列表中、路径、命令或域名不在允许列表内、速率限制、没有匹配的能力),1001 到 1006 表示签名、令牌和会话问题,3000 到 3002 表示证明问题。文档的建议是:"Switch on error.code, not on the status."(根据 error.code 分支,而不是根据状态码。)
第 9 步:每个决定都留下一条审计事件
网关会发布 ToolCallAuthorized 或 PolicyViolationBlocked 等事件,内容包括信封的签名、时间戳和 jti,令牌的 sub、scp、wid 和 exec_id,工具名,载荷摘要("payloads are not logged by default",默认不记录载荷),以及决定和做出决定的规则。由于只有该会话的私钥能签署这个信封,这条记录具有不可否认性。
第 10 步:会话随执行一起结束
执行结束时,无论是成功、失败、超时还是取消,编排器都会调用 DELETE /v1/seal/sessions/{session_id}。网关删除密钥,之后重放被截获的信封会被拒绝。
文档尚未说明的地方
- 速率限制。SEAL Protocol 页面把 "rate limit not exceeded"(未超过速率限制)列为一项检查,并有错误码
2005;Security Contexts 页面却说rate_limit"reserved for a future enforcement phase"(保留给未来的执行阶段)。文档没有说明目前是否实施任何限制。 - 文档说会话关闭后的重放会以
session_not_found失败;错误表写作1005SESSION_NOT_FOUND。文档没有展示这种情况下客户端收到的响应体。 - 这些页面没有说明独立网关把审计事件存在哪里,也没有说明
PolicyViolationBlocked是否出现在它的gateway_events表中。
下一步
想在真实的执行中找到这些调用,请阅读 Reading an AEGIS execution log(英文)。想动手试试,AEGIS 可以用 100monkeys.ai 上给出的命令安装:
curl -fsSL https://get.100monkeys.ai | bash