はじめに
Claude Codeを使い続けると、2つの相反する不満が生まれる。
「毎回 npm run test の実行に確認が必要で遅い」(不満A)。「--dangerously-skip-permissions は怖いが、毎回承認も面倒」(不満B)。
この2つは正しいパーミッション設計で同時に解決できる。「安全なものは自動で通す・危険なものは絶対ブロック・曖昧なものは都度確認」という3層設計が答えだ。
パーミッションの3層モデルと評価順序
Claude Codeのパーミッションは次の順序で評価される。
deny(最優先)→ ask → allow
deny が最優先であることが重要で、allowとdenyが競合した場合はdenyが勝つ。
| レイヤー | 動作 | 対象の例 |
|---|---|---|
| Allow | 確認なしで自動実行 | npm run *, git status, Read, Write, Edit |
| Deny | 完全にブロック(実行不可) | .env読み取り, rm -rf *, npm publish |
| Ask | 実行前に確認 | git push --force, terraform apply |
「未定義」はデフォルトで「ask(都度確認)」として扱われる。
Allow設定:毎回確認が不要な安全な操作
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npm test)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(ls *)",
"Read",
"Write",
"Edit"
]
}
}
ワイルドカード構文を使うと柔軟に設定できる。"Bash(npm run *)" は npm run build、npm run test、npm run lint 全てを自動許可する。"Edit(/docs/**)" は docs/ ディレクトリ配下のファイル編集のみを自動許可する。
設計原則:Allowに追加するのは「何度やっても安全」と確認されたものだけ。初めて使うコマンドはaskで様子を見てからAllowに昇格させる。
Deny設定:絶対にClaude Codeに触らせないもの
機密ファイルの保護
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(**/*.pem)",
"Read(**/*.key)",
"Read(**/*credentials*)",
"Write(./.env)",
"Write(./.env.*)"
]
}
}
破壊的操作のブロック
{
"permissions": {
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force *)",
"Bash(git reset --hard *)",
"Bash(npm publish *)",
"Bash(curl *)",
"Bash(wget *)"
]
}
}
使用しないツールのブロック(トークン節約)
Claude Codeのシステムツールは約19,400トークン(コンテキストの9.7%)を消費している(参考値)。使わないツールをdenyすると、システムプロンプトから除外されてトークン消費が削減できる。JupyterNotebookを使わないプロジェクトでは、NotebookEdit と NotebookRead を deny するだけで数千トークンを節約できる。
機密ファイルの二重ブロック
settings.jsonのdenyだけでは「Readツール経由」のアクセスしかブロックできない。cat ~/.ssh/id_rsa のようなBashコマンドは別途ブロックが必要だ。
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(**/*.pem)"
]
},
"sandbox": {
"filesystem": {
"denyRead": [
"~/.aws/credentials",
"~/.ssh",
"~/.config/gcloud"
]
}
}
}
| 層 | ブロック対象 | 設定箇所 |
|---|---|---|
| permissions.deny | ReadツールによるAPI経由アクセス | settings.json |
| sandbox.filesystem.denyRead | Bashコマンド(cat等)による直接アクセス | settings.json |
注:
sandbox.filesystem.denyReadはナレッジベースで確認された設定項目だが、公式ドキュメントでの記載は変動する可能性がある。使用する前に最新のAnthropicドキュメントを確認すること。
プロンプトインジェクション攻撃では悪意あるコードにAIへの指示が埋め込まれ、Claude Codeが意図せず機密ファイルを読もうとする可能性がある。二重ブロックがこのリスクを大幅に低減する。
設定ファイルの管理:チーム設定と個人設定の分離
パーミッションはどのスコープで設定するかも重要で、4段階ある。
| スコープ | ファイル | 管理方法 |
|---|---|---|
| エンタープライズ | managed-settings.json | 組織ポリシー(上書き不可) |
| プロジェクト | .claude/settings.json | git管理・チーム共有 |
| ローカル上書き | .claude/settings.local.json | .gitignore・個人用 |
| ユーザー | ~/.claude/settings.json | 全プロジェクトに適用 |
私がチーム導入時に使っているディレクトリ構成はこうだ。
プロジェクトルート/
├── .claude/
│ ├── settings.json ← git管理(チーム共有のパーミッション)
│ └── settings.local.json ← .gitignore(個人のカスタマイズ)
└── .gitignore
└── .claude/settings.local.json ← 必ず除外
settings.json にはチーム全員に適用したいAllow/Deny設定を書き、settings.local.json には自分だけの追加Allow(開発中の特定スクリプトなど)を書く。
パーミッションモードの選択
コマンドラインからモードを指定することもできる。
| フラグ / モード | 動作 | 使いどき |
|---|---|---|
| デフォルト(なし) | settings.json設定に従う | 通常の開発 |
--permission-mode plan | 読み取り専用(Plan Mode) | 計画・調査フェーズ |
--dangerously-skip-permissions | 全確認をスキップ | CI/CDのみ・コンテナ内のみ |
--dangerously-skip-permissions はCI/CDのDockerコンテナ内など「コンテナ自体が安全な境界」になっている場合のみ使用する。ローカル開発では使わない。
権限の定期棚卸し
/permissions コマンドで現在有効な全権限設定を一覧表示できる。使い続けると「Always allow」で許可したルールが蓄積されるため、月1回の棚卸しで不要なAllowを削除する習慣をつけるとよい。
ビフォーアフター
Before(デフォルト設定のまま)
npm test を実行するたびに「許可しますか?」が来る。git status も確認。ファイル編集も確認。1セッションで何十回も「y」を押す羽目になり、面倒になって --dangerously-skip-permissions を使ってしまう。結果、.envファイルも破壊的コマンドも全て無制限に実行できる状態になる。
After(3層パーミッション設計)
npm run * は確認なしで即座に実行(Allow)。.env 読み取りは完全ブロック(Deny)。rm -rf * も完全ブロック(Deny)。git push は確認あり(Ask)。高速な自律実行と安全な境界線が両立する。
まとめ:今日からできること
- 今すぐ(5分):
.claude/settings.jsonにnpm run *とgit status/diffをAllowに追加する - 今日中:
.env・rm -rf *をDenyに追加する - 今週:
/permissionsで現在の権限設定を確認し、不要なAllow設定を整理する - チーム展開:
.claude/settings.jsonをgit管理し、settings.local.jsonを.gitignoreに追加する
「安全のためにすべて手動確認」でも「速度のためにすべて自動許可」でもなく、3層の設計で両方を手に入れる——それがパーミッション設計の醍醐味だと思っている。

コメント