Claude Code にはエージェントに強い許可を与えながら安全に動かすためファイルシステムやネットワークを分離する Sandboxing の機能があり、Linux ではこれに bubblewrap を用いている。 bubblewrap は CLONE_NEWNET や CLONE_NEWPID などのフラグを渡して clone(2) システムコールを呼び出すことで 各 namespace を分離する。
$ sudo apt install bubblewrap
$ bwrap \
--ro-bind /usr /usr \
--ro-bind /lib /lib \
--ro-bind /lib64 /lib64 \
--unshare-net \
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
$ bwrap \
--ro-bind /usr /usr \
--ro-bind /lib /lib \
--ro-bind /lib64 /lib64 \
--proc /proc \
--unshare-pid \
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
1000 1 0.0 0.0 3584 1420 ? S+ 07:14 0:00 bwrap --ro-bind /usr /usr --ro-bind /lib /lib --ro-bi
1000 2 0.0 0.0 8284 4096 ? R+ 07:14 0:00 ps aux
Docker と異なりデーモンを動かしてやり取りする必要がなく、小さいオーバーヘッドでプロセスを実行できる。
$ time for i in {1..100}; do
echo "test" > /dev/null
done
real 0m0.022s
user 0m0.019s
sys 0m0.003s
$ time for i in {1..100}; do
bwrap --ro-bind /usr /usr --ro-bind /lib /lib --ro-bind /lib64 /lib64 --unshare-all echo "test" > /dev/null
done
real 0m0.374s
user 0m0.125s
sys 0m0.095s
$ time for i in {1..100}; do
docker run --rm alpine echo "test" > /dev/null
done
real 0m1.126s
user 0m0.254s
sys 0m0.158s
Sandbox Runtime (srt) は bwrap --unshare-net で外部への通信を遮断しつつ、socat コマンドで Sandbox の localhost:{port} を socket に転送するようにして HTTP(S)_PROXY などに localhost:{port} を設定することで、ホストのプロキシサーバーを通って外に出られるようにする。このサーバーでallowed/deniedDomain によるフィルタを行う。
$ npm install -g @anthropic-ai/sandbox-runtime
$ sudo apt install ripgrep socat
$ srt --version
1.0.0
$ cat ~/.srt-settings.json
{
"filesystem": {
"denyRead": [],
"allowWrite": ["."],
"denyWrite": []
},
"network": {
"allowedDomains": ["example.com"],
"deniedDomains": []
}
}
$ SRT_DEBUG=1 srt curl "sambaiz.net"
...
[SandboxDebug] HTTP proxy listening on localhost:44889
[SandboxDebug] SOCKS proxy listening on 127.0.0.1:44311
[SandboxDebug] Starting HTTP bridge: socat UNIX-LISTEN:/tmp/claude-http-59898d4a7ef502ee.sock,fork,reuseaddr TCP:localhost:44889,keepalive,keepidle=10,keepintvl=5,keepcnt=3
[SandboxDebug] Starting SOCKS bridge: socat UNIX-LISTEN:/tmp/claude-socks-59898d4a7ef502ee.sock,fork,reuseaddr TCP:localhost:44311,keepalive,keepidle=10,keepintvl=5,keepcnt=3
...
[SandboxDebug] No matching config rule, denying: sambaiz.net:80
[SandboxDebug] HTTP request blocked to sambaiz.net:80
Connection blocked by network allowlist[SandboxDebug] Sent SIGTERM to HTTP bridge process
[SandboxDebug] Sent SIGTERM to SOCKS bridge process
なお、Claude Code の /sandbox は現状 Windows 未対応で WSL2 でも動かない。
> /sandbox
⎿ Error: Sandboxing is currently only supported on macOS and Linux
ただ srt コマンドで動かすことはできる。Claude Code を動かすのに必要なドメインを許可する必要がある。
$ cat ~/.srt-settings.json
{
"filesystem": {
"denyRead": [
"~/.ssh",
"~/.aws"
],
"allowWrite": [
".",
"/tmp",
"~/.claude.json",
"~/.claude"
],
"denyWrite": [
".env"
]
},
"network": {
"allowedDomains": [
"api.anthropic.com",
"claude.ai",
"statsig.anthropic.com",
"sentry.io"
],
"deniedDomains": []
},
"ignoreViolations": {
"*": [
"/usr/bin",
"/System"
]
}
}
$ srt "claude --dangerously-skip-permissions --print \"run a command: curl sambaiz.net\""
The curl command attempted to connect to sambaiz.net but the connection was blocked by a network allowlist. This means that network access to this domain is restricted in the current environment.
The response shows that only 39 bytes were received before the connection was blocked, suggesting some initial data was retrieved but the full content couldn't be fetched due to network restrictions.