From 4a5b21a69e73b5d223fc76562767eebb1fda393b Mon Sep 17 00:00:00 2001 From: wunianxiao Date: Mon, 22 Jun 2026 11:51:05 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E4=B8=A4=E5=B1=82=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E8=BE=B9=E7=95=8C=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 授权边界(统一审批)+ 隔离边界(Docker 一次性容器)+ 审计 的设计、实现与验证记录。 --- docs/SECURITY_BOUNDARIES.md | 143 ++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 docs/SECURITY_BOUNDARIES.md diff --git a/docs/SECURITY_BOUNDARIES.md b/docs/SECURITY_BOUNDARIES.md new file mode 100644 index 0000000..1e45b18 --- /dev/null +++ b/docs/SECURITY_BOUNDARIES.md @@ -0,0 +1,143 @@ +# 两层安全边界设计 + +> 审批决定"能不能做",Docker 限制"做坏了能坏到哪里",审计回答"谁让系统新增或修改了什么能力"。 + +## 架构 + +``` +LLM 调用工具 + → registry.dispatch(name, params, user_id, approved) + → load spec + validate params + → 【授权边界】if high_risk && !approved: 统一审批(不依赖消息类型) + → 【隔离边界】按 sandbox.profile 选择执行方式: + - local : 本地 spawn(env_clear + 白名单注入) + - stdio : docker run ias-stdio-runner (无网络、只读根) + - network : docker run ias-network-runner(联网、资源限制) + - builder : docker run ias-tool-builder (离线编译,仅 tool_manager) + → stdin 传 envelope → stdout 读 JSON → 超时 kill → 容器销毁 +``` + +## 第一层:统一工具级审批(授权边界) + +**位置**:`src/tools/executor.rs` `execute_loop()` 入口 + +高风险工具在 **spawn 之前** 必须获得用户确认,与工具后续输出的消息类型(`result`/`http`/`db`)无关。 + +```rust +if spec.is_high_risk() && !approved { + // 发送确认码 → 等待用户回复 → Approved/Rejected/Expired +} +``` + +**修复的漏洞**:原实现审批只在 `http`/`db` 消息分支触发,`stdio → result` 可绕过。`tool_manager`(high risk)直接输出 result 即可零确认执行。 + +## 第二层:一次性 Docker 容器(隔离边界) + +### 三类基础镜像 + +| 镜像 | 用途 | 网络 | 文件系统 | +|------|------|------|----------| +| `ias-stdio-runner` | 普通 stdio 工具 | none | 只读根 + tmpfs /tmp | +| `ias-network-runner` | 需联网的工具(预留) | default | 只读根 + tmpfs /tmp | +| `ias-tool-builder` | tool_manager 编译 Rust 工具 | none | 可写 /work(bind mount) | + +构建:`docker/build-images.sh` + +### 容器安全基线 + +所有容器统一: +- `--rm` 一次性,用完销毁 +- `--cap-drop ALL` 丢弃所有 Linux capability +- `--security-opt no-new-privileges` 禁止提权 +- `--memory` / `--cpus` / `--pids-limit` 资源限制 +- 只挂载工具二进制(readonly)+ tmpfs /tmp +- 不挂载项目根目录、不挂载 docker.sock +- env 按白名单注入(`env_clear` + spec.env) + +### 沙箱配置(spec) + +```yaml +sandbox: + profile: stdio # local | stdio | network | builder + network: none # none | default + memory: 256m + cpus: "0.5" + pids_limit: 64 + read_only: true +``` + +默认 `profile: local`(不启用容器)。现有非 tool_manager 工具均设为 `profile: stdio`。 + +### 启用沙箱 + +```bash +export IAS_DOCKER_SANDBOX=1 # 工具执行走一次性容器 +export IAS_DOCKER_BUILDER=1 # tool_manager 编译走 builder 容器 +``` + +未设置时退回本地执行(仍保留 env_clear + 白名单注入)。 + +### builder 容器特殊处理 + +`--cap-drop ALL` 丢掉 `CAP_DAC_OVERRIDE`,root 无法写 bind mount 的非 root 目录。 +解法:builder 容器以宿主 `uid:gid` 运行(`--user`),自然能写自己的目录。 +镜像内 `CARGO_HOME=/tmp/cargo` 预缓存 serde_json 并 `chmod 777`,任意 uid 可用。 +编译加 `--offline`,确保 `--network none` 下不尝试联网。 + +## tool_manager 加固 + +| 措施 | 实现 | +|------|------| +| 禁止自改 | `RESERVED_NAMES` 包含 `tool_manager`,禁止 create/update/build | +| 强制 high risk | `spec_yaml` 忽略调用方 risk_level,一律写 `high` | +| 审计日志 | 每次调用追加 `tools/.tool_audit.log`(ts/uid/action/tool/result) | +| 构建超时 | `timeout 180s` 包裹 cargo build | +| 失败清理 | 构建失败删除残留旧二进制,避免 reload 后调用旧版本"假成功" | +| 离线编译 | `IAS_DOCKER_BUILDER=1` 时在 builder 容器内 `--offline` 编译 | + +## 结构化结果 + +`executor` 返回 `ToolRunOutcome` 枚举替代裸字符串: + +```rust +enum ToolRunOutcome { + Ok(String), + Err { kind: ToolErrorKind, message: String }, +} +``` + +`daemon` 据此判断是否 reload(tool_manager 成功后重载注册表), +替代原 `is_tool_error()` 的中文前缀字符串匹配。 + +## 审批并发修复 + +`ApprovalManager::clean_expired()` 两阶段加锁: +收集过期 `code_hash` → 更新 DB → 重新加锁按 `code_hash` 定位删除。 +不依赖快照 index,避免并发回复导致 index 错位误删未过期审批。 + +## 验证 + +| 场景 | 结果 | +|------|------| +| tool_manager update 自身 | ❌ 拒绝(保留名) | +| create_tool risk_level=low | spec 强制 high | +| datetime 本地执行 | +08:00(宿主时区) | +| datetime Docker 执行 | +00:00(容器 UTC,证明确实隔离) | +| 容器残留检查 | 无(--rm 生效) | +| builder 容器编译 serde_json | ✅ 离线成功 | +| cargo test | 25 passed | + +## 实施状态 + +| # | 步骤 | 状态 | +|---|------|------| +| 1 | 统一工具级审批 | ✅ | +| 2 | 禁止 tool_manager 自改 | ✅ | +| 3 | 强制生成工具 high risk | ✅ | +| 4 | env_clear 环境白名单 | ✅ | +| 5 | 修 clean_expired 并发 | ✅ | +| 6 | 三类 Docker 镜像 + sandbox spec | ✅ | +| 7 | stdio 工具迁移到一次性容器 | ✅ | +| 8 | network 工具迁移 | ⏸ 保持 stdio profile(工具走宿主代理联网,最小权限不给直接网络) | +| 9 | tool_manager build 迁移到 builder 容器 | ✅ | +| 10 | 结构化结果替换 is_tool_error | ✅ |