- AIコーディングエージェントがローカルのファイルを読み書きする時代、「.envはgitignoreしているから安全」という前提はもう成り立たない。gitignoreはgitの管理対象から外す設定にすぎず、ファイルシステムの読み取り権限には一切関与しない。
- Cloudflare Workersでは、機密情報をvarsに置かず、Worker単位で閉じるWorker Secretsか、アカウント単位で複数のWorker・AI Gatewayと共有するSecrets Store(2026年8月時点はオープンベータ)を使い分ける。設定ファイルにシークレット名を宣言しておけば、デプロイ前に未設定を検知できる。
- 環境ごとの分離、CI/CDのデプロイトークンの最小権限、漏洩時のローテーション手順、ローカル開発と個人の秘密の置き場所まで、実務で回せる型として整理する。
なぜ今、.envにAPIキーを置くのは危険なのか?
AIコーディングエージェントがローカルのファイルを読み書きする時代になり、「gitignoreしているから安全」という前提が成り立たなくなったから。
.envファイルにAPIキーを平文で書き、.gitignoreに追加してリポジトリの管理対象から外す。長らく開発現場の標準的なやり方とされてきたこの運用は、単純な前提の上に成り立っている。「ファイルの中身を実際に読むのは、そのマシンにログインできる人間だけ」という前提だ。他人がリポジトリを取得しても.envは含まれておらず、ローカルの.envファイルそのものを覗き見られる機会は限られる、という考え方である。
この前提は、AIコーディングエージェントの実務利用が広がったことで崩れている。コードを書くために、エージェントは対象ディレクトリのファイルを横断的に読み、必要であればコマンドも実行する。ここで見落とされがちなのは、ファイルを読む際にエージェントが.gitignoreを参照する義務はどこにもない、という点だ。.gitignoreはgit add・git status・git commitといったgit自体の挙動を制御する設定であり、OSのファイルシステム上での読み取り権限には一切関与しない。エージェント側から見れば、.envもソースコードのファイルも同じ「読めるファイル」でしかない。
「.envさえgit管理から外していれば安全」という認識のまま、AIエージェントに「このプロジェクトのAPI周りの設定を確認して」と頼めば、.envの中身はそのままエージェントの作業文脈に載る。悪意がなくても、その内容がログや会話の履歴、あるいは外部サービスに送る要約の中に紛れ込む経路は一つではない。さらに厄介なのは間接的な経路だ。エージェントが外部のWebページやドキュメントを読み込んで作業する構成では、悪意ある指示がその中に埋め込まれ、ローカルのファイルを読み上げて外部に送信させるという攻撃も報告されている。攻撃者が.envの存在とパスを推測できれば、それはエージェント自身に「読んで教えて」と頼むだけの攻撃になりうる。こうした間接的な指示混入の型は、LLMアプリのガードレール設計で扱ったプロンプトインジェクションと同じ構造を持つ。
「gitignoreしているから安全」という説明が成り立つのは、リスクの発生源を「他人がリポジトリを見るケース」だけに限定していたときの話だ。ローカルのファイルシステムを横断的に読み書きするエージェントが標準的な開発ツールになった以上、守るべき境界線はリポジトリの外側ではなく、値がどこに平文で存在するかに引き直す必要がある。
図:境界線は「gitで管理しているか」ではなく、「AIツールのプロセスが直接読める場所に平文で存在するか」で引き直す。
Cloudflare Workersでは、シークレットをどこに置くのが正しいのか?
機密情報はvarsに置かず、Worker単位ならWorker Secrets、複数Workerで共有するならSecrets Store(2026年8月時点はオープンベータ)を使う。
Cloudflareの公式ドキュメントは、この点で明確に線を引いている。Workerの設定ファイルのvarsに機密情報を保存してはならず、代わりにsecretsを使うこと、と明記されている。varsは設定ファイルにそのまま平文で書かれる値で、リポジトリにコミットされる前提の項目だ。APIのベースURLや機能フラグのような「知られても困らない設定値」には向くが、APIキーやトークンのような機密情報をvarsに書けば、.envと同じ問題——平文でリポジトリに残る——を、今度はCloudflareの設定ファイルの中で再現することになる。
機密情報の置き場所は、実務では2つに分かれる。1つのWorkerだけが使うならWorker Secrets、複数のWorkerやAI Gatewayで共有するならSecrets Storeだ。両者は置き場所が違うだけでなく、設計思想そのものが異なる。Worker SecretsはWorker単位・環境単位で閉じたスコープを持ち、wrangler secret putコマンドで値を登録すると新しいWorkerバージョンが作成されて即座にデプロイされる。段階的デプロイ(gradual deployments)を使う構成では、即時に有効化しないwrangler versions secret putを使う場面も出てくる。一方のSecrets Storeはアカウント単位で一元管理する仕組みで、1つのシークレットを複数のWorkerから同じバインディングで参照できる。ただし2026年8月時点ではオープンベータの段階にあり、対応する製品もWorkersとAI Gatewayに限られる。中国リージョンでは利用できない。
| 項目 | vars | Worker Secrets | Secrets Store |
|---|---|---|---|
| 適した用途 | 機密でない設定値(ベースURL、機能フラグなど) | 単一Workerだけが使う機密情報 | 複数のWorker・AI Gatewayで共有する機密情報 |
| スコープ | Worker単位 | Worker単位(環境ごとに分離可) | アカウント単位 |
| 値の保存 | 設定ファイルに平文で記述 | Cloudflare側で暗号化保存。設定ファイルには名前のみ残る | Cloudflare側で暗号化保存。ストアとして一元管理 |
| 主なコマンド | 設定ファイルに直接記述 | wrangler secret put <NAME> | wrangler secrets-store secret create <STORE_ID> |
| ローカル開発 | 設定ファイルの値がそのまま使われる | .dev.vars/.envで値を用意 | ローカルでの扱いは2026年8月時点で公式の明記なし(要確認) |
| 2026年8月時点の位置づけ | 標準機能 | 標準機能 | オープンベータ(Workers・AI Gatewayのみ対応、中国リージョン非対応) |
設定ファイルには、実際の値を書く代わりに「このWorkerにはこの名前のシークレットが必要だ」という宣言だけを残せる。secretsプロパティに必要な名前を列挙しておくと、wrangler deployやwrangler versions uploadを実行したタイミングで、宣言済みの名前のうち未設定のものがあれば明確なエラーで失敗する。「デプロイは通ったのに、本番で機密情報が空だった」という事故を、デプロイの前に潰しておける仕組みだ。
図:secretsプロパティに名前を宣言しておくと、未設定のままのデプロイをその場で止められる。エラー文言は要点を示すための再現イメージで、正確な表示は使用するwranglerのバージョンで確認してほしい。
複数のWorkerで同じシークレットを共有したい場合は、Secrets Store側の設定になる。設定ファイルにsecrets_store_secretsとしてバインディング名・ストアID・シークレット名を宣言し、Worker内のコードからは非同期のget()で値を取り出す。登録はwrangler CLIから行う。
図:Secrets Storeはstore_id(ストアのID)を介して、複数のWorkerから同じシークレットを参照できる。環境ごとに異なる値を持てるかは2026年8月時点の公式ドキュメントに明記がなく、要確認。
筆者自身の運用でも、設定ファイルには実際のキーの値を一切書いていない。書くのはシークレットの名前だけで、設定ファイルのコメントに「値はリポジトリへ保存しない」「以下のコマンドで登録する」という手順そのものを残している。値そのものではなく、値を登録する手順をリポジトリに残す発想に切り替えると、新しいメンバーが加わっても「このプロジェクトにはどんなシークレットが必要か」が設定ファイルを読むだけで分かる一方、実際の値はCloudflare側にしか存在しない状態を保てる。
なお.dev.varsや.envは、あくまでローカル開発限定の仕組みだ。公式ドキュメントも、ローカル開発用のシークレットはこれらのファイルに置くと案内する一方、「gitにコミットしてはならない」「.dev.vars*と.env*を.gitignoreに追加すること」と重ねて注意している。本番の値の置き場所ではない、という位置づけを取り違えないことが出発点になる。個人だけが使う秘密をこのファイルにさえ置かない方がよい理由は、後段の「ローカル開発と個人の秘密」で扱う。
環境ごとの分離と、CI/CDでは何に気をつけるべきか?
環境ごとにシークレットを分離し、デプロイトークンの権限を最小化し、設定ファイルへの宣言でデプロイ前に検証する。
開発環境と本番環境で同じAPIキーを使い回すと、開発中の事故がそのまま本番の被害になる。Worker Secretsは環境ごとに値を分離できるため、wrangler secret put --env productionのように対象の環境を明示して、開発用と本番用に別のキーを登録しておく。ローカル側も同様で、.dev.vars.productionや.env.stagingのように環境名を付けたファイルを使い分ければ、ローカルの検証環境から本番のキーが誤って読まれる事故を防げる。
CI/CDのデプロイトークンについても同じ発想が要る。CloudflareのAPIトークンは、古い形式のGlobal API Keyと違ってスコープを絞って発行できる。CI/CD専用のデプロイトークンには、対象アカウントでWorkerをデプロイする権限だけを与え、DNSの変更や他のWorkerの削除、請求情報の閲覧といった無関係な権限は持たせない。このトークン自体もCI側のシークレットストア(GitHub ActionsのSecretsなど)に保管し、ビルドログにそのまま出力されないようにする。トークンが漏れたときに広がる被害の天井を、権限のスコープであらかじめ決めておくという考え方だ。
事前検証の仕組みは、CI/CDと特に相性がいい。人がターミナルでwrangler deployを打つ場面では、登録し忘れに気づく余地がまだ残る。だがCI/CDのパイプラインは、指示された手順を淡々と実行するだけだ。設定ファイルにsecretsの宣言をしておけば、シークレットの登録漏れをCIのその場で検知でき、「デプロイは成功したように見えたのに、本番で機能が動いていなかった」という事後発覚を防げる。
| チェック項目 | やること | ねらい |
|---|---|---|
| デプロイトークンの権限 | Global API Keyではなく、Workerのデプロイだけに絞ったAPIトークンを発行する | トークンが漏れたときの被害範囲を限定する |
| トークンの保管 | CI側のシークレットストア(GitHub ActionsのSecretsなど)に保管し、ビルドログに出力しない | ログ経由の漏洩を防ぐ |
| シークレットの事前宣言 | 設定ファイルのsecretsプロパティに必要な名前を列挙する | 未設定のままのデプロイをCIの時点で失敗させる |
| 環境ごとの分離 | 開発・本番でシークレットとデプロイ対象の環境を分ける | 開発中の事故が本番に波及しないようにする |
環境の分離とトークンの最小権限は、どちらも「漏れないようにする」対策ではなく「漏れたときの被害を小さく区切っておく」対策だ。完全に漏れを防ぐことは前提にできない。
シークレットが漏れたとき、何をすればよいのか?
発行元サービスでの失効を最優先に、影響範囲の特定→新しい値への切り替え→不正利用の確認という順で動く。
漏洩に気づいたときにやることは、優先順位を間違えると意味がなくなる。最優先は、Cloudflare側で新しい値に差し替えることではなく、漏れたキーそのものをその発行元のサービス側で無効化することだ。wrangler secret putで新しい値に上書きしても、旧いキーがAnthropicやOpenAIといった発行元サービス側でまだ有効なままなら、それを手にした第三者はCloudflareを経由せずに直接そのサービスを使い続けられる。Cloudflare側の入れ替えは、あくまで自分のWorkerが正しいキーを使う状態に戻すための作業であって、漏れたキー自体を無力化する作業ではない。
| 順番 | やること | 目的 |
|---|---|---|
| ① 発行元での失効 | 漏れたキーを発行したサービス(Anthropic Console、OpenAIの管理画面など)側でそのキーを無効化する | 漏れたキー自体を使えなくする(最優先) |
| ② 影響範囲の特定 | 設定ファイルのsecrets宣言や環境ごとの登録状況を確認し、どのWorker・どの環境で使われていたかを洗い出す | 差し替えが必要な範囲を漏れなく把握する |
| ③ 新しい値への切り替え | 発行元で新しいキーを発行し、影響範囲すべてにwrangler secret putで登録し直す | サービスを正しいキーで動く状態に戻す |
| ④ 利用状況の確認 | 発行元サービス側のAPI利用ログとCloudflare側の監査ログを確認する | 不正利用の痕跡と被害範囲を確定させる |
| ⑤ 再発防止 | そのシークレットがsecrets宣言に載っていたか、平文でコミットされた形跡がなかったかを振り返る | 同じ経路で次が漏れないようにする |
「いつ、どのキーが、どの経路で漏れたか」を後から追えるかどうかは、平時にどれだけ記録を残しているかで決まる。設定ファイルにシークレット名を宣言しておく運用は、デプロイ前検証だけでなく、漏洩時に「このWorkerが依存しているシークレットの一覧」としてもそのまま機能する。日々の手間を惜しんで平文管理に戻せば、この一覧そのものが失われる。
ローテーションは「新しい値に差し替えて終わり」ではない。発行元での失効を飛ばした差し替えは、鍵を替えたつもりでいるだけで、実際には古い合鍵がまだ外に配られている状態と変わらない。
ローカル開発と個人の秘密は、どこに置けばよいのか?
チーム共有の開発用値は.dev.vars、個人だけの秘密はOSのシークレットストア(Keychain等)に置き、AIツールが直接読めない場所に分離する。
チームで共有する開発用の値と、個人だけが使う秘密は、置き場所を分けて考える。チーム開発でよく使うのは.dev.varsだ。前段で触れた通り、ローカル限定の仕組みであり、gitにコミットしないことが公式にも案内されている。ここまでは複数人のチームで共有する前提の値の話だ。
個人だけが使う秘密——自分のマシンでだけ動かす検証スクリプトのAPIキーなど——は、.dev.varsのようなプロジェクトファイルにすら置かない方がよい。macOSであればKeychainが候補になる。security add-generic-passwordコマンドでKeychainに保存した値は、取り出す際にユーザーのログイン認証(パスワードや生体認証)を求められる設定にできる。AIエージェントのプロセスは、この認証を代わりに突破する手段を持たない。ファイルとして存在する.envとの決定的な違いはここにある。
図:Keychainから値を取り出す際にユーザー認証を求める設定にしておけば、プロセスとして動くAIエージェントが代わりに認証を突破することはできない。
個人の手元を超えて、チームや複数の環境で使う秘密になった段階では、置き場所も段階的に引き上げていく。優先順位を1枚にまとめると、次のようになる。
| 段階 | 置き場所 | 向いている用途 |
|---|---|---|
| ローカル・個人 | OSのシークレットストア(macOSならKeychain) | 自分のマシンだけで使う検証用の値。AIツールから直接読めない |
| チーム・複数環境 | Doppler/Infisicalなどのシークレットマネージャー | 複数人・複数環境で共有する値をCLIから環境変数として注入する |
| 本番・クラウド | Cloudflare Worker Secrets/Secrets Store、GCP Secret Manager、AWS Secrets Managerなど | 本番でアプリケーションが実際に読み込む値 |
| エンタープライズ | HashiCorp Vault | 大規模組織での一元管理・監査要件 |
| 最終手段 | .envファイル | 上記がすべて使えない場合のみ。使う場合もリスクを理解した上で |
秘密は、どこに「置くか」ではなく、誰が(何が)「読めるか」で管理する。
.envが「最終手段」だという位置づけ自体は変わっていない。変わったのは、その最終手段を選んだときに引き受けるリスクの大きさだ。以前は「他人にリポジトリを見られる」リスクだけを考えればよかったが、いまは「ローカルで動くツール全般に読まれる」リスクまで含めて引き受けることになる。なお、監査対応やSaaS選定の観点は情シス審査を通すSaaS設計、Cloudflareダッシュボード自体へのアクセス制御はCloudflare Accessによるゼロトラスト構成で扱っている。
よくある質問
いいえ。gitignoreはgitの追跡対象から外す設定であり、ファイルシステム上の読み取り権限には関与しません。AIコーディングエージェントなどのローカルツールは、gitで管理されているかどうかに関係なく、指定されたパスのファイルを読めます。ローカルに平文で存在する限り、リスクは残ります。
Worker Secretsは単一のWorker・環境に紐づく機密情報で、wrangler secret putコマンドで登録します。Secrets Storeはアカウント単位で管理し、複数のWorkerやAI Gatewayから同じシークレットを共有できる仕組みです。1つのWorkerだけが使うキーはWorker Secrets、複数のWorkerで共有するキーはSecrets Storeが候補になりますが、Secrets Storeは2026年8月時点でオープンベータであり、対応製品もWorkersとAI Gatewayに限られます。重要な用途では現在のステータスを公式サイトで確認してください。
2026年8月時点の公式ドキュメントには、この点についての明記がありません。Secrets Storeはアカウント単位で管理する設計のため、Worker Secretsのように環境ごとに値を分けられるとは限りません。環境ごとに異なる値が必須な用途では、断定せずCloudflareの公式サイトで最新の挙動を確認したうえで採用してください。
最優先は、そのシークレットの発行元サービス(Anthropic、OpenAIなど)側でキー自体を無効化することです。Cloudflare側でwrangler secret putにより新しい値へ差し替えても、漏れた旧キーが発行元サービス側で有効なままなら、それを手にした第三者はCloudflareを経由せずに使い続けられます。発行元での失効を最優先に、影響範囲の特定、新しい値への切り替え、利用ログでの不正利用有無の確認という順で進めてください。
