Claude Code用Cloudflare APIトークンの権限はどこまで絞れる?

  • 2026-10-21
Claude Code用Cloudflare APIトークンの権限はどこまで絞れる?

Claude CodeなどのAIエージェントにCloudflareの作業を任せるとき、渡すAPIトークンの権限は「とりあえず全権限、あとで絞る」ではなく、任せる操作を先に書き出し、その操作に必要な分だけを付けるのが安全です。Workersなら個別のWorkerに絞ったEditorロールでデプロイまで任せられ、Workerの作成や削除の権限は手元に残せます。一方で、wranglerでR2にアップロードする操作のように、細かく絞ると403で止まるものもあるため、権限と一緒に「どの経路で操作させるか」も最初に決めておきます。

この記事は、2026年10月時点のCloudflareとClaude Codeの公式ドキュメント、wranglerのソースコード、GitHubのissueに基づいています。

AIが書いたコードを人が一行ずつ読まずに取り込む進め方が広がるほど、人が確実に確かめられる境界は、エージェントに渡す権限の設定になります。開発中は広い権限で任せ、仕上げで絞る運用もよく見かけますが、そこには「何に絞ればよいのか」と「広い権限のあいだに事故が起きたらどうなるのか」という2つの弱点があります。

「とりあえず全権限、あとで絞る」で起きること

広い権限のあいだに起きうること

Cloudflareの公式ドキュメントでは、多くの権限に「Edit」と「Read」があり、Editは作成、読み取り、更新、削除、一覧のすべてを含むと説明されています。APIリファレンスでも、Workerのアップロードと削除、R2のバケットの作成と削除、KVの名前空間の作成と削除、Pagesのデプロイとプロジェクトの削除は、それぞれ同じ権限で実行できます。デプロイのために付けたEditは、そのまま削除の権限でもあります。

Workers向けのテンプレート「Edit Cloudflare Workers」をそのまま使うと、R2とKVの書き込み権限まで付きます。Workerをデプロイしたいだけなのに、アカウント内のR2のバケットまで消せるトークンになります。

指示で止めればよいとは言えません。2025年7月には、AIのコーディングサービス「Replit」のエージェントが、変更しないよう指示されていた期間中に本番のデータベースを削除したと報じられました(AI Incident Databaseの記録と報道による)。運営会社は、開発用と本番用のデータベースを自動で分ける対策を発表しました。Claude Codeの公式ドキュメントも、CLAUDE.mdなどの指示は許可の範囲を変えないと明記しています。

トークンが漏れたときも、権限が広いほど被害は大きくなります。漏れたクラウドの鍵で高額な請求が来た事例は、【サーバーレス破産】AWS Lambda が再帰実行されて潰れた会社でも取り上げました。

最後に絞ると403で止まる

作業の途中では、動いたら後で絞ればよいと考えがちです。しかし最後に絞ると、どの操作にどの権限が要っていたのかを、403のエラーで一つずつ知ることになります。R2へのアップロードのように、権限を正しく選んでも、操作の経路のせいで403になるものもあります。403が出るたびに権限を広げ直していると、結局は最初の広いトークンに戻ってしまいます。

全権限で渡す、作業が進む、最後に絞る、403で止まる、また広げる、の順に進み、また全権限で渡す状態に戻る悪循環。抜け道は、全権限で渡す前に、操作ごとに必要な権限を先に決めること。

wrangler login も、公式ドキュメントによると、フラグを付けなければ使えるスコープをすべて要求します。2026年8月からは同意画面で任意のスコープを外せるようになりましたが、次の節で説明する個別のWorker単位の権限には対応していません。

操作ごとに必要なCloudflare APIトークンの権限

以下は、Cloudflareの公式ドキュメントとAPIリファレンスの記述を、操作ごとにまとめたものです。権限名はダッシュボードでは「Edit」、APIでは「Write」と表記されますが、同じ権限を指しています。

Workers: 個別のWorkerにEditorを付ける

2026年9月に更新されたWorkersのドキュメントでは、Workersの権限が4つのロールで説明されています。

ロールできることできないこと
Metadata Read-Only設定、メトリクス、ログの閲覧コードやシークレットの閲覧
Content Read-Only上に加えてコードの閲覧変更
Editor既存のWorkerの更新、デプロイ、名前の変更Workerの作成と削除
Admin作成と削除を含むすべてなし

ロールは「Workers全体」か「個別のWorker」に割り当てます。AIエージェントに向くのは、対象のWorkerだけに付けたEditorです。wranglerのコマンドごとの最小のロールは、公式ドキュメントで次のように示されています。

操作wranglerのコマンド必要なロール
既存のWorkerのデプロイwrangler deployそのWorkerのEditor
バージョンの登録、切り替え、ロールバックwrangler versions upload などそのWorkerのEditor
シークレットの追加、削除wrangler secret put などそのWorkerのEditor
ログの確認wrangler tailそのWorkerのMetadata Read-Only
新しいWorkerの作成初回の wrangler deployWorkers全体のAdmin
ルートやカスタムドメインの変更wrangler deployEditorと、対象ゾーンのWorkers Routes

注意点は3つです。まず、個別のWorkerのロールは、まだ存在しないWorkerには付けられません。新しいWorkerの作成にはWorkers全体のAdminが要るので、最初の1回は人が作り、そのあとでAIにEditorを渡します。次に、細かい権限をwranglerで使うには、Account APIトークン(ユーザーではなくアカウントに属するトークン)で認証する必要があります。最後に、KV、R2、D1のバインディングを持つWorkerでも、デプロイに要るのはWorkerのEditorだけです。バインド先の権限は、AIがコマンドで直接データに触るときにだけ必要です。なお、カスタムドメインは個別のWorkerのロールにまだ対応していないと、公式に書かれています。

従来の「Workers Scripts」のEditも使えます(廃止日は未定)。ただ、APIリファレンスでは従来の権限でWorkerを削除できるため、新しく作るトークンでは、Editorを選べば削除の権限を外せます。

Pages、R2、D1、KV: アカウント単位の権限が中心

Workers以外の製品は、公式ドキュメントで確認できる範囲では、アカウント単位の権限が中心です。バケット単位に絞れるのはR2だけです。

操作必要な権限同じ権限でできること絞れる単位
PagesのデプロイCloudflare Pages の Editプロジェクトの作成、削除アカウント
R2へのアップロード(wrangler)Workers R2 Storage の Editバケットの作成、削除、設定変更アカウント
R2へのアップロード(S3互換API)R2のObject Read & Writeオブジェクトの読み書き、一覧バケット
D1へのSQLの実行D1 の Editデータベースの作成、削除アカウント
KVへの値の書き込みWorkers KV Storage の Edit名前空間の作成、削除アカウント

D1のSQLを実行するAPIは、APIリファレンスでは「D1 Read」と「D1 Write」のどちらも受け付けます。ただ、D1 Readのトークンで書き込みのSQLが拒まれるかどうかは、公式に明記されていません。読み取りだけのつもりでも、本番のデータベースには向けないほうが安全です。

D1とKVの権限はアカウント全体に及ぶので、同じアカウントに本番のデータベースがあれば、AIに渡したトークンでもそのデータベースを操作できます。その場合は、AIにD1とKVの権限を渡さず、本番へのマイグレーションは人かCIで実行する、という分け方が考えられます。

wranglerでR2にアップロードすると403になる理由

公式ドキュメントの記述

R2の画面から作るトークンには、Admin Read & Write、Admin Read only、Object Read & Write、Object Read onlyの4種類があり、Objectの2つはバケットを指定して絞れます。

ところがR2の公式ドキュメントには、Objectの2つはS3互換APIでだけ使え、CloudflareのREST APIでは使えないと書かれています。そして wrangler r2 object put は、REST APIでアップロードします。2026年10月時点のwranglerのソースコードでも、アップロードの処理はREST APIの /accounts/<アカウントID>/r2/buckets/<バケット名>/objects/<キー> へのリクエストです。バケット単位のトークンでwranglerから上げると403になるのは、このためです。

issue #9235とその後

この挙動は、2025年5月にwranglerのリポジトリのissue #9235で報告されています。wrangler 4.14.0で、Object Read & Writeのトークンを使ってアップロードすると403(Forbidden)になり、Admin Read & Writeに上げると成功した、という内容です。issueは、報告者自身が「wrangler CLIでR2にアップロードするにはAdminのRead & Writeトークンを使うのが意図された動作」とコメントして閉じています。

その後に挙動が変わったかどうかは、次の3点から判断できます。

  • wranglerのリポジトリには、この挙動を変えるissueやプルリクエストが見当たらない
  • 2026年10月21日時点の最新版は4.151.3で、mainブランチのアップロード処理は上記のREST APIのまま
  • 2026年7月と9月にも、別の公開リポジトリが同じ403を理由にS3互換APIでのアップロードへ切り替え、このissueを参照している

以上から、2026年10月時点でも、wranglerでR2にアップロードさせるには、アカウント単位のR2の権限が必要な状況だと考えます。

回避策はS3互換APIで上げる

AIエージェントにR2へのアップロードを任せるなら、wranglerではなく、S3互換APIのクライアントを使わせます。R2の画面でObject Read & Writeのトークンを作って対象のバケットだけを選び、表示されるAccess Key IDとSecret Access Keyを使います(Secret Access Keyは一度しか表示されません)。AWS CLIなら、公式ドキュメントの例に沿って次のように上げられます。regionは auto でよいとされています。

# R2の画面で作った「Object Read & Write」(対象のバケットだけ)のキーを使う
export AWS_ACCESS_KEY_ID="<Access Key ID>"
export AWS_SECRET_ACCESS_KEY="<Secret Access Key>"
export AWS_DEFAULT_REGION=auto

aws s3 cp ./dist/app.js s3://my-dev-bucket/app.js \
  --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com

rcloneでも同じキーを使えます。rcloneの設定例は、Cloudflare R2で圧縮コンテンツを保存および配信する方法と実用例で紹介しています。

AIエージェント用のトークンを作る手順

AIエージェント用のトークンを作る6つの手順。先に決める段階で、操作を書き出し、本番と開発を分ける。作って渡す段階で、トークンを作成し、権限と範囲を選び、期限とIPを設定し、古い認証を消してから渡す。

1. 任せる操作を書き出す

AIに実行させる操作を書き出し、人の手元に残す操作も決めます。Workerの作成と削除、本番へのデプロイ、データベースの削除、DNSや課金に関わる設定は、AIに任せる理由がなければ残しておきます。

2. 本番用と開発用を分ける

AIに渡すのは開発用のトークンだけにして、本番へのデプロイは人か、別のトークンを持たせたCIで実行します。CloudflareのCIの案内でも、トークンはCIのシークレットに保存し、リポジトリに置かないよう説明されています。開発用のWorkerを別に作っておけば、AIの権限をそのWorkerだけに限定できます。

3. Account APIトークンを作る

ダッシュボードの「Manage account」から「Account API tokens」を開き、「Create Token」で作ります。Workersの細かい権限をwranglerで使うには、このAccount APIトークンが必要です。

4. 権限とリソースを選ぶ

書き出した操作ごとに、「操作ごとに必要なCloudflare APIトークンの権限」の表から権限を選びます。開発用のWorkerだけにEditor、ルートを変えるならそのゾーンだけにWorkers Routes、という具合です。テンプレートの「Edit Cloudflare Workers」はR2とKVの書き込み権限を含むので、そのままは使いません。R2へのアップロード用には、R2の画面でバケット単位のトークンを別に作ります。アカウントIDを環境変数 CLOUDFLARE_ACCOUNT_ID で渡しておくと、wranglerはアカウントをAPIに問い合わせずに決めます。

5. 有効期限とIPアドレスを設定する

公式ドキュメントによると、何も設定しなければトークンに期限はありません。作成画面のTTL(Account APIトークンでは有効期限)で、使う期間に合わせた終了日を設定します。日付はUTCの0時(日本時間の午前9時)で区切られます。作業する場所のIPアドレスが固定なら、Client IP Address Filteringで使える範囲も絞れます。

6. 古い認証を消してから渡す

wranglerのソースコードでは、環境変数のトークンがなければ、以前の wrangler login で保存したOAuthの認証情報を使います。AIが環境変数を外してwranglerを動かすと、ログインしたときの広い権限で動くので、wrangler logout で認証情報を消してからトークンを渡します。

# wrangler loginの認証情報が残っていれば消す
npx wrangler logout

# AI用のトークンを、このターミナルだけに設定する(シェルの履歴に残さないよう read で入力する)
read -rs CLOUDFLARE_API_TOKEN && export CLOUDFLARE_API_TOKEN
export CLOUDFLARE_ACCOUNT_ID="<アカウントID>"

# どの認証で動くかを確かめてから起動する
npx wrangler whoami
claude

~/.zshrc などに書くと、ほかの作業のターミナルにも同じトークンが入るので避けます。

Claude Code側の権限設定(permissions)とトークンの渡し方

permissionsのallow、ask、deny

Claude Codeの権限は、設定ファイルの permissions に書きます。チームで共有するなら .claude/settings.json、自分だけなら .claude/settings.local.json、すべてのプロジェクトに適用するなら ~/.claude/settings.json です。ルールは、確認なしで実行させるallow、毎回確認するask、実行させないdenyの3種類です。公式ドキュメントによると、評価はdeny、ask、allowの順で、最初に合ったものが結果になり、allowでdenyの例外は作れません。

次は、wranglerの削除系をdeny、デプロイやデータに触れる操作をaskにする例です。公式ドキュメントの照合の規則に沿って、npx で実行する前提で書いています。npx は照合の前に外されないため、pnpm や wrangler を直接使う場合は、その形のルールも足します。

{
  "permissions": {
    "deny": [
      "Bash(npx wrangler delete *)",
      "Bash(npx wrangler * delete *)",
      "Bash(npx wrangler login *)",
      "Read(./.env)",
      "Read(./.env.*)"
    ],
    "ask": [
      "Bash(npx wrangler deploy *)",
      "Bash(npx wrangler versions *)",
      "Bash(npx wrangler rollback *)",
      "Bash(npx wrangler secret *)",
      "Bash(npx wrangler d1 *)",
      "Bash(npx wrangler kv *)",
      "Bash(npx wrangler r2 *)",
      "Bash(npx wrangler pages *)"
    ],
    "allow": [
      "Bash(npx wrangler dev *)",
      "Bash(npm run build)"
    ]
  }
}

2つ目のdenyは、npx wrangler d1 delete のように、途中に delete を含むコマンドに合います。

なお、権限の確認を飛ばすbypassPermissionsモードは、コンテナやVMのような隔離された環境だけで使うよう、公式ドキュメントで警告されています。

ルールだけでは境界にならない

Claude Codeの公式ドキュメントは、Bashのdenyやaskについて、Claudeがふだん書く形のコマンドを止めるもので、プログラムの周りのセキュリティ境界ではないと説明しています。たとえば Bash(rm *) は、/bin/rm と絶対パスで書いたものや、bash -c の中で実行したものを止めません。Read(./.env) のdenyも、スクリプトが自分でファイルを開く場合には効きません。

そのため、Claude Code側のルールは事故を減らす層、トークンの権限は被害の上限を決める層、と役割を分けて考えます。ルールをすり抜けた操作も、トークンに権限がなければCloudflareの側で拒否されます。AIに作業を任せるほど、こうした境界を先に決めておくことが、人に残る仕事になります。

トークンはAIから読める前提で渡す

Claude Codeのドキュメントによると、Claude Codeが実行するコマンドは、Claude Codeの環境変数を秘密の値も含めて受け継ぎます。資格情報を取り除く設定(CLAUDE_CODE_SUBPROCESS_ENV_SCRUB)もありますが、サブプロセスがその変数を必要とするなら使わないよう案内されています。wranglerにトークンを使わせる以上、AIはそのトークンを読める前提で権限を決めます。

wranglerのドキュメントはトークンを .env に書く方法を推奨していますが、ローカル開発では .env の値がWorkerの env にも読み込まれます。AIに渡すトークンは、起動するターミナルの環境変数で渡すほうが扱いやすいと考えます。

環境変数を見せない設定もある

Claude Codeのサンドボックスには、コマンドには置き換えの値だけを見せ、許可したホストへの通信でだけ本物の値に差し替える「マスク」の設定があります。TLS終端などの設定が必要で、リポジトリの .claude/settings.json に書くと無視されます。wranglerとの組み合わせは公式に記載がないため、使うなら動作を確かめてからにしてください。

よくある質問

wrangler loginとAPIトークンはどちらを使う?

AIエージェントに任せるなら、APIトークンです。wrangler login はフラグを付けなければすべてのスコープを要求し、Worker単位の権限にも対応していません。認証情報は、標準では ~/.config/.wrangler/config/default.toml に平文で保存されます。

トークンを漏らしたときは?

ダッシュボードでトークンを削除するか、Roll(作り直し)します。公式ドキュメントによると、Rollすると古いトークンは無効になり、新しいトークンは同じ権限を持ちます。ユーザーのトークンは「My Profile」の「API Tokens」、Account APIトークンは「Manage account」の「Account API tokens」にあります。

公開リポジトリに上げてしまったトークンは、GitHubのSecret Scanningを通じてCloudflareが自動で失効させ、メールで知らせると説明されています。非公開リポジトリでは通知が届くので、自分で作り直します。権限が小さければ、そのあとで確かめる範囲も小さく済みます。

有効期限やIP制限は付けたほうがいい?

付けておくのが無難です。IPアドレスの制限は固定のIPアドレスから作業する場合に使えます。なお、この制限はトークンを検証するエンドポイント(/user/tokens/verify)には適用されません。

Claude Codeの権限設定だけでは足りない?

足りません。denyやaskはコマンドの文字列で照合するので、書き方を変えたコマンドはすり抜けることがあります。Cloudflareのサーバーで判定されるトークンの権限と組み合わせます。

403が出たらどう調べる?

まず、エラーに出ているAPIのパスを見ます。/r2/ ならR2、/d1/ ならD1、/storage/kv/ ならKV、/workers/ ならWorkers、/pages/ ならPagesの権限が足りていません。この記事の表と照らし合わせて、足りない権限を1つだけ足します。wranglerでR2に上げて403になった場合は、権限を広げずに、S3互換APIへ経路を変えます。