Hotdry.

Article

Rust 实现的 Goose 代理框架:插件沙箱与权限模型实战

深入 block/goose 的 Rust 插件系统,给出可落地的沙箱隔离、权限分级与监控参数清单。

2025-12-11ai-systems

本地 AI 代理一旦获得 “写文件、起容器、调 API” 的能力,就等同于在开发者电脑里放了一位 7×24 的初级实习生。Goose 把这位实习生的合同开源了:Rust 写的核心,插件化的技能,任何 LLM 都能指挥。好处是 “写完即跑”,风险是 “跑错即毁”。本文把官方文档没细说的沙箱与权限模型拆开,给你一份可直接抄进 CI 的落地清单。

一、Goose 的权限边界长什么样?

官方把能力拆成三层:

  1. Agent Runtime(crates/goose):纯 Rust,负责对话状态、工具调用、插件生命周期。默认无系统调用权限,所有 “动手” 动作必须落进插件。
  2. Extension(插件):独立进程,通过 MCP(Model Context Protocol)与 Runtime 通信。插件可以声明自己需要哪些 “能力”(capabilities),Runtime 只做白名单校验。
  3. MCP Server:把能力翻译成具体协议,例如 filesystem、docker、github。Server 本身可以用任意语言实现,Goose 仓库里提供了 Go、Python、TypeScript 三套模板。

一句话:Runtime 不直接碰系统,插件想碰系统必须先声明,用户侧可一键吊销。

二、沙箱的三种落地形态

  1. Native 沙箱(默认)

    • 插件进程用 Rust 的 tokio::process 拉起,自带 --sandbox 参数时,自动加 seccomp-BPF 过滤器,屏蔽 300+ 系统调用(源码见 crates/goose/src/sandbox/seccomp.rs)。
    • 文件系统只挂载工作区子目录,父目录通过 open_tree + move_mount 做只读绑定,防止 ../../../ 逃逸。
    • 网络命名空间隔离,仅允许 Unix Domain Socket 与 Runtime 通信,TCP/UDP 默认全关。
  2. Docker 沙箱(CI 推荐)

    • 官方镜像 ghcr.io/block/goose-mcp:latest 自带非 root 用户(uid=1000),入口脚本通过 gosu 降权。
    • 默认 --cap-drop=ALL --cap-add=DAC_OVERRIDE,只保留修改文件权限的能力;--security-opt=no-new-privileges 禁止提权。
    • 通过 docker run --read-only --tmpfs /tmp:rw,noexec,nosuid,size=100m 把可写目录限制在内存盘,重启即销毁。
  3. Firecracker microVM(重度隔离)

    • 对敏感仓库(含生产密钥)可在 .goose/config.yaml 里开启 vm = "firecracker",Goose 会调用 /usr/bin/jailer 启动 128 MB 微虚拟机,启动时间 180 ms,IO 性能下降 8%。
    • 虚拟机内只挂 virtio-fs 的 repo 目录,其余文件系统为空镜像,kernel 用官方精简 config,只保留 9 个系统调用。

三、用户可调的 7 个关键参数

把下面配置写进 $HOME/.goose/config.yaml,可在团队内部统一基线:

extensions:              # 插件白名单,不在列表的即使安装也不加载
  allowlist:
    - id: filesystem
      max_permission: read-write  # 还可 read-only、deny
    - id: docker
      max_permission: deny        # 完全禁用

sandbox:
  level: docker                # native | docker | firecracker
  docker_image: ghcr.io/block/goose-mcp:1.16.1
  cpu_limit: 

ai-systems