给你的 AI Coding Agent 上个笼子:Linux 下用 Bubblewrap 沙箱隔离

我这两天刷Hacker News,一个帖子让我愣了几秒——”An AI agent deleted our production database. The agent’s confession is below”。点进去一看,评论区吵翻了,有人说活该,有人说是剧本,但大部分人其实心里都清楚:这事儿早晚会烂大街。

AI coding agent 这东西,好用是真™好用。Claude Code、Cursor、Copilot 这一票工具,写起代码来比我带过的三年经验的小朋友还利索。但问题也出在这儿——你给了它 shell 权限,它就真以为自己是 root。

上周我也差点翻车。让 Claude Code 帮我重构一个目录结构,结果它直接把老目录 rm 了,git 都救不回来那种(因为我忘了 commit)。那之后我花了两天研究怎么给 AI agent 上笼子,最后发现 Linux 上最趁手的方案不是什么高大上的虚拟机,而是一个被很多人忽略的老工具——**bubblewrap**。

## 为什么要用 bubblewrap 而不是 Docker

Docker 当然可以,但你每次跑 agent 都要 build image、挂载 volume、等容器启动。开发环境里一天要跑几十次 agent,Docker 那套太重了。而且 Docker 默认网络隔离太彻底,agent 要连 API、要起本地服务给你调试,网络配置起来烦得要死。

bubblewrap(简称 bwrap)是 Flatpak 底层用的沙箱工具,只依赖 Linux 内核的 user namespace 和 cgroup 能力。它没有 daemon、没有 image 层、不需要网络配置——直接把你当前的文件系统用 bind mount 的方式”借”给沙箱进程用。

我的需求很简单:
– agent 只能读写当前项目目录
– 能正常访问网络(API + 本地调试)
– 系统工具链要齐全(node、python、gcc 这些)
– 不能碰 ~/.ssh、~/.aws 这些敏感目录
– 启动要快,快得像没跑沙箱一样

bwrap 完美满足。

## 安装

Ubuntu/Debian 直接 apt:

“`bash
sudo apt install bubblewrap
“`

Arch 系:

“`bash
sudo pacman -S bubblewrap
“`

完事。整个 binary 不到 200KB,不需要启动任何服务。

## 写一个沙箱脚本

以 Claude Code 为例,我写了个 `sandbox-claude.sh`:

“`bash
#!/bin/bash

# 先把 claude 的配置文件读进来,不让它写回硬盘
exec 3<$HOME/.claude.json exec /usr/bin/bwrap \ --tmpfs /tmp \ --dev /dev \ --proc /proc \ --hostname sandbox --unshare-uts \ --ro-bind /bin /bin \ --ro-bind /lib /lib \ --ro-bind /lib64 /lib64 \ --ro-bind /usr/bin /usr/bin \ --ro-bind /usr/lib /usr/lib \ --ro-bind /etc/ssl/certs /etc/ssl/certs \ --ro-bind /etc/resolv.conf /etc/resolv.conf \ --ro-bind /etc/hosts /etc/hosts \ --ro-bind /etc/nsswitch.conf /etc/nsswitch.conf \ --ro-bind $HOME/.bashrc $HOME/.bashrc \ --ro-bind $HOME/.gitconfig $HOME/.gitconfig \ --ro-bind $HOME/.local $HOME/.local \ --bind $HOME/.claude $HOME/.claude \ --file 3 $HOME/.claude.json \ --bind "$PWD" "$PWD" \ claude --dangerously-skip-permissions "$@" ``` 解释几个关键点: **`--ro-bind` 只读挂载**:系统工具链全部只读挂进去,agent 改不了它们。`~/.gitconfig` 也是只读,agent 可以读你的 git 配置来 commit,但改不了配置本身。 **`--bind` 读写挂载**:只给了两个——当前工作目录和 claude 的 session 目录。项目文件可读写,但 ~/.ssh、~/.aws、~/Documents 这些 agent 碰都碰不到。 **`--file 3` 注入配置文件**:把 `$HOME/.claude.json` 通过 fd 3 注入沙箱,agent 能读取但任何修改都不会写回宿主机。下次启动还是干净的配置。 **`--tmpfs /tmp`**:临时文件全跑在内存里,重启即焚。 ## 日常使用 ```bash # 在项目目录里正常跑 cd ~/projects/my-app ./sandbox-claude.sh "帮我重构 user 模块,提取 Service 层" # 让 agent 启动开发服务器 ./sandbox-claude.sh "添加一个 /health 端点并启动服务测试" ``` 因为网络是通的,agent 可以在沙箱里起一个 FastAPI 服务跑在 8000 端口,你在宿主机浏览器直接访问 `localhost:8000` 就能调试。体验和没沙箱一模一样。 ## 效果验证 跑一下看看隔离效果: ```bash # 启动沙箱后试试读 SSH key ./sandbox-claude.sh > cat ~/.ssh/id_rsa
cat: /root/.ssh/id_rsa: No such file or directory
“`

再试试写系统目录:

“`bash
> touch /etc/test
touch: cannot touch ‘/etc/test’: Read-only file system
“`

完美。

## 进阶:项目专用 API Key

还有个很容易被忽视的问题——agent 在沙箱里虽然安全了,但你的 API Key 要是被它写进代码里 commit 了,一样尴尬。

我给每个项目单独配 API Key,用 `.env` 文件管理:

“`bash
# .env.claude
ANTHROPIC_API_KEY=sk-ant-项目专用-key
“`

然后在沙箱脚本里注入这个环境变量:

“`bash
exec /usr/bin/bwrap \
–setenv ANTHROPIC_API_KEY “sk-ant-项目专用-key” \
… 其他参数 …
“`

这样即使 agent 把 key 写进了代码,泄露的也只是一个项目的 key,不是你的主 key。在 API 管理后台限制这个 key 只能访问特定仓库,风险降到最低。

## 需要注意的坑

1. **bwrap 需要 user namespace 支持**。大多数云服务器默认开着,但某些 Docker 容器里被禁了。用 `unshare –user true` 测试。

2. **/dev 挂载是共享的**。bwrap 默认把宿主机的 /dev 挂进去,意味着 agent 理论上可以操作其他进程的 ptrace。如果用 `–dev /dev` 觉得不放心,可以改用 `–proc /proc –dev /dev` 组合或者自己 mknod。

3. **网络逃逸风险**。agent 有网络访问,如果宿主机跑了 ssh server,agent 可以 ssh localhost 逃逸。更严格的方案是用 network namespace 隔离,但日常开发这样已经够了。

4. **macOS 用户别想了**。bwrap 只跑在 Linux 上。macOS 上可以用 `sandbox-exec`,但那是另一套语法了。

## 写在最后

AI agent 的能力越强,它闯祸的能力也越强。前几天的 Hacker News 上有个帖子问 “How are you sandboxing AI agents and developer CLIs?”,回复里五花八门——有人裸奔(YOLO),有人买了远程开发机,还有人直接在 KVM 虚拟机里跑 agent。

bwrap 这个方案不算完美,但它是典型的”够用就行”。200KB 的 binary、零配置、启动瞬间完成、隔离效果可靠。对于每天要和 AI agent 打交道的开发者来说,花半小时配好沙箱,比赌 agent 不会手滑 rm -rf 要靠谱得多。

毕竟,trust but verify。agent 写的代码你可以 review,但是 agent 跑的命令可没经过 review——这句话在 HN 那帖子的评论区里被顶了三百多次,不是没有道理。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注