Linux 中的 AI 代理沙箱化
Source: Hacker News
沙箱化
标准的解决方案是对代理进行沙箱化——可以在远程机器上(exe.dev、sprites.dev、daytona.io),也可以在本地通过 Docker 或其他虚拟化机制实现。
在 Linux 上的轻量级替代方案是 bubblewrap,它利用 Linux 内核特性(如 cgroups 和用户命名空间)来限制(监禁)进程。
事实证明,bubblewrap 是对 AI 代理进行轻量级沙箱化的良好方案。以下是我个人对这种方案的需求:
- 模拟我常用的 Linux 开发机器环境(我不想管理多个开发环境)。
- 限制对除当前项目所需信息之外的任何信息的访问。
- 仅对当前项目拥有写入权限。
- 直接操作项目的文件/文件夹,这样我可以轻松地在 IDE 中检查或修改同一文件,或自行运行代码。
- 网络访问——既能连接 AI 提供商并搜索互联网,又能启动服务器供我连接使用。
bubblewrap 和 Docker 并非硬化的安全隔离机制,但这对我来说已经足够。我并不真正担心以下风险:
- 通过零日 Linux 内核漏洞逃逸。
- 隐蔽的侧信道通信。
- 从当前项目(包括项目专用的访问密钥)中泄露数据。
- 破坏代码库(代码通过
git管理,并在 GitHub 或其他地方备份)。
另一种做法是通过创建项目专用的 API 密钥来限制潜在损害,这样即使密钥泄露,影响范围也会最小化。
Source:
实际操作
下面是我的 bubblewrap 沙箱脚本示例:
#!/usr/bin/bash
exec 3<$HOME/.claude.json
exec /usr/bin/bwrap \
--tmpfs /tmp \
--dev /dev \
--proc /proc \
--hostname bubblewrap --unshare-uts \
--ro-bind /bin /bin \
--ro-bind /lib /lib \
--ro-bind /lib32 /lib32 \
--ro-bind /lib64 /lib64 \
--ro-bind /usr/bin /usr/bin \
--ro-bind /usr/lib /usr/lib \
--ro-bind /usr/local/bin /usr/local/bin \
--ro-bind /usr/local/lib /usr/local/lib \
--ro-bind /opt/node/node-v22.11.0-linux-x64/ /opt/node/node-v22.11.0-linux-x64/ \
--ro-bind /etc/alternatives /etc/alternatives \
--ro-bind /etc/resolv.conf /etc/resolv.conf \
--ro-bind /etc/profile.d /etc/profile.d \
--ro-bind /etc/bash_completion.d /etc/bash_completion.d \
--ro-bind /etc/ssl/certs /etc/ssl/certs \
--ro-bind /etc/ld.so.cache /etc/ld.so.cache \
--ro-bind /etc/ld.so.conf /etc/ld.so.conf \
--ro-bind /etc/ld.so.conf.d /etc/ld.so.conf.d \
--ro-bind /etc/localtime /etc/localtime \
--ro-bind /usr/share/terminfo /usr/share/terminfo \
--ro-bind /usr/share/ca-certificates /usr/share/ca-certificates \
--ro-bind /etc/nsswitch.conf /etc/nsswitch.conf \
--ro-bind /etc/hosts /etc/hosts \
--ro-bind /etc/ssl/openssl.cnf /etc/ssl/openssl.cnf \
--ro-bind /usr/share/zoneinfo /usr/share/zoneinfo \
--ro-bind $HOME/.bashrc $HOME/.bashrc \
--ro-bind $HOME/.profile $HOME/.profile \
--ro-bind $HOME/.gitconfig $HOME/.gitconfig \
--ro-bind $HOME/.local $HOME/.local \
--bind $HOME/.claude $HOME/.claude \
--bind $HOME/.cache $HOME/.cache \
--file 3 $HOME/.claude.json \
--bind "$PWD" "$PWD" \
claude --dangerously-skip-permissions "$@"
如果这看起来相当特立独行,那是因为它本来就是这样。与其使用通用规则,我反复尝试 bwrap,直到找到我的系统所需的最小配置。
一些有趣的细节
/tmp、/proc和/dev会被bwrap自动处理。- 我以与本机相同的路径绑定挂载(即暴露)文件和目录,所以文件位置或项目路径没有区别。
- 我没有暴露整个
/etc,只挂载了必需的最小集合。 $HOME/.claude.json的内容会被注入到沙箱中,因此对该文件的任何更改都不会影响真实文件。$HOME/.claude/目录是 读写 映射的,允许 Claude 保存会话数据。/opt/node/node-v22.11.0-linux-x64/是我自定义的 Node.js 安装位置。- 更改主机名可以轻松区分宿主机和沙箱。
我可能会根据需要微调脚本,但这对我来说已经是一个相当稳固的起点。
如何自定义
如果你想将其适配到其他 AI 代理或你的系统,我的建议是修改脚本,使其运行 bash,然后手动启动你的代理,观察出现的问题并相应地进行调整。
一个有用的命令是 strace,它可以跟踪文件访问系统调用,让你看到需要哪些文件:
strace -e trace=open,openat,stat,statx,access -o /tmp/strace.log codex
检查日志以找出所需的文件,并根据需要进行绑定挂载。