Modal 推出 Sidecars,为 Sandboxes 提供低延迟信任边界
Sidecars: A low-latency trust boundary for Sandboxes
Modal 推出 Sidecars(Beta),一种与主 Sandbox 同宿主运行但隔离的可信容器,用于在可信与不可信代码之间建立安全边界。
原文给出 Sidecar 的隔离机制、3 倍通信提速和 Ramp 实例,读者可据此评估替代现有 egress 控制的可行性。
在 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 通过 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 官方工程博客 · modal.com