Modal 发布 Sidecars:为 Sandbox 提供低延迟信任边界
Sidecars: A low-latency trust boundary for Sandboxes
Modal 发布 Sidecars,一种与主 Sandbox 同主机运行但相互隔离的容器,用于在可信与不可信代码之间建立安全边界,目前处于 Beta。官方称 Sandbox 与 Sidecar 之间的通信比同区域独立 Sandbox 至少快 3 倍,p50 单次通信 0.58ms 对 2.6ms,p99 为 1.4ms 对 44ms。
Modal 官方给出 Sidecar 的隔离机制与延迟数据,可据此判断智能体沙箱的信任边界如何落地。
在 Modal,我们的客户依赖 Sandboxes 来执行由其下游用户编写的不可信代码,或者——如今几乎完全如此——由 agent 编写的不可信代码。运行不可信代码并不是一个新问题:每个云服务提供商从第一天起就必须这样做,以将其平台与用户隔离,并将用户彼此隔离。幸运的是,像 gVisor 和 Firecracker 这样的技术在大约八年前就“解决”了“隔离”问题。但对我们来说不幸的是,它们解决的是如今已经过时的信任单元。你如何保护用户免受其“自己”代码的侵害?
今天我们很高兴推出 Sidecars,这是我们对这一问题的更广泛解答。Sidecars 是隔离的容器,与你的主 Sandbox 运行在同一主机上,并在可信或不可信代码之间提供真正的安全边界。与使用单独的 Sandboxes 相比,Sidecars 使跨信任边界的通信速度提升 3 倍——这对操作密集型工作负载尤其有帮助。
Sandboxes 中充满了可信代码
Agent 需要能力,但不应拥有凭据。我希望 agent 能查看我的 Slack 消息,并替我向同事道歉,因为回复他们发来的内容花了太长时间。我不希望当这个 agent 偶然打开 exfiltrate-my-credentials.com 的落地页、而该页面指示它记录我的密码时,它知道我的 Slack 密码。
如果 Sandboxes 主要是作为不可信代码的执行环境而存在,那么你就得问:为什么 Sandboxes 里有这么多可信代码?
这种反模式很大程度上源于早期编码 agent(如 Claude Code)的设计方式——它们是为在用户笔记本电脑上运行而设计的,而不是在远程 Sandbox 中运行。harness 从未与其工具调用分离,而这种设计模式在迁移到云端后依然存在。
将 harness 和工具调用托管在一起是一种安全风险。Simon Willison 称之为致命三要素:一个 agent 如果能够访问私有数据、接触不可信内容,并具备对外通信能力,就可能被诱骗泄露这些数据。一个 harness 在其 Sandbox 中运行的编码 agent 默认就具备这三点。harness 的凭据与生成的代码放在一起,agent 可以从网络上读取不可信内容,比如软件包和代码仓库,而 Sandbox 中的任何东西都可以发起网络调用。
如今的修复方案以延迟或灵活性换取安全
我们不是第一个思考这个问题的人,也不是第一个提出解决方案的人。如今流行的解决方案各自移除三要素中的一条腿:将 harness 移出 Sandbox 可移除私有数据,而添加高级网络出口控制则可限制对外通信。
像 Anthropic 和 OpenAI 这样的公司提倡将 agent 的 harness 与其工具调用分离,或者用 Anthropic 的话说:将“大脑”与“手”分离,我们也一直倡导这种模式。
然而,无论 harness 运行在控制平面还是单独的 Sandbox 中,现在每一次 agent 操作都需要一次网络调用。对于进行大量工具调用的 agent 来说,每次调用相关的微小延迟会累积起来。安全最终以延迟为直接代价。此外,对于编码 agent 来说,代码库本身就是私有数据,所以即使 harness 被移出,仍然存在数据泄露风险,这就引出了第二种方法。
第二种方法是构建高级网络出口控制,例如域名允许列表、凭证注入和动态出口策略更新。沙箱提供商,包括我们在内,一直在快速推出这些功能,以解决最常见的泄露风险。
这些解决方案易于使用,对大多数客户来说非常有效,但它们并不像许多客户需要的那样灵活。例如,我们的一个客户 Ramp 需要在其 agent 旁边运行一个复杂服务,该服务既注入密钥,又监控外部调用——现成的密钥注入并未完全满足他们的用例。随着 agent 能力越来越强,新需求涌现的速度超过了任何提供商推出新功能的速度,前沿团队需要一种构建自己解决方案的方式。
一个能避免上述任一权衡的完整解决方案应做到:
- 完全隔离不受信任和受信任的代码
- 为操作密集型 agent 最小化延迟
- 足够灵活,以适应尚未想到的程序
Sidecar 作为一种“新”隔离原语
Sidecar 是我们以低延迟和高可编程性隔离受信任与不受信任代码的答案。Sidecar 与 Sandbox 并行运行,同时与其保持隔离,为受信任软件提供一个位置来注入凭证、代理流量、脱敏数据、运行 harness 逻辑或观察 agent,而无需让每个操作都跨越远程服务边界。
该模式从现有设计中汲取灵感,例如 Kubernetes sidecar 容器或 Datadog Agent:与主应用程序一起运行的小型专用容器,以提供支持功能。Sidecar 将同样的理念应用于 agent 基础设施,并具备在容器之间建立信任边界所需的隔离性。
隔离:Sidecar 与主 Sandbox 之间采用与独立 Sandbox 相同的隔离边界进行隔离——gVisor 或 VM,具体取决于你传给 `Sandbox.create()` 的运行时。这意味着 agent 生成的代码可以在主 Sandbox 中运行,而凭证、代理、harness 逻辑或其他受信任操作则在 agent 无法直接访问的 Sidecar 中运行。
延迟:由于容器运行在同一主机上,它们之间的通信保持本地。主 Sandbox 及其 Sidecar 通过基于 TCP/UDP 的内部桥接网络连接,每个容器都可通过名称访问。原本需要从 Sandbox 到远程控制平面的工具调用,可以由运行在其旁边的 Sidecar 处理,从而避免在执行密集型 agent 循环中累积的网络往返。我们的内部基准测试显示,Sandbox 与其 Sidecar 之间的通信至少比同一区域内独立 Sandbox 之间的通信快 3 倍。
| Sidecar | 独立 Sandbox(HTTPS) | |
|---|---|---|
| 每次调用传输,p50 | 0.58ms | 2.6ms |
| 每次调用传输,p99 | 1.4ms | 44ms |
| 100 次调用,总时间 | 0.6s | 1.2s |
创建:Sidecar 通过 Modal SDK 动态创建,因此你可以在运行时启动所需的受信任服务,而不必预先定义固定拓扑。Sandbox 内运行的代码无法创建或修改它们。
资源:Sandbox 和 Sidecar 共享 CPU 和内存资源,这使得使用 Sidecar 比在多个 Sandbox 中运行进程更具成本效益。单个 Sandbox 最多可运行 250 个 Sidecar。
网络策略:每个 Sidecar 都有自己的出站网络策略,独立于主 Sandbox,你可以强制 Sandbox 的出站流量通过代理 Sidecar。
生命周期:Sidecar 可以在 Sandbox 生命周期的任意时刻终止和替换,其文件系统可以被快照,并用于启动另一个 Sandbox 或 Sidecar。终止 Sandbox 会停止其所有 Sidecar。
Sidecar 实战:在 Ramp 构建自定义出口代理
Ramp 的后台编码代理 Inspect 编写了 Ramp 所有已合并拉取请求的 75% 以上,每个会话都在自己的 Modal Sandbox 中运行。Ramp 在 Sidecar 之上构建了自己的自定义出口代理,与每个 Inspect Sandbox 并排运行,以监控和控制代理的出站流量。
“我们需要确切知道我们的编码代理正在访问什么,并能够在它访问不该访问的内容时阻止它。Sidecar 让我们能够在代理旁边运行自己的出口代理,使用自己的规则。我们可以强制出站流量通过代理,这样就没有任何东西能绕过它,而且由于它在同一主机上,这不会给我们带来额外的网络跳数。”——Zach Bruggeman,Ramp 首席软件工程师
开始使用
Sidecar 现已推出 Beta 版,有关如何开始使用以及已知限制的更多详细信息,请参阅我们的文档。
我们有意将 Sidecar 设计为一个灵活的构建模块,但为了帮助你入门,我们也为一些特定用例编写了示例:
不过,我们预计最有趣的用例将是那些我们尚未想到的。所以,如果你用 Sidecar 构建了什么,我们很想听听!
来源:Modal Blog · modal.com