enableWeakerNestedSandboxとbwrapPathでDocker内のsandboxを動かす
非特権Dockerでsandboxが動かない原因は/procのマウントです。enableWeakerNestedSandboxで何が弱まるか、PATH外のbwrapを指すbwrapPathとの使い分けを比べます。
2つの設定は何を解くのか
sandbox.enableWeakerNestedSandboxは、非特権のDockerコンテナの中でClaude CodeのLinux sandboxを動かすための設定です。sandbox.bwrapPathは、PATHの外に置いたbubblewrap(bwrap)をsandboxに使わせる設定です。名前は似ていませんが、どちらもLinuxとWSL2のbubblewrapまわりを調整するキーなので、閉じたネットワークやコンテナで運用するときに一緒に出てきます。
解く問題は別物です。
| 設定 | 解く問題 | 設定できる場所 | 既定値 |
|---|---|---|---|
enableWeakerNestedSandbox | 解く問題コンテナ内でbwrapが新しい/procをマウントできない | 設定できる場所どの設定ファイルでも可 | 既定値false |
bwrapPath | 解く問題bwrapがPATH上に無い | 設定できる場所管理設定(managed)のみ | 既定値未設定(PATH検索) |
どちらもsandboxを有効にするsandbox.enabledの上に乗るキーです。有効化そのものはsandbox.enabledの記事が扱っています。
非特権Dockerでsandboxが失敗する理由
非特権コンテナでは、bubblewrapが新しい/procファイルシステムをマウントできません。sandbox内のコマンドは次のようなbwrapエラーで失敗します。
bwrap: Can't mount proc on /newroot/proc: Operation not permittedメッセージが「Operation not permitted」で、しかもコンテナの中で出ているなら、enableWeakerNestedSandboxで解消する症状です。NixOSの権限エラーやunshareの失敗は、原因が別なので対処も違います。症状別の切り分けはNixOSのbwrapエラーとapply-seccompのsetgroups失敗にあります。
enableWeakerNestedSandboxで何が弱まるか
trueにすると、内側のsandboxは新しい/procを作らず、コンテナが持っている既存の/procをbind-mountします。これでbwrapは起動できますが、新しいマウントなら隠れるはずのプロセス情報が、sandbox内のコマンドから見えるようになります。
{
"sandbox": {
"enabled": true,
"enableWeakerNestedSandbox": true
}
}値の意味は2つだけです。
true: 既存の/procをbind-mountするfalse(既定): 新しい/procをマウントする。非特権Dockerでは動かない
弱まるのは/procの見え方です。ファイルシステムやネットワークの許可設定がそのまま消えるわけではありません。ただ、外側のコンテナがすでに隔離を担っている前提で使う設定です。コンテナ自体が特権付きだったり、ホストの/procやソケットを大きく共有していたりすると、sandboxの内側が弱くなった分を外側で補えません。
名前が似たenableWeakerNetworkIsolationはmacOS用で、効く場所がまったく違います。違いはenableWeakerNetworkIsolationの記事にまとめてあります。
設定する場所と、組織が止める方法
enableWeakerNestedSandboxはどの設定ファイルにも書けます。つまり開発者がユーザー設定から、リポジトリが.claude/settings.jsonからtrueにできます。管理側で許したくないなら、管理設定でfalseを固定します。管理設定が値を持つBoolean系のキーは、ローカルの値が無視されるためです。
sandboxを管理者が必須にしている構成(allowUnsandboxedCommands: falseかallowManagedDomainsOnly: trueが管理設定にある状態)では、扱いがもう一段厳しくなります。
| 設定を書いた場所 | true の扱い | false の扱い |
|---|---|---|
リポジトリの.claude/settings.jsonと.claude/settings.local.json | true の扱い無視される | false の扱い有効のまま |
管理設定、--settings、ユーザー設定 | true の扱い有効 | false の扱い有効 |
リポジトリ側から勝手に隔離を弱められず、falseだけは通るという非対称な作りです。この挙動はClaude Code v2.1.285以降が前提です。管理設定の全体像はClaude Code組織管理ガイドにあります。
bwrapPathでPATH外のbwrapを使う
エアギャップ環境では、パッケージマネージャーからbubblewrapを入れられないことがあります。社内で用意したコピーを/opt/admin/bwrapのような場所に置くなら、bwrapPathでその絶対パスを指します。
{
"sandbox": {
"enabled": true,
"bwrapPath": "/opt/admin/bwrap"
}
}押さえる点は4つです。
- 管理設定からだけ読まれます。ユーザー・プロジェクト・ローカルのファイルに書いても、別のバイナリを指させる経路にならないよう無視されます
- 値は絶対パスの文字列です。相対パスは捨てられ、
PATH検索に戻ります - 起動時の依存確認と、sandbox内の各コマンドを包むときの両方で、そのパスが使われます
- Linux、WSL2のみが対象です
socatを同じ要領で指すsandbox.socatPathもあり、違いはsocatPathの記事で比べています。
組み合わせるときの判断
Docker内かつエアギャップ、という環境では2つが同時に要ることがあります。ただし役割が独立しているので、症状から順に外していくと迷いません。
Linuxのsandboxが動かないときの確認順
- 1
bwrapが見つかるか
/sandboxパネルがbubblewrapの不足を示すなど、バイナリ自体が見つからないならPATHの問題です。入れ直すか、管理設定のbwrapPathで場所を教えます。 - 2
起動後に/procのエラーが出るか
Can't mount proc on /newroot/procなら、コンテナが非特権です。外側が隔離を担うと判断できる場合に限り、enableWeakerNestedSandboxをtrueにします。 - 3
それでも出るなら別の原因
Ubuntu 24.04以降の既定のAppArmorポリシーは、bubblewrapが隔離に使うユーザー名前空間の作成を止めます。
/procとは無関係な原因なので、enableWeakerNestedSandboxでは直りません。下の節の手順でbwrap用のプロファイルを足します。
Ubuntu 24.04以降でユーザー名前空間を許可する
まず制限が効いているかを確かめます。WSL2の中でも同じ確認ができます。
sysctl kernel.apparmor_restrict_unprivileged_userns0が返れば制限はなく、この手順は不要です。No such file or directoryと出る場合もキー自体が無いので不要です。1が返ったときだけ、bwrapにユーザー名前空間を許すプロファイルを置きます。
sudo tee /etc/apparmor.d/bwrap > /dev/null <<'EOF'
abi <abi/4.0>,
include <tunables/global>
profile bwrap /usr/bin/bwrap flags=(unconfined) {
userns,
include if exists <local/bwrap>
}
EOF
sudo systemctl reload apparmorこのプロファイルが対象にするのはbwrap自身だけで、bwrapがsandbox内で動かすコマンドには及びません。
/sandboxパネルのDependenciesタブは、ripgrep・bubblewrap・socat・seccompフィルターのうち、足りないものを一覧します。タブが出ないなら依存は揃っています。まずここで1の段階を確かめられます。
WSL2で試している場合は、先にWSLのバージョンも確かめます。PowerShellでwsl -l -vを実行し、Sandboxing requires WSL2と出たなら、そのディストリビューションはWSL1で動いています。WSL2へ上げるか、sandboxなしで使うかのどちらかになり、この記事の2つの設定では解決しません。ネイティブのWindowsでもsandboxは動かないため、bwrapPathを含めて対象外です。
コンテナイメージに依存と設定を焼き込む
Linux側のsandboxはbubblewrapとsocatに頼ります。Dockerfileで先に入れておけば、起動してから/sandboxで足りない依存に気づく手間が減ります。Ubuntu系のイメージなら、パッケージは次の1行です。
RUN apt-get update && apt-get install -y bubblewrap socatFedora系ならdnf install bubblewrap socatに置き換えます。ripgrepはネイティブ版のClaude Code本体に同梱されているので、別に入れる必要はありません。Unixドメインソケットの遮断を足すseccompフィルターは任意の依存で、足りなければnpm install -g @anthropic-ai/sandbox-runtimeで入れます。
設定はイメージの中に置くと、起動のたびに配る手間が消えます。管理設定のファイルはLinuxなら/etc/claude-code/managed-settings.jsonです。ここに次を書くと、このコンテナの中ではsandboxが必須になります。
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"enableWeakerNestedSandbox": true
}
}各キーの役割は次のとおりです。
failIfUnavailable: 依存が欠けているなどでsandboxを起動できないとき、隔離なしで動き続けず、起動時にエラーで終了する。既定はfalseで、そのままだと隔離なしで動いてしまうallowUnsandboxedCommands: false: sandboxで失敗したコマンドを、Claudeがsandbox外で再試行する経路を閉じるenableWeakerNestedSandbox: 前の節の/procの問題を避ける
管理設定にallowUnsandboxedCommands: falseを置くと、リポジトリ側の.claude/settings.jsonがenableWeakerNestedSandboxをtrueにしても無視されます。上の例のようにイメージ側の管理設定で自分でtrueを書いておけば、この制約の影響を受けません。依存を入れ直したあとは、依存確認が起動時に走るため、Claude Codeを再起動してから/sandboxで確かめます。
/procが見えると何が変わるか
enableWeakerNestedSandboxで変わるのは、sandbox内のコマンドから見える/procだけです。設定リファレンスの記述は「プロセス情報が露出する」までで、どの項目がどこまで見えるかの一覧は載っていません。具体的な見え方はコンテナのPID名前空間の設定に左右されるため、機密に近い環境では、実際にpsなどを試して確かめてから使う選択肢があります。
確かめた結果、コンテナ内のプロセスしか見えないなら、露出の範囲はコンテナの内側に収まります。ホストのプロセスまで見えるなら、外側のコンテナ設定の見直しが先です。
外側のコンテナに隔離を任せる設計
この設定を使うのは、sandboxを「二重化」したいのではなく、外側のコンテナが本来の境界である構成です。たとえばCI用のコンテナ、使い捨てのDevContainerがそうです。DevContainerで認証情報を遮断する設計はDevContainerの完全実装が扱っています。
excludedCommandsでdockerを対象外にする使い方とは、向きが逆です。そちらはsandboxの内側からDockerを使う話で、本記事の設定はDockerの内側でsandboxを動かす話です。
まとめ
enableWeakerNestedSandboxは、非特権Dockerで/procのマウントが通らないときにだけtrueにする、隔離を一段弱める設定です。bwrapPathは管理設定専用で、PATH外のbwrapを使わせます。エラーが「bwrapが無い」のか「/procを作れない」のかを先に見分ければ、どちらを触るかは決まります。組織で運用するなら、前者は管理設定で配り、後者は管理設定でfalseに固定しておく選択肢があります。