refactor(sandbox): 长期容器 + docker exec 替代一次性 docker run
容器策略从"每次 docker run 一次性容器"改为"长期容器 + docker exec": - 统一产物目录 tools/bin/:build.sh 和 tool_manager 编译后复制产物到 此目录,registry 解析路径优先用 tools/bin/<tool>。 - 长期容器 ias-sandbox:daemon 启动时 ensure(已运行则复用), tools/bin 只读挂载到 /tools,无网络/只读根/cap-drop ALL/资源限制。 - docker exec 调用:工具执行改为 docker exec -i ias-sandbox timeout -k 5 <secs> /tools/<name>,省去容器创建开销。 timeout -k 5 确保超时 SIGTERM→SIGKILL,无孤儿进程。 - 新增 src/tools/sandbox.rs:ensure_container + build_exec_cmd。 - executor 删除 build_docker_cmd/sandbox_enabled,docker 分支改用 sandbox::build_exec_cmd。 - env 按 spec 白名单 -e 注入(容器启动时仅有 PATH)。 验证:本地执行 hostname=debian,docker exec hostname=容器ID, 证明确实走长期容器 exec;25 测试通过。
This commit is contained in:
@@ -31,7 +31,7 @@ if spec.is_high_risk() && !approved {
|
||||
|
||||
**修复的漏洞**:原实现审批只在 `http`/`db` 消息分支触发,`stdio → result` 可绕过。`tool_manager`(high risk)直接输出 result 即可零确认执行。
|
||||
|
||||
## 第二层:一次性 Docker 容器(隔离边界)
|
||||
## 第二层:长期沙箱容器 + docker exec(隔离边界)
|
||||
|
||||
### 适用范围(按威胁模型精确化)
|
||||
|
||||
@@ -44,12 +44,41 @@ http/db 类工具的子进程是"瘦壳"——危险操作(联网、DB 读写
|
||||
| tool_manager 产出的工具 | ✅ stdio 容器 | 含 LLM 提供的 rust_code,不受信任 |
|
||||
| tool_manager 编译 | ✅ builder 容器 | cargo 执行任意 build script/proc macro |
|
||||
|
||||
### 统一产物目录
|
||||
|
||||
所有工具二进制统一收集到 `tools/bin/`(`build.sh` 编译后复制,`tool_manager` 编译后也复制)。
|
||||
registry 解析路径时优先用 `tools/bin/<tool>`。
|
||||
|
||||
### 长期容器模式
|
||||
|
||||
daemon 启动时创建常驻容器 `ias-sandbox`,`tools/bin/` 只读挂载到 `/tools`:
|
||||
|
||||
```
|
||||
docker run -d --rm --name ias-sandbox \
|
||||
--network none --cap-drop ALL --security-opt no-new-privileges \
|
||||
--read-only --memory 512m --cpus 1 --pids-limit 128 \
|
||||
--mount type=bind,source=tools/bin,target=/tools,readonly \
|
||||
--mount type=tmpfs,target=/tmp \
|
||||
ias-stdio-runner sleep infinity
|
||||
```
|
||||
|
||||
工具调用通过 `docker exec` 在容器内执行(省去每次 `docker run` 的创建开销):
|
||||
|
||||
```
|
||||
docker exec -i -e KEY=VAL ias-sandbox timeout -k 5 <secs> /tools/<name> --command <cmd>
|
||||
```
|
||||
|
||||
- 容器已运行则复用,daemon 重启不重建
|
||||
- `timeout -k 5` 超时 SIGTERM、5s 后 SIGKILL,避免孤儿进程
|
||||
- env 按 spec 白名单 `-e` 注入(容器启动时仅有 PATH)
|
||||
- 新工具由 tool_manager 编译后复制到 `tools/bin/`,bind mount 自动可见,无需重启容器
|
||||
|
||||
### 两类基础镜像
|
||||
|
||||
| 镜像 | 用途 | 网络 | 文件系统 |
|
||||
|------|------|------|----------|
|
||||
| `ias-stdio-runner` | tool_manager 产出的不受信任工具 | none | 只读根 + tmpfs /tmp |
|
||||
| `ias-tool-builder` | tool_manager 编译 Rust 工具 | none | 可写 /work(bind mount) |
|
||||
| `ias-stdio-runner` | tool_manager 产出的不受信任工具(长期容器) | none | 只读根 + tmpfs /tmp |
|
||||
| `ias-tool-builder` | tool_manager 编译 Rust 工具(一次性容器) | none | 可写 /work(bind mount) |
|
||||
|
||||
构建:`docker/build-images.sh`
|
||||
|
||||
@@ -83,11 +112,12 @@ sandbox:
|
||||
### 启用沙箱
|
||||
|
||||
```bash
|
||||
export IAS_DOCKER_SANDBOX=1 # 工具执行走一次性容器
|
||||
export IAS_DOCKER_SANDBOX=1 # 工具执行走长期容器 docker exec
|
||||
export IAS_DOCKER_BUILDER=1 # tool_manager 编译走 builder 容器
|
||||
```
|
||||
|
||||
未设置时退回本地执行(仍保留 env_clear + 白名单注入)。
|
||||
daemon 启动时自动 ensure `ias-sandbox` 容器,失败则回退本地执行。
|
||||
|
||||
### builder 容器特殊处理
|
||||
|
||||
@@ -133,9 +163,10 @@ enum ToolRunOutcome {
|
||||
|------|------|
|
||||
| tool_manager update 自身 | ❌ 拒绝(保留名) |
|
||||
| create_tool risk_level=low | spec 强制 high |
|
||||
| tool_manager 产出工具 spec | 自动含 `sandbox: profile: stdio` |
|
||||
| datetime 本地执行 | +08:00(宿主时区,默认不套容器) |
|
||||
| tool_manager 产出工具 Docker 执行 | 容器内运行成功 |
|
||||
| tool_manager 产出工具 spec | 自动含 `sandbox: profile: stdio` + 产物复制到 `tools/bin/` |
|
||||
| datetime 本地执行 | +08:00(宿主时区,开发者工具默认不套容器) |
|
||||
| tool_manager 产出工具 docker exec | 容器内 hostname=容器ID,证明确实走长期容器 exec |
|
||||
| 容器常驻 | docker ps 可见 ias-sandbox,exec 完无孤儿进程 |
|
||||
| builder 容器编译 serde_json | ✅ 离线成功 |
|
||||
| cargo test | 25 passed |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user