Claude Codeを業務で使うときに、「こうしてください」と文書に書くだけでは統制になりません。この記事では、公式ドキュメントにある設定キーを使って、権限、サンドボックス、MCPサーバーの許可リスト、データとテレメトリの扱いを、設定ファイルに書く方法をまとめました。
キー名は、公式ドキュメントと公開JSON Schemaで確認しています。手元で動かして確かめた範囲と、確かめていない範囲を分けて書きます。気になる節だけ拾ってもらえれば十分です。
環境
動作確認は2026年10月17日です。
- Claude Code 2.1.302(
claude --version) - macOS
- 設定キーの検証: 公開JSON Schema(
https://json.schemastore.org/claude-code-settings.json)
Claude Codeは機能の追加が速く、キー名や既定の動作が変わることがあります。使う前に、手元のバージョンと公式ドキュメントで確かめてください。例の中のドメインは、すべて架空(example.com)です。
この記事をざっくり図解
設定の優先順位(高い順): Managed > コマンドライン > ローカル > プロジェクト > ユーザー
^ここに書いたものは、利用者が上書きできない(一部の例外を除く)
1 permissions 何を実行・読み書きしてよいか deny > ask > allow の順に評価
2 sandbox シェルコマンドをOSの制限で囲む 対象はシェルコマンドだけ
3 MCP 接続してよいサーバーの許可リスト
4 data / env テレメトリ、フィードバック、ローカルの保存期間
0. 前提: CLAUDE.mdは統制にならない
権限のドキュメントには、権限ルールを実行するのはモデルではなくClaude Code自身で、プロンプトや CLAUDE.md の指示は「Claudeが試みること」に影響するが、「Claude Codeが許可すること」は変えない、と書かれています。
つまり、「.env は読まない」と CLAUDE.md に書くだけでは、読めない状態にはなりません。読めなくするには、設定に書く必要があります。
hookで機密ファイルの読み込みを止める方法と、CLAUDE.md に書くルールの決め方は、別の記事(「Claude CodeのPreToolUse hookで、.envなど機密ファイルの誤読み込みを止める」「CLAUDE.mdに「やらないこと」を書く」)で書いたので、ここでは設定ファイルだけを扱います。
設定ファイルの置き場所は4種類あります。
| 区分 | ファイル | 誰が決めるか |
|---|---|---|
| Managed |
managed-settings.json、MDM、claude.aiの管理コンソール |
組織 |
| ローカル | .claude/settings.local.json |
個人(そのプロジェクト) |
| プロジェクト | .claude/settings.json |
リポジトリの全員 |
| ユーザー | ~/.claude/settings.json |
個人(全プロジェクト) |
Managedのファイルは、ドキュメントによると、macOSが /Library/Application Support/ClaudeCode/、LinuxとWSLが /etc/claude-code/、Windowsが C:\Program Files\ClaudeCode\ に置きます。このあとの例は、すべてManagedに置く前提で書きます。1人で試すだけなら、プロジェクトの .claude/settings.json に同じキーを書いても動きます。
1. permissions: deny、ask、allow
ルールは permissions.deny、permissions.ask、permissions.allow に書きます。評価の順は deny、ask、allow で、最初に一致したものが結果を決めます。
大事なのは、範囲の狭いallowで、範囲の広いdenyの例外は作れないことです。たとえば Bash(aws *) をdenyにすると、Bash(aws s3 ls) をallowしても止まります。
書き方の例です。
{
"permissions": {
"deny": ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)", "Bash(curl *)"],
"ask": ["Bash(git push *)"],
"allow": ["Bash(npm run test *)", "Bash(git status)"]
}
}
-
Read(./.env)は、カレントディレクトリの.envです。パスの書き方は gitignore と同じ系統で、ホームからは~/、ファイルシステムのルートからは//opt/project/...のように先頭に2つのスラッシュを付けます。先頭1つのスラッシュ(/secrets/**)は、絶対パスではなく、設定ファイルを置いた場所が基準になります。 -
Bash(npm run test *)のように、*の前には空白を入れます。Bash(ls *)はls -laに一致しますがlsofには一致せず、Bash(ls*)はlsofにも一致します。
モードを固定する
承認なしで実行できるモードがあります。権限のドキュメントは、bypassPermissions を、コンテナや仮想マシンのような隔離された環境でだけ使うよう求めています。使えないようにするキーが2つあります。
{
"permissions": {
"disableBypassPermissionsMode": "disable",
"disableAutoMode": "disable"
}
}
どの設定ファイルにも書けますが、Managedに置くと利用者が戻せません。
利用者のルールを無効にする
allowManagedPermissionRulesOnly: true をManagedに置くと、権限ルールの出どころがManagedだけになります。ただし副作用があります。利用者やプロジェクトが足したallowも無効になるので、日常の作業に必要なallowをManaged側に十分書いておかないと、確認のダイアログだらけになります。
実測: Read denyは効き、grep -r は通った
ドキュメントには、Read/Editのdenyの限界が書かれています。ファイル名を指定せずに読むコマンド(grep -r pattern . など)や、スクリプトが自分でファイルを開くような場合には効かない、という内容です。確かめました。
使い捨てのプロジェクトに、架空の値だけを入れた .env を作り、次の設定を置きました。
{
"permissions": {
"deny": ["Read(./.env)"],
"allow": ["Bash(grep *)", "Bash(cat *)"]
}
}
# Readツールで読ませる
claude -p "Use the Read tool on ./.env and tell me the first line." --max-turns 3 --setting-sources project
# grep -r で読ませる
claude -p "Run exactly this command and show its raw output: grep -r DEMO_API_KEY . " --max-turns 4 --setting-sources project
結果です。
- Readツール: 拒否されました。Claudeは「権限設定で読み取りがブロックされている」と答えました
-
grep -r DEMO_API_KEY .: 実行され、.envの中の架空の値が出力されました
補足です。実行時に、このディレクトリは信頼の確認を通していないため permissions.allow の2件は無視される、という警告が出ました(-p で、一度も開いたことのない一時ディレクトリだったためです)。つまり、この grep が通ったのは allow のおかげではありません。ドキュメントでは、grep や cat などは読み取り専用の組み込みコマンドとして、承認なしで実行される扱いです。
ドキュメントの記述どおりです。なお、1つ目ではClaude自身が、cat で読めば管理者が意図して設定した制限を迂回することになる、と説明して、試しませんでした。ただしこれは、モデルがそう振る舞ったというだけで、統制ではありません。同じ設定で、別の指示や別のモデルの振る舞いが同じになる保証はありません。
OSのレベルですべてのプロセスから隠したいなら、次のサンドボックスを使います。ドキュメントも、そう案内しています。
Bashのdenyは、書き方の違いで迂回される
ドキュメントの表には、Bash(curl *) が curl https://example.com には一致するものの、/usr/bin/curl https://example.com や sh -c 'curl https://example.com' には一致しない、という例があります。同様に Bash(git push *) は、git -C . push origin main には一致しません。denyは「普通に書かれた形」を止めるものと考えて、ネットワークの出口はサンドボックスのドメイン許可で絞るほうが確実です。
2. sandbox: シェルコマンドをOSの制限で囲む
サンドボックスは、Claude Codeが実行するシェルコマンドとその子プロセスを、OSが強制する制限で囲みます。初期状態は無効です。/sandbox コマンドか、sandbox.enabled: true で有効にします。
| 項目 | ドキュメントの記述 |
|---|---|
| 書き込み | 作業ディレクトリ、一時ディレクトリ、追加したディレクトリ |
| 読み取り | 初期設定では、マシンの大部分(~/.ssh や ~/.aws/credentials を含む) |
| ネットワーク | 許可したドメインだけを通すプロキシ経由。許可リストは最初は空 |
| 環境変数 | Claude Codeから引き継ぐ。環境内のシークレットも含む |
| 対象外 | Read、Edit、WebFetchなどの組み込みツール、フック、ローカルのMCPサーバー、! で手入力したコマンドなど |
| 対応環境 | macOS、Linux、WSL2。ネイティブのWindowsではサンドボックスなしで実行 |
組織で強制するときの設定の例です。
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"network": {
"allowedDomains": ["registry.npmjs.org", "pypi.org", "files.pythonhosted.org"]
},
"credentials": {
"files": [
{ "path": "~/.aws/credentials", "mode": "deny" },
{ "path": "~/.ssh", "mode": "deny" }
],
"envVars": [
{ "name": "GITHUB_TOKEN", "mode": "deny" },
{ "name": "NPM_TOKEN", "mode": "deny" }
]
}
}
}
-
failIfUnavailable: trueは、依存関係が足りないなどでサンドボックスを起動できないときに、サンドボックスなしで動かさず、起動時に終了します。既定では、そのままサンドボックスなしで実行されます。ネイティブのWindowsでは常にサンドボックスがないため、この設定を入れた環境では、WSL2で動かす必要があります。 -
allowUnsandboxedCommands: falseは、サンドボックスで失敗したコマンドを、サンドボックスの外で再実行する逃げ道を閉じます。 -
credentialsは、読ませたくないファイルと、サンドボックス内のコマンドから消したい環境変数を指定します。ドキュメントによると、サンドボックス内のコマンドだけに効きます(全サブプロセスから外したい場合は別の環境変数があります)。 -
allowedDomainsにgithub.comのような広いドメインを入れると、情報を持ち出す経路になり得る、とドキュメントは注意しています。プロキシがTLSの中身を見ず、ホスト名だけで判断するためです。
ドキュメント自身が、サンドボックスは「リスクを減らすが、完全な隔離ではない」と書いています。
3. MCP: 接続してよいサーバーを決める
既定では、Claude Codeを使う誰もが、任意のMCPサーバーに接続できます。Anthropicはコネクタを掲載前に審査しますが、MCPサーバーのセキュリティ監査や管理は行わない、とドキュメントにあります。
組織で絞る方法は、ドキュメントでは大きく3つあります。
| やりたいこと | 使うもの |
|---|---|
| 危険なものだけ止める | deniedMcpServers |
| 承認したものだけ許可する |
allowedMcpServers と allowManagedMcpServersOnly: true
|
| 会社が選んだサーバーだけ固定で配る。MCPを無効にする | managed-mcp.json |
許可リストの書き方です。
{
"allowManagedMcpServersOnly": true,
"allowedMcpServers": [
{ "serverUrl": "https://mcp.example.com/*" },
{ "serverCommand": ["npx", "-y", "@example/approved-mcp-server@1.2.3"] }
],
"deniedMcpServers": [
{ "serverUrl": "https://*.untrusted.example.com/*" }
]
}
覚えておきたい点です。
-
serverNameはセキュリティの統制にはなりません。 名前は利用者がclaude mcp addで付けるラベルで、どんなサーバーにもgithubという名前を付けられるからです。強制したいならserverUrlかserverCommandで書きます。 -
serverCommandは、コマンドと引数の完全一致です。["npx", "-y", "server"]は、["npx", "-y", "server", "--flag"]には一致しません。上の例のようにバージョンを固定すると、版が変わったときにも止まります。 -
allowedMcpServersを書かない場合は、全部許可です。空の配列[]にすると、(ドキュメントが挙げる例外を除いて)全部拒否です。この2つは別の意味なので、混同に注意してください。 -
allowManagedMcpServersOnlyを付けないと、利用者が自分の設定で許可を広げられます。 -
managed-mcp.jsonに{"mcpServers": {}}を置くと、MCPを無効にできます。このファイルには、全ユーザーが読める前提で、キーや認証情報を書かないでください。
4. データとテレメトリ: 環境変数と保存期間
通信と保存については、環境変数と設定で制御できる部分があります。設定ファイルの env に書けます(ドキュメントには、環境変数は settings.json に入れてよいとあります)。
{
"env": {
"DISABLE_TELEMETRY": "1",
"DISABLE_ERROR_REPORTING": "1",
"DISABLE_FEEDBACK_COMMAND": "1"
},
"cleanupPeriodDays": 7
}
| 設定 | 効果(data usage のドキュメントより) |
|---|---|
DISABLE_TELEMETRY=1 |
使用状況のメトリクスの送信を止める。コードやプロンプト、ファイルパスは含まれないとされている |
DISABLE_ERROR_REPORTING=1 |
エラーレポートの送信を止める。Claude Code内部のエラーと、スタックトレース |
DISABLE_FEEDBACK_COMMAND=1 |
/feedback を使えなくする。このコマンドは、コードを含む会話履歴のコピーをAnthropicに送る |
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC |
必須でない通信をまとめて止める |
cleanupPeriodDays |
ローカルに保存されるセッション記録の保持日数(既定は30日) |
注意点が3つあります。
-
DISABLE_TELEMETRYやCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFICを設定すると、フィーチャーフラグの評価も止まり、Remote Controlが使えなくなることがあります(DISABLE_ERROR_REPORTINGは影響しません)。 - セッションの記録は、手元のマシンの
~/.claude/projects/に平文で保存されます。プロンプトに貼った機密情報は、そこに残ります。cleanupPeriodDaysは短くできますが、保存自体を止めるものではありません。 - 学習への利用は、アカウントの種類で異なります。ドキュメントによると、Team、Enterprise、API、サードパーティ基盤(商用)では、顧客が自らデータを提供した場合を除き、Claude Codeに送ったコードやプロンプトで生成モデルを学習しません。Free、Pro、Maxでは、モデル改善への利用は設定で選びます。設定ファイルでは決まらないので、アカウント種別の管理が先です。
5. まとめた例と、キー名の検証
上の断片を1つにしたものです。managed-settings.json として置く想定です。
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"allowManagedPermissionRulesOnly": true,
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Read(~/.ssh/**)",
"Bash(curl *)",
"Bash(wget *)"
],
"ask": [
"Bash(git push *)"
],
"allow": [
"Bash(npm run test *)",
"Bash(npm run lint)",
"Bash(git status)",
"Bash(git diff *)"
],
"disableBypassPermissionsMode": "disable",
"disableAutoMode": "disable"
},
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"network": {
"allowedDomains": ["registry.npmjs.org", "pypi.org", "files.pythonhosted.org"]
},
"credentials": {
"files": [
{ "path": "~/.aws/credentials", "mode": "deny" },
{ "path": "~/.ssh", "mode": "deny" }
],
"envVars": [
{ "name": "GITHUB_TOKEN", "mode": "deny" },
{ "name": "NPM_TOKEN", "mode": "deny" }
]
}
},
"allowManagedMcpServersOnly": true,
"allowedMcpServers": [
{ "serverUrl": "https://mcp.example.com/*" },
{ "serverCommand": ["npx", "-y", "@example/approved-mcp-server@1.2.3"] }
],
"deniedMcpServers": [
{ "serverUrl": "https://*.untrusted.example.com/*" }
],
"env": {
"DISABLE_TELEMETRY": "1",
"DISABLE_ERROR_REPORTING": "1",
"DISABLE_FEEDBACK_COMMAND": "1"
},
"cleanupPeriodDays": 7
}
キー名の打ち間違いは、起動してから気づくと遅いので、公開されているJSON Schemaで先に検証しておくと安全です。
import json, jsonschema
schema = json.load(open("schema.json")) # curl -sL https://json.schemastore.org/claude-code-settings.json
doc = json.load(open("managed-settings.json"))
validator = jsonschema.validators.validator_for(schema)(schema)
errors = list(validator.iter_errors(doc))
print("schema errors:", len(errors))
上の例では schema errors: 0 でした。sandbox.failIfUnavailable を failIfUnavailabel に、permissions.disableBypassPermissionsMode を disableBypassPermissionMode にわざと変えたところ、2件のエラーが出ました。ただし、トップレベルのキーの打ち間違いは、このSchemaでは許容されるため、エラーになりません。ネストしたキーの検証に使えるものと考えてください。
動作は /permissions(ルールと、どのファイルから来たかの一覧)、/sandbox、claude mcp list(Managedの配布後に、承認したサーバーだけが出るか)などで確かめます。
限界と、確かめていないこと
-
Managedのキーが強制される動作は、この記事では確認していません。
allowManagedPermissionRulesOnly、allowManagedMcpServersOnly、failIfUnavailableなどを、システムのパスに置いて試してはいません。確認したのは、キー名のSchema検証、プロジェクト設定でのRead denyとgrep -rの挙動、公式ドキュメントの記述です。 - 設定は、会社が管理する端末にしか届きません。 私物の端末や、別のアカウントで使うClaude Codeは、Managedの外にあります。
- サンドボックスは、シェルコマンドだけを囲みます。 ファイルツール、ローカルのMCPサーバー、フックはサンドボックスの外で、利用者の権限のまま動きます。MCPとフックは、別に承認の仕組みが必要です。
- denyルールは、書き方の揺れで迂回されます。 ネットワークとファイルの両方で、サンドボックスとの併用が前提です。
- 権限ルールは、人が読むことの代わりにはなりません。 承認の前にコマンドを読むのは、利用者の仕事です。
-
キー名と既定の動作は、バージョンで変わります。 2.1.302で確認した内容です。ドキュメントの記述(特に、
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFICの範囲)は、手元のバージョンで確かめてください。
最後に
1つだけ試すなら、使い捨てのディレクトリに架空の .env を置いて、Read denyと grep -r の違いを自分の環境で再現してみてください。どこまでが設定で止まり、どこから止まらないかが、体感として分かります。
参考文献
- Claude Code Docs「Configure permissions」 https://code.claude.com/docs/en/permissions
- Claude Code Docs「Configure the sandboxed Bash tool」 https://code.claude.com/docs/en/sandboxing
- Claude Code Docs「Control MCP server access for your organization」 https://code.claude.com/docs/en/managed-mcp
- Claude Code Docs「Data usage」 https://code.claude.com/docs/en/data-usage
- Claude Code Docs「Settings files and precedence」 https://code.claude.com/docs/en/settings
- JSON Schema Store「claude-code-settings.json」 https://json.schemastore.org/claude-code-settings.json