【Claude Code 連載 第16回】権限ルール——allow / ask / deny の書き方と、効かない書き方

スポンサーリンク
【Claude Code 連載 第16回】権限ルール——allow / ask / deny の書き方と、効かない書き方 用語解説
【Claude Code 連載 第16回】権限ルール——allow / ask / deny の書き方と、効かない書き方
この記事は約9分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

スポンサーリンク

背景

この連載では、Claude Codeの公式ドキュメントを1ページずつ読み解いていきます。公式ドキュメントは情報が網羅されている分、「結局どの機能を、どんな場面で使えばいいのか」は自分で考える必要があり、読むのに意外と時間がかかります。そこで、私が実務で使うために読み込んだ内容を「使う場面→実例コード」の順に整理して残していくことにしました。専門家の解説というより、一次情報を読んだ記録です。推測や動作を確認していない部分には、その都度そう書きます。

1. これは一言でいうと何か

権限ルールは、Claude Code がアクセスして実行できる内容を、ツール単位・コマンド単位・パス単位で指定する仕組みです。バージョン管理にチェックインして組織全体に配布でき、開発者が個別にカスタマイズすることもできます。

前回(第15回)の権限モードが「確認の頻度」を決めるベースラインだったのに対し、今回はその上に重ねる個別のルールです。押さえるべき前提が1つあります。権限ルールを実装しているのは Claude Code であって、モデルではありません。 プロンプトや CLAUDE.md の指示は Claude が何をしようとするかを形作りますが、Claude Code が許可する内容は変わりません。

2. どういう場面で役立つか

ルールは3種類です。Allow(手動承認なしで使える)、Ask(使おうとするたびに確認)、Deny(使用を防止)。/permissions で一覧と、それがどの settings.json 由来かを確認できます。

  • テストとビルドだけ通したいBash(npm run *) を allow に置けば、日常的なコマンドの確認が消えます。
  • push だけは必ず止めたいBash(git push *) を deny に置きます。
  • 秘密ファイルを読ませたくないRead(.env) のような deny ルールを書きます。
  • 特定のサブエージェントを無効化したいAgent(Explore) を deny に置きます。

効かない書き方・向かない使い方。

  1. deny ルールに例外は作れません。 評価は deny → ask → allow の順で、最初にマッチしたものが結果を決め、ルールの具体性は順序を変えませんBash(aws *) を deny にすると、より狭い Bash(aws s3 ls) の allow があってもブロックされます。ask と allow の間も同じで、マッチする ask ルールがあれば、より具体的な allow があってもプロンプトが出ます。
  2. コマンド引数を制約する Bash パターンは脆弱です。 ドキュメントは Bash(curl http://github.com/ *) を例に、オプションの前置き、プロトコル違い、リダイレクト、変数展開、余分なスペースで容易に外れると説明しています。URL を絞りたいなら curlwget を deny にして WebFetch(domain:...) を使うか、PreToolUse フックで検証してください。WebFetch だけを使ってもネットワークアクセスは防げません。Bash が許可されていれば任意の URL に到達できます。
  3. Read / Edit の deny は万能ではありません。 Claude の組み込みファイルツールと、catsed など Claude Code が認識する Bash のファイルコマンドには効きますが、Python や Node のスクリプトがファイルを自分で開く場合には適用されません。OS レベルで止めたいならサンドボックスを使います。

3. コード・コマンドの実例と解説

前提条件

  • ルールの形式は Tool または Tool(specifier) です。括弧なしのツール名は全使用にマッチします(Bash(*)Bash と同等)。
  • deny ルールは書き方で挙動が変わります。 Bash のようなベアツール名はツールを Claude のコンテキストから完全に削除するため、Claude はその存在すら見ません。Bash(rm *) のようなスコープ付きルールはツールを残したまま、該当する呼び出しだけをブロックします。
  • 権限プロンプトで Ctrl+E を押すと、コマンドの説明(何をするか、なぜ実行しようとするか、何が問題になり得るか)が低・中・高のリスクラベル付きで表示されます。表示してもコマンドは実行されません。

ワイルドカードで許可・拒否する

{
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(git commit *)",
      "Bash(git * main)",
      "Bash(* --version)",
      "Bash(* --help *)"
    ],
    "deny": [
      "Bash(git push *)"
    ]
  }
}

npm と git commit を許可し、git push をブロックする設定です。ワイルドカードはコマンド内の任意の位置に置け、単一の * はスペースを含む任意の文字列にマッチします(Bash(git * main)git push origin main にも git merge main にもマッチ)。

* の前のスペースが決定的に重要です。 Bash(ls *) は単語境界を強制するため ls -la にマッチしますが lsof にはマッチしません。スペースなしの Bash(ls*) は両方にマッチします。:* サフィックスは末尾のワイルドカードと同等(Bash(ls:*) = Bash(ls *))ですが、末尾でのみ認識されます。Bash(git:* push) のコロンはリテラル文字として扱われ、git コマンドにはマッチしません。

複合コマンドは分割して評価される

Claude Code はシェルオペレータを認識するため、Bash(safe-cmd *) があっても safe-cmd && other-cmd は実行できません。区切りとして認識されるのは &&||;||&&、改行で、各サブコマンドが独立してマッチする必要があります

「はい、今後は聞かない」で複合コマンドを承認した場合も、複合文字列そのままではなくサブコマンドごとに個別ルールが保存されます(1つの複合コマンドで最大5つ)。

パスの書き方はアンカーで決まる

Read と Edit のルールは gitignore 仕様に従い、4種類のパターンがあります。

パターン意味
//pathファイルシステムルートからの絶対パスRead(//Users/alice/secrets/**)
~/pathホームディレクトリからのパスRead(~/Documents/*.pdf)
/path設定ソースからの相対パスEdit(/src/**/*.ts)
path または ./path現在のディレクトリからの相対パスRead(*.env)

最も間違えやすいのは3行目です。 /Users/alice/file は絶対パスではありません。単一の先頭スラッシュは設定ソースにアンカーされます。ユーザー設定に Read(/secrets/**) と書くと、プロジェクト内の secrets ではなく ~/.claude/secrets/** をブロックすることになります。全プロジェクトに効かせたいなら //~/ を使ってください。

なお、ベアファイル名は gitignore セマンティクスで任意の深さにマッチするため、Read(.env)Read(**/.env) は同等です。ただしこれは現在のディレクトリ以下だけで、親や別プロジェクトの .env はブロックしません。それも止めたいなら Read(//**/.env) です。

MCP ツールをまとめて拒否する

{
  "permissions": {
    "deny": [
      "mcp__*"
    ]
  }
}

deny と ask はツール名の位置でもグロブを受け付けます。mcp__* は全サーバーの全 MCP ツールにマッチします。ただし allow 側は対称ではありません。 許可ルールはリテラルの mcp__<server>__ プレフィックスの後でしかグロブを受け付けず、"*""mcp__*" のようなアンカーなしの許可グロブは警告とともにスキップされ、自動承認されません。

サブエージェントを無効化する

{
  "permissions": {
    "deny": ["Agent(Explore)"]
  }
}

Agent(AgentName) で個別のサブエージェントを制御します。--disallowedTools CLI フラグでも同じことができます。

その他(PowerShell ルールとエイリアス正規化、入力パラメータマッチ Tool(param:value)、プロセスラッパーの扱いと devbox run などの落とし穴、読み取り専用コマンドの組み込みセット、WebFetch のワイルドカード境界、シンボリックリンクの扱い、Cd ルール、additionalDirectories--add-dir で読み込まれる設定の一覧、管理のみの設定18項目、ワークスペーストラストの詳細)は公式ドキュメントを参照してください。

4. まとめと次回予告

  • ルールは deny → ask → allow の順で評価され、最初のマッチが勝ちます。具体性では覆せません。
  • Bash は * の前のスペースで挙動が変わり、複合コマンドはサブコマンドごとに判定されます。
  • パスは4つのアンカーを持ちます。/path は「設定ソースからの相対」であって絶対パスではありません。

優先順位は「拒否が常に勝つ」で貫かれています。 設定の優先順位は 管理設定 > コマンドライン引数 > ローカルプロジェクト > 共有プロジェクト > ユーザー設定 ですが、どのレベルであれ拒否されたツールを他のレベルが許可することはできません。管理設定の deny は --allowedTools で上書きできず、ユーザー設定の deny はプロジェクト設定の allow をブロックします。

フックとの関係も同じ形です。 PreToolUse フックは権限プロンプトの前に実行されますが、フックの決定が権限ルールをバイパスすることはありません。deny ルールと ask ルールはフックの戻り値に関係なく評価されます。一方でブロッキングフックは allow ルールより優先され、終了コード2で終わるフックは権限ルール評価前に呼び出しを止めます。「Bash は全部許可して、一部だけフックで止める」という構成が成立するのはこのためです。

最後に、チーム配布で引っかかりやすい点を1つ。プロジェクトの .claude/settings.json にある permissions.allowadditionalDirectories は、ワークスペーストラストダイアログを受け入れるまで適用されません。 読み込まれてはいるが効いていない状態です。これらは「機能を付与する」ルールだからで、制限のみを行う deny と ask は影響を受けません。トラストダイアログには、そのフォルダが付与する許可ルールと追加ディレクトリが表示されるので、受け入れる前に確認できます。

次回予告:Bash コマンドを OS レベルで隔離する「サンドボックス」を取り上げる予定です。

関連ページ(本記事で触れた概念の詳細):モードの選び方 →「権限モードを選択する」、完全な設定リファレンス →「設定」、OS レベルの隔離 →「サンドボックス」、分類器への信頼インフラ登録 →「auto モードを設定する」、PreToolUse の書き方 →「Hooks」、ツールの正規名 →「ツール参照」、ワークスペーストラスト →「セキュリティ」。


本記事は執筆時点の公式ドキュメント(権限を設定する)に基づきます。最新は公式ドキュメントをご確認ください。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました