AI に読まれる前提で、ローカル開発の運用を見直した
API キーや DB 接続情報、Bot Token などの secret 管理で、.env を使っている開発現場は多いと思います。
自分も長いこと普通に使ってきました。
ただ最近、AI コーディング支援や IDE 拡張を使う機会が増えてきて、以前より気になることが増えました。
-
.envを Git に入れなければ本当に十分か - ローカルにあるだけで読まれる可能性はないか
- 「このファイルは読まないで」と書いても信用していいのか
- プロンプトインジェクションや自動走査を完全に防げるのか
結論から言うと、自分は 「プロジェクト配下に平文のシークレットを置かない」 を優先して、.env を作らない運用に寄せることにしました。
この記事では、そう考えるに至った背景と、いま採っている運用方針を整理します。
.env が悪いというより、「平文のシークレットがプロジェクトにある」のがつらい
まず前提として、.env 自体が悪という話ではないです。
便利ですし、多くのフレームワークやツールが前提にしています。
ただ、自分の中で問題になってきたのは、.env という形式よりも 「プロジェクトフォルダ配下に平文のシークレットがあること」 でした。
これまでも .env には定番のリスクがありました。
- 誤って commit する
- 添付や画面共有で漏れる
- 引き継ぎ時に雑に受け渡される
- 別名ファイルに複製される
でも最近は、これに加えて別の観点が入ってきています。
- IDE 拡張が読むかもしれない
- AI エージェントが読むかもしれない
- 補助ツールが走査するかもしれない
-
.gitignoreに入っていても、ローカルにあれば参照対象になりうる
つまり、Git管理対象外であることと、安全であることは別になってきた、という感覚です。
「読まないで」と書いても、技術的保証にはなりにくい
ここが今回いちばん大きかったポイントです。
AI ツールに対して、
- このファイルは読まないで
- secret は送らないで
- このディレクトリは対象外にして
みたいな指示を書くことはできます。
でも、それがどこまで効くかは、かなり実装依存です。
しかも厄介なのは、直接こちらが命令しなくても、
- リポジトリ内のドキュメント
- コメント
- 外部から取り込んだテキスト
- 補助ツールの設定
みたいなところから、意図しない振る舞いにつながる可能性があることです。
プロンプトインジェクションも含めて考えると、
「読ませない」ことを完全に信じるより、そもそも置かないほうが強い と感じました。
そこで、「.env を作らない」運用に寄せた
考えた方針はかなり単純です。
-
.envは作らない - secret は OS のキーストアに保存する
- プロジェクトフォルダ配下に secret を含むファイルを置かない
- 実行時だけ環境変数として取り出す
要するに、secretをファイルとして置くのではなく、実行時に必要なぶんだけ参照するという考え方です。
この運用の全体像
実際の構成は、シンプルに言うと次のようになります。
- secret の実体は OS のキーストアに保存する
- プロジェクトには
.envを置かない -
.envrcには secret の値ではなく、取得コマンドだけを書く -
direnvがプロジェクトディレクトリに入ったときに.envrcを読み、環境変数を export する - アプリケーションは
.envではなく、通常の環境変数として値を参照する
図にすると、だいたいこんなイメージです。
OS key store
↓
secret 取得コマンド
↓
.envrc
↓
direnv
↓
process environment
↓
application
この構成では、secret をプロジェクト配下のファイルとして保持しません。
その代わり、シェルに入ったときに必要な値を取り出して環境変数へ展開します。
.envrc には secret ではなく、取得コマンドだけを書く
この方式のポイントは、.envrc の扱いです。
.envrc は secret を保存するファイルではなく、どこから値を取得するかを書くファイルとして使います。
イメージはこんな感じです。
SERVICE="myapp/dev"
export OPENAI_API_KEY="$(chezmoi secret keyring get --service "$SERVICE" --user openai_api_key)"
export DB_URL="$(chezmoi secret keyring get --service "$SERVICE" --user db_url)"
export SLACK_BOT_TOKEN="$(chezmoi secret keyring get --service "$SERVICE" --user slack_bot_token)"
ここで書いているのは secret そのものではなく、OS キーストアから取得するためのコマンドです。
この形にしておくと、.envrc がリポジトリに近い場所にあっても、そこに平文のシークレットを置かずに済みます。
direnv の役割
この構成で、.envrc を読み込んで実際に環境変数へ展開するのが direnv です。
direnv を使うと、プロジェクトディレクトリに入ったときに .envrc を読み込み、そこに書かれた export をシェル環境へ反映できます。
つまり、
- プロジェクトに入る
-
direnvが.envrcを読む - OS キーストアから secret を取得する
- 環境変数として使えるようになる
という流れになります。
.env ファイルを読む代わりに、ディレクトリ単位で環境を組み立てるイメージです。
この構成で chezmoi を使っている理由
この運用では、.envrc から OS のキーストアに保存した secret を取得します。
その取得部分で使っているのが chezmoi です。
chezmoi は dotfiles 管理ツールとして知られていますが、今回の用途では主に キーストア操作を共通化するための薄いラッパー として使っています。
macOS と Windows ではキーストアの扱いが異なりますが、chezmoi secret keyring ... のような形で扱うことで、.envrc やセットアップ手順をある程度そろえやすくなります。
つまり、dotfiles 管理をしたいというよりは、
OS ごとの差分を減らして、同じ運用文書で回しやすくするため に採用しています。
なぜクラウドの secret 管理にしなかったのか
もちろん、クラウドの secret 管理サービスを使う案もあります。
たぶん理想だけを言えば、そちらのほうがきれいです。
ただ、実際にはこういう事情がありました。
- 社内手続きが重い
- 権限まわりが面倒
- 小さな検証にはオーバーヘッドが大きい
- 結局、現場でローカル回避運用が始まりやすい
このあたりは組織や環境によると思いますが、少なくとも自分の状況では、
理想的だけど定着しない運用より、少し地味でも回る運用のほうが価値があると判断しました。
なので今回は、ローカルの OS キーストアを使う現実解に寄せています。
運用ルールとして置いたこと
実際にルール化したのは、だいたい次のようなものです。
-
.envは作成しない - secret は OS キーストアに保存する
-
.envrcには secret を書かず、取得コマンドだけを書く - プロジェクトフォルダ配下に secret を含むファイルを置かない
-
.envrcを変更したときだけdirenv allowする - 他人が変更した
.envrc/.envrc.tmplは、中身を確認してからdirenv allowする
特に最後の direnv allow は重要だと思っています。
.envrc は単なる設定ファイルではなく、実行されるコードでもあるからです。
なので、他人の変更を差分確認せずに許可するのは避けたほうがいい、という考え方です。
この方式で防ぎたいこと
この運用で主に防ぎたいのは、ファイルとして secret が残ることによる事故 です。
たとえば、
-
.envの誤 commit - 一時ファイルの置き忘れ
- AI/IDE によるローカルファイル参照
- 引き継ぎ時の雑な共有
- 誤添付や誤共有
あたりです。
一方で、これは万能ではありません。
実行時には環境変数として値を展開するので、次のような問題は別途気をつける必要があります。
- ログへの出力
- デバッグで
process.envを丸ごと出す - 子プロセスへの継承
- アプリ側の例外メッセージに接続文字列が出る
つまりこの方式は、secret のファイル残置リスクを下げる ものであって、
実行時露出を完全になくすものではありません。
手間は増える。でも毎日はそこまで重くない
正直に言うと、初回セットアップは .env 方式より面倒です。
-
direnvを入れる -
chezmoiを入れる - secret をキーストアに登録する
-
.envrcを作る -
direnv allowする
このへんは確かに重いです。
ただ、日常運用はかなり普通です。
- プロジェクトに入る
- 開発コマンドを打つ
基本はそれだけです。
なので、コストの本体は「毎回の運用」より
初回導入の学習コストと心理的ハードル にあると思っています。
このへんをどう下げるかは、運用を広げるうえでかなり重要そうです。
いまの自分の結論
現時点では、次の考え方に落ち着いています。
AI や補助ツールがローカルファイルを参照しうる環境では、
「読まないで」と運用で期待するより、読まれて困る平文のシークレットをプロジェクト配下に置かないほうが扱いやすい。
たぶん将来的には、
- 短寿命トークンを使う
- アプリが必要時に secret manager から直接取得する
- 人手で長寿命の API キーを持たない
みたいな方向のほうが強いと思います。
ただ、ローカル開発でそこまで一気にやるのは重い。
なので今は、OS キーストア + .envrc + .env 非生成 くらいが、現実的な落としどころかなと思っています。
おわりに
以前の .env 議論は、主に「Git に入れるな」が中心でした。
でも今は、それだけでは少し足りない気がしています。
ローカルにあるだけで、参照されたり、送信対象になったりする可能性がある。
そう考えると、secret管理の論点はバージョン管理から配置と露出面に少し移ってきています。
なお、ツールによっては挙動を設定で調整できるものもあります。たとえば Claude Code では settings.json で .env の読み込みを制御できます。
それでも、自分は codex や Copilot のような支援ツールも含め、ワークスペース上のファイルは参照・編集対象になりうる前提で運用を考えるのが無難だと感じています。
同じようなことを考えている人がいたら、
「うちではこうしている」「こういう代替案もある」といった知見があれば、ぜひ知りたいです。
※ 本記事の構成整理と表現のブラッシュアップには生成AIを利用しています。内容の判断、事実確認、最終編集は筆者が行っています。