--- title: 隔离与放置 description: 谁能跑在谁上面、沙箱能连到哪,以及平台会拒绝什么。 --- # 隔离与放置 四个彼此独立的控制,各管一件事。把它们混为一谈,多租户部署就会出现"某个租户的沙箱 跑在另一个租户机器上"。 ## 一、放置按租户限定 每个 worker 带一个工作区,每次创建带一个租户 —— 租户来自**发起请求的凭据**,不是 请求体。 ``` 沙箱(租户=A) → worker(租户=A) ✓ 沙箱(租户=A) → worker(租户=B) ✗ 永不调度 沙箱(租户=A) → worker(租户="") ✓ 自托管机队,故意不限定 ``` 这条规则在调度器里,所以对每一条创建路径都生效:原生 API、E2B 面,以及崩溃后恢复的 重新投递。 ## 二、worker 角色只能做两件事 worker 用 join token(`jn_…`)认证,拿到的角色只够到两条路由:隧道握手,和它自己的 心跳。它不能列机队、不能读沙箱、不能签发任何东西,其它一律 `403`。 这很重要,因为 join token 会发到一台你未必完全信任的机器上 —— 客户的 VM、外包的 笔记本。被攻陷的 worker 能跑沙箱,但看不到你部署的其余部分。 ## 三、出网是策略,不是指望 沙箱可以带白名单创建。在 Docker worker 上,这是**结构性**执行:每个沙箱一个没有出口 的内部网络,加一个挂在普通网络上的出网代理 sidecar。沙箱只挂在内部网络上,所以除了 代理它没有别的路。 ```json {"allowed_domains": ["pypi.org", "github.com"]} ``` 策略在**容器创建时**生效。对运行中的沙箱设置,只是记录下来给下一次创建用,无法就地 改造网络。细节与权衡见[出网策略](/zh/egress)。 ## 四、权限闸门(agent 与员工电脑模式) 在 agent 模式下,沙箱是某个真人的电脑,问题就变了:不是"这个容器能连到哪",而是 "这个智能体能对我的文件做什么"。那是一套六分支的决策引擎 —— 硬锁、强制拒绝、工作 目录、永久授权、会话授权、然后询问 —— 每次决策都写进审计日志,底下还可以叠一层操作 系统沙箱(Linux 的 `bwrap`、macOS 的 `seatbelt`),在内核层面执行同样的答案。 它是可选的(`-permission-mode prompt|strict`),因为在一次性的沙箱上加它只会多出 一堆弹窗。 ## 平台会拒绝什么 拒绝是特性。下面每条都是故意的: | 请求 | 回答 | 为什么 | |---|---|---| | 在无机队具备出网能力时请求策略 | `409 worker capability unavailable` | 另一种做法是给你一个"号称被墙住、其实没有"的沙箱 | | 超过工作区并发沙箱上限的创建 | 准入闸门返回 `403` | 闸门在创建的唯一入口上,任何入口都绕不过 | | member 想删 worker 或签发 key | `403 owner_required` | 花钱和授权属于工作区 owner | | 用名字访问别的租户的沙箱 | `404` | 与"不存在"不可区分,这是故意的 | ## 隔离做不到什么 - **不是虚拟机边界。** 同一 worker 上的两个沙箱共享内核。需要硬件级隔离,就给工作区 分配专属 worker(或专属云主机)。 - **不是资源保证。** `cpu_cores` 和 `memory_mb` 是调度提示;容器限额是 Docker 的, 一台繁忙的 worker 会拖慢上面的每个沙箱。 - **挡不住 worker 本身。** worker 跑 Docker,能看到它承载的每个容器。这就是 join token 被限定作用域和时效、以及"客户自己的硬件是最强租户边界"的原因。 ## 下一步 - [出网策略](/zh/egress) —— 策略格式与执行方式。 - [Worker 与隧道](/zh/workers) —— 能力位与租户字段。