Claude CodeのallowManagedReadPathsOnlyで読み取り再許可を管理設定に限定する
allowManagedReadPathsOnlyをtrueにすると、denyReadで塞いだパスの再解放はmanaged settingsのallowReadだけに限られます。設定例と効かない範囲を扱います。
managed settings(組織が配布する設定ファイル)でsandbox.filesystem.denyReadを使い、ホームディレクトリの読み取りを塞いだとします。それだけでは終わりません。開発者はユーザー設定にallowReadエントリを1行足すだけで、塞いだパスを自分の手元だけ開け直せます。allowManagedReadPathsOnlyはこの再解放の経路を潰す設定です。trueにすると、サンドボックス化されたコマンドが読めるallowReadはmanaged settings由来のものだけになり、開発者側がどのスコープに書いても無視されます。
allowManagedReadPathsOnlyは何を固定するのか
sandbox.filesystem.allowManagedReadPathsOnlyはBoolean型の設定で、書けるスコープはmanaged settingsだけです。ユーザー設定・プロジェクト設定・ローカル設定・--settingsフラグのいずれから指定しても無視されます。既定値はfalseです。この場合、allowReadエントリはセッションが読み込む設定ファイルからマージでき、開発者が追加した分もそのまま有効になります。
trueにすると挙動が変わります。Claude Codeはmanaged settingsに書かれたallowReadエントリだけに従い、それ以外のスコープのallowReadは完全に無視します。一方denyReadの扱いは変わりません。このロックを立ててもdenyReadはセッションが読み込む全スコープから引き続きマージされます。つまりallowManagedReadPathsOnlyが制限するのは「塞いだパスを開け直す方向」だけです。「さらに塞ぐ方向」の権限は、ロックの有無にかかわらず開発者側にも常に残ります。
denyReadとallowReadだけでは組織のポリシーが固定できない理由
サンドボックス化されたBashコマンドの既定の読み取り範囲は、コンピューター全体に及びます。書き込みは作業ディレクトリとその配下、--add-dirで追加したディレクトリ、ユーザーごとの一時ディレクトリ($TMPDIR)に限られます。読み取りは一部の拒否ディレクトリを除いて広く開いています。~/.aws/credentialsのような認証情報ファイルも、既定ではこの広い読み取り範囲に含まれます。
組織側がdenyReadでホームディレクトリ全体を塞ぎ、業務用のディレクトリだけallowReadで開け直す、という構成はよくある設計です。ここで問題になるのが配列の扱いです。allowWrite・denyWrite・denyRead・allowReadの4つは、セッションが読み込むすべての設定ファイルからマージされます。開発者が自分のユーザー設定にallowReadを追記すれば、それも組織のリストにそのまま加算されます。v2.1.285より前のバージョンでは、プロジェクトの.claude/settings.jsonでも同じです。管理者が意図した境界は、開発者の1行で簡単に広がってしまいます。このうちallowReadの合流を止めるのがallowManagedReadPathsOnlyです。
対象はallowReadという1つのリストだけで、マージ元をmanaged settingsに絞ります。ネットワーク側で同じ役割を果たすのがsandbox.network.allowManagedDomainsOnlyです。こちらはallowedDomainsとWebFetch(domain:...)の許可ルールをmanaged settings由来だけに絞ります。両方とも「許可を広げる方向のリストだけをロックする」という設計です。設定例やつまずきはallowManagedDomainsOnlyで許可ドメインを管理設定に固定するで扱っています。
作業ディレクトリの外を一律に読めなくするだけでよいなら、もっと簡単な手もあります。denyRead/allowReadを自分で書く前にpermissions.blockReadsOutsideWorkingDirectoriesも選択肢に入ります。ホームディレクトリやマウントされたボリュームの読み取りを塞ぎつつ作業ディレクトリだけ読める状態にする、という単純な形であれば1つのBooleanで済みます。パスを個別に列挙してmanaged専用ロックまで組む構成は、業務ディレクトリごとに例外を分けたい場合に向きます。単純な内外分離では足りないときの選択肢です。設定例と効かないケースはClaude Codeで作業ディレクトリ外の読み取りを一括禁止する設定にまとめています。
管理設定でホームディレクトリを塞ぎ、業務ディレクトリだけ開ける
公式ドキュメントが示す例は、ホームディレクトリの読み取りを一括で拒否し、~/workだけを再度開ける構成です。managed-settings.jsonに次のように書きます。
{
"sandbox": {
"filesystem": {
"denyRead": ["~/"],
"allowRead": ["~/work"],
"allowManagedReadPathsOnly": true
}
}
}この状態では、開発者が自分のユーザー設定にallowRead: ["~/Documents"]を足しても無視されます。読めるようになるのは~/workだけで、それ以外のホーム配下はdenyReadのまま塞がれ続けます。
読み取りロックを配る順序
- 1
サンドボックスを必須にする
managed settingsに
sandbox.enabled: trueとfailIfUnavailable: trueを置きます。サンドボックスが起動しなければ、ファイルシステムの許可リストはそもそも評価されません。 - 2
denyReadで塞ぎ、allowReadで開ける
組織が読ませたくない範囲を
denyRead、業務に要る範囲だけをallowReadに書きます。allowReadは塞いだ領域の内側にだけ意味があります。 - 3
allowManagedReadPathsOnlyをtrueにする
開発者側から
allowReadを足しても効かなくなります。 - 4
filesystem.disabledの経路を確かめる
配布後に、開発者側の設定から
filesystem.disabledを立てても効かないことを確かめておきます。
組織全体にサンドボックスを強制する例(allowManagedReadPathsOnly込み)
サンドボックスの有効化・起動失敗時のフォールバック禁止・読み取りロックを1つのmanaged-settings.jsonにまとめると、次のようになります。
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"filesystem": {
"denyRead": ["~/"],
"allowRead": ["~/work"],
"allowManagedReadPathsOnly": true
}
}
}failIfUnavailable: trueは、Linuxでbubblewrapが入っていないなど依存関係が欠けている環境でClaude Codeの起動自体を止めます。allowUnsandboxedCommands: falseは別の役目です。サンドボックス内でコマンドが失敗したときに、dangerouslyDisableSandboxのエスケープハッチで非サンドボックス実行へ逃がすことを禁じます。この2つを外したままallowManagedReadPathsOnlyだけ設定しても効果は限定的です。サンドボックスがそもそも起動しない環境や、エスケープ後の再実行では読み取りロックが意味を持ちません。
allowReadを足せる発信元ごとの扱い
ロックを置かなくても、すべてのallowReadが通るわけではありません。管理側に次のどれかがあると、リポジトリ側のallowReadは一部が自動で無視されます。filesystem.denyRead、Read(...)のdenyルール、credentials.filesのエントリです。ここがロックの本当の守備範囲を決めます。
allowReadを書く場所ごとの結果
リポジトリの.claude/settings.json
managed settingsか
--settingsに上記の拒否設定があれば、拒否された領域の内側を指すallowRead(またはそれに一致する可能性のあるワイルドカード)は無視されます。v2.1.285以降の挙動です。ロックを置かなくても、リポジトリ経由の開け直しはここで止まります。ユーザー設定と--settings
ロックがなければマージされ、開発者が自分の手元で開け直せます。
allowManagedReadPathsOnlyが実際に止める相手は、この2つです。ロックを置くと、リポジトリ由来も含めてmanaged以外のallowReadはすべて無視されます。managed settings
常に有効です。ロックの有無にかかわらず、組織が決めた再解放はここに書きます。
管理側に拒否設定が無く、サンドボックスがadmin-requiredでもない場合に限り、リポジトリの設定は通常どおりマージされます。admin-requiredになる条件の例は、managed settingsのallowUnsandboxedCommandsがfalseであること。もう1つはallowManagedDomainsOnlyがtrueであることです。この場合は、ユーザー設定のdenyRead配下を指すリポジトリ由来のallowReadも無視されます。クローンしたリポジトリの設定ファイルによる開け直しを防ぐだけなら、管理側のdenyReadで足ります。開発者本人の意思による開け直しまで止めたいときに、allowManagedReadPathsOnlyが必要になります。
allowManagedReadPathsOnlyが対象にしないもの
このロックが効くのは、サンドボックス化されたBashコマンドとその子プロセス(kubectl・terraform・npmなど)がOSサンドボックスの境界で読み取るファイルです。Claude Code自身のReadツール・Editツール・Writeツールはサンドボックスの実行境界を通らず、権限システムを直接使います。Readの拒否ルールはdenyReadに統合されますが、Readツールを許可するかどうかの判定自体は権限システム側で行われます。サンドボックスの適用範囲の違いは、Claude Code権限モデルの変遷で扱っている権限系統の分岐とも重なります。
--setting-sources(Agent SDKではsettingSources)でuser・project・localのいずれかを除外できます。v2.1.287のclaude --helpでは、この行が次のように出ます。
claude --help --setting-sources <sources> Comma-separated list of setting sources
to load (user, project, local).除外したスコープのsandbox.filesystemエントリ・Edit権限ルール・Read拒否ルールは、サンドボックス構成の組み立てから丸ごと外れます。候補はuser・project・localの3つだけで、managed settingsは除外対象に含まれません。allowManagedReadPathsOnlyをmanaged settings側で有効にしている限り、起動オプション側からこのロックを迂回する経路はありません。
allowManagedReadPathsOnlyはファイルシステム分離が有効なときにしか意味を持ちません。sandbox.filesystem.disabledをtrueにすると、ファイルシステム分離そのものをスキップできます。この状態ではClaude CodeはdenyReadもcredentials.filesのdenyエントリも一切強制しません。allowManagedReadPathsOnlyをtrueにしていても、filesystem.disabledが別の設定源からtrueになれば読み取りロックごと無効化されます。managed settingsがsandbox.filesystemを1つでも設定していればfilesystem.disabled自体もmanaged settings限定になります。managed settingsにsandbox.filesystemの設定が1つも無いと、この抜け道が残ります。
他のallowManaged*Onlyロックとの違い
managed専用の「開発者による拡張を禁じるロック」は、設定リファレンスに項目がある主なものは次の5つです。ユーザーが入れたmodだけを塞ぐallowManagedModsOnlyは別枠です。pluginConfigsのcc-plugin-sec-default@builtinに置くオプションとして用意されています。
| キー | 対象 | trueで固定されるもの | ロックされないもの |
|---|---|---|---|
allowManagedReadPathsOnly | 対象ファイル読み取り(allowRead) | trueで固定されるものmanagedのallowReadだけが有効 | ロックされないものdenyReadは全スコープから常にマージ |
allowManagedDomainsOnly | 対象通信許可ドメイン | trueで固定されるものmanagedのallowedDomainsだけが有効 | ロックされないものdeny側の追加は開発者側からも可能 |
allowManagedPermissionRulesOnly | 対象権限ルール全体(allow/ask/deny) | trueで固定されるものmanaged以外のallow/ask/denyを無視 | ロックされないもの--disallowedToolsと現在セッションのdeny/askルール |
allowManagedHooksOnly | 対象フックの実行 | trueで固定されるものmanagedが配布したhooksだけ実行 | ロックされないものAgent SDKのhooks、強制有効化されたプラグインのhooks |
allowManagedMcpServersOnly | 対象追加できるMCPサーバー一覧 | trueで固定されるものmanagedのallowedMcpServersだけが有効 | ロックされないものdeniedMcpServersは全スコープから常にマージ |
読み取りパスと通信ドメインのロックは、それぞれallowReadとallowedDomainsという「広げる方向」のリスト1つだけを狙い撃ちする設計で共通しています。allowManagedPermissionRulesOnlyはもっと範囲が広く、権限ルールの発行元そのものをmanaged settingsに一本化します。sandbox.filesystem.allowWrite・denyWriteとexcludedCommandsには、これに相当するロックがありません。公式ドキュメントも、excludedCommandsとfilesystem.allowWriteにはmanaged専用のロックが無いと書いています。書き込み許可の拡張を防ぎたい場合は、このロックの不在を前提に運用でカバーする必要があります。kubectlやterraformの書き込み範囲をallowWrite・denyWriteで調整する具体例はallowWriteとdenyWriteで書き込み範囲を調整する設定にまとめています。
導入時によくあるつまずき
blockReadsOutsideWorkingDirectoriesと同時に使うと一部が抜ける
permissions.blockReadsOutsideWorkingDirectoriesは、サンドボックス化されたコマンドからもホームディレクトリや/Volumesなどを読めなくします。ただしallowManagedReadPathsOnlyを設定している間、この読み取りブロックはサンドボックス化されたコマンドには及びません。Claude Codeのファイルツールでは引き続き効きます。2つを重ねても、サンドボックス内のコマンドの境界はdenyReadとallowReadだけで決まります。またblockReadsOutsideWorkingDirectoriesが有効な間は、リポジトリ由来のallowReadのエントリも外されます。
ワイルドカードのdenyReadは広いallowReadより強い
denyReadにワイルドカードエントリ(~/**/.envなど)を書くと、そのエントリが指すディレクトリの中身もまとめて読み取り拒否になります。より広いallowReadエントリでそのパスを覆っても、ワイルドカードや完全一致のdenyReadは内側でブロックされたままです。macOSにはこの重なりの処理に古い不具合がありました。v2.1.236より前のバージョンでは、広いallowReadエントリがワイルドカードのdenyReadが一致したディレクトリを誤って再度開いてしまい、中身が読み取り可能なまま残っていました。この不具合は修正済みです。
重なったルールでは、パスの狭いほうが優先されます。denyRead: ["~/"]にallowRead: ["~/projects"]を重ねると~/projectsだけが読めます。逆にallowRead: ["~/"]の内側にdenyRead: ["~/.env"]があれば、~/.envは塞がれたままです。広いallowでは、内側の狭いdenyを覆せません。
相対パスの.は、書いた場所で指す先が変わります。プロジェクトの.claude/settings.jsonではプロジェクトルート、~/.claude/settings.jsonでは~/.claudeです。ユーザー設定にallowRead: ["."]を書くと、作業中のプロジェクトは読めるようになりません。managed settingsで業務ディレクトリを開けるときは、~/workのようにホームからのパスで書きます。
excludedCommandsは別枠のまま残る
excludedCommandsは、サンドボックスを経由させずに実行するコマンドの指定です。allowManagedReadPathsOnlyとallowManagedPermissionRulesOnlyを組み合わせても、sandbox.excludedCommandsには手が届きません。開発者は自分の設定にexcludedCommandsを追記して、特定のコマンドをサンドボックスの境界そのものから外せます。読み取りポリシーを固定しても、対象コマンドをサンドボックス外に逃がされればallowManagedReadPathsOnlyは関与しません。
対応プラットフォームはmacOS・Linux・WSL2まで
サンドボックス自体がmacOS・Linux・WSL2でのみ動作し、ネイティブのWindowsには対応していません。failIfUnavailableを配るとネイティブのWindows機ではClaude Codeが起動時に終了します。macOSとLinuxにだけ設定ファイルを配るか、WindowsユーザーをWSL2やコンテナへ移すかを選ぶことになります。
まとめ
配布前に、守りたい相手がクローンしたリポジトリなのか開発者本人なのかを決めておくと、必要な設定が絞れます。サンドボックス全体の設計はClaude Codeのサンドボックス設計、managed settingsの配布方法はClaude Code組織管理ガイドで扱っています。