.env でシークレット管理をやめる方法を調べてみた
に公開※ 本記事の執筆、修正、校閲に AI を使用しています。
記事要約
.env にシークレットをプレーンテキストで保存する慣習は、OWASP が非推奨としているプラクティスです。さらにコーディングエージェントの普及により、.env のシークレットがプロンプトインジェクション等で外部に流出するリスクが現実的な脅威になっています。
エージェントの設定で .env を読めなくする対策はありますが、エージェントの自律性とのトレードオフが生じます。根本的な解決策は、シークレットをシークレットマネージャーに移し、.env には非秘匿の設定値だけを残すことです。
背景
筆者は Supabase を使うことが多く、ローカルで開発環境を構築できるため、.env にはローカルの接続情報だけを入れ、本番環境への接続情報は Vercel の環境変数で管理するという運用をしてきました。この構成では .env に秘匿情報が入らないため、特に問題にはなっていませんでした。
しかし、一部 SaaS のサービスを利用する上でローカル環境が構築できず、開発時にもそのサービスへ直接接続する必要が生じました。その接続情報を .env に入れて管理していたのですが、Claude Code で開発する際にシークレットが流出しないよう permissions.deny で .env の読み取りを禁止したところ、.env に依存するコマンドがすべて実行できなくなりました。開発サーバーの起動はもちろん、テストの実行も動作しません。
この問題をきっかけに、シークレットの管理方法について改めて調べてみようと思ったのがこの記事の出発点です。
.env にシークレットを入れる問題
OWASP の見解
OWASP Secrets Management Cheat Sheet は、シークレット管理について以下の要件を示しています。
- 一元管理(centralize and standardize)
- きめ細かなアクセス制御(fine-grained access controls, least privilege)
- 監査ログ(誰が・いつ・何のためにアクセスしたか)
- 自動ローテーションと動的シークレットの利用
- 暗号化(保存時・転送時ともに)
.env でのシークレット管理は、これらの要件をいずれも満たしません。プレーンテキストで暗号化なし、ファイルパーミッション以上のアクセス制御なし、監査ログなし、ローテーションは手動。
さらに OWASP は環境変数への秘匿情報の保存自体についても警告しています。
environment variables are generally accessible to all processes and may be included in logs or system dumps. Using environment variables is therefore not recommended unless the other methods are not possible
(環境変数は一般的にすべてのプロセスからアクセス可能であり、ログやシステムダンプに含まれる可能性がある。他の方法が利用できない場合を除き、環境変数の使用は推奨されない)
また OWASP SAMM では「本番環境のシークレットは常に暗号化して保存すること」「本番シークレットを開発・テスト環境の設定ファイルに入れないこと」が明記されています。
まとめると、OWASP の立場はこうです。
- シークレットをプレーンテキストの設定ファイル(
.envを含む)に保存するな - 環境変数にシークレットを入れることも非推奨(他の方法がない場合を除く)
- シークレットマネージャーで一元管理し、アクセス制御・監査・ローテーション・暗号化を実現せよ
コーディングエージェントによるリスクの増大
上記の問題はこれまでも存在しており、サプライチェーン攻撃(悪意のある npm パッケージの postinstall スクリプト等)によって .env のシークレットが窃取されるリスクはありました。コーディングエージェントの登場により、このリスクはさらに拡大しています。
コーディングエージェントはファイルの読み書きやコマンドの実行を自律的に行います。プロジェクトディレクトリ内の .env ファイルは、エージェントにとっても読み取り可能です。
実際に起きた事例: 2025年8月 Nx サプライチェーン攻撃
2025年8月、週間ダウンロード数460万を超える npm パッケージ「Nx」が侵害されました (Socket のレポート)。攻撃者は postinstall スクリプトを通じて、SSH キー、GitHub トークン、npm トークン、そして .env ファイル を窃取しました。
注目すべきは、このマルウェアが Claude Code、Gemini CLI、Amazon Q といった AI コーディングエージェントの CLI を --dangerously-skip-permissions 等のフラグ付きで呼び出し、ファイルシステムの探索とシークレットの特定をエージェントに委任しようとしたことです (Snyk のレポート)。Snyk はこれを「マルウェアが AI アシスタントの CLI を偵察と情報窃取に利用した、おそらく初めて文書化された事例の一つ(likely one of the first documented cases)」としています。
Claude Code で .env を deny するアプローチの限界
Claude Code では settings.json の permissions.deny で .env の読み込みを禁止できます。
json
{
"permissions": {
"deny": [
"Read(**/.env*)"
]
}
}筆者の環境(macOS, v2.1.x 系)で検証したところ、この deny は Read ツールによる直接的な読み込みだけでなく、Bash ツール経由で実行されたコマンドが .env を間接的に読み込むこともブロックします。公式ドキュメント (Configure permissions) でも「Read ルールを Grep, Glob, LS のようなファイルを読み取る全組み込みツールに best-effort で適用する」と記載されています。
deny の問題点
Bash ツール経由でも .env が読み込めなくなるため、コーディングエージェントが実行するコマンドが環境変数に依存していると軒並みエラーになります。開発サーバーの起動(next dev, vite 等)、テスト実行(Jest, Playwright 等)、DB マイグレーション(Prisma, Drizzle 等)。環境変数に依存している操作はすべて失敗するため、「コード修正→テスト→修正」の自律的なループが回せなくなります。
つまり、.env にシークレットを入れたまま deny で守ろうとするアプローチは、エージェントの自律性を大きく損なうトレードオフを伴います。
解決策:シークレットを .env から出す
根本的な解決策は .env の役割を本来のものに戻すことです。
.env: 環境ごとに異なる非秘匿な設定値を管理する(ポート番号、ホスト名、フィーチャーフラグ等)- シークレット: シークレットマネージャーで管理し、ランタイム時に取得・注入する
こうすれば .env を deny する必要がなくなり、コーディングエージェントのワークフローも維持できます。
シークレットマネージャーの取得パターン
シークレットマネージャーからの取得方法は大きく3つあります。
1. CLI 注入(プロセス起動時に環境変数として注入)
bash
op run -- npm run dev # 1Password
doppler run -- npm run dev # Doppler
infisical run -- npm run dev # Infisical手軽に始められますが、結果的に環境変数としてプロセスに渡されるため、OWASP の観点では理想的ではありません。ただし .env にプレーンテキストで永続化するよりは大幅に改善されます。シークレットマネージャー側のアクセス制御・監査・ローテーションの恩恵も受けられます。
2. SDK によるランタイム取得(アプリケーションコードから直接)
python
# 1Password SDK の例
from onepassword import Client
client = await Client.authenticate(service_account_token="...")
secret = await client.secrets.resolve("op://vault/item/field")アプリケーションが必要なタイミングで直接取得する方式です。環境変数を経由しないため OWASP の推奨に最も近いですが、アプリケーションコードの変更が必要になります。
3. インフラ層での注入(Kubernetes Secrets, Connect Server 等)
1Password Connect Server のようなセルフホスト型の REST API サーバーを立て、インフラ層でシークレットを注入する方式です。本番環境向け。
主要なシークレットマネージャー
コーディングエージェントとの相性で重要なのは、ローカル開発で手軽に使える CLI 注入に対応しているかどうかです。
1Password — パスワードマネージャーとシークレットマネージャーの両面を持つ
チームで既に 1Password を使っていれば、追加のツール導入なしでシークレットマネージャー機能が使えるのが最大の強みです。CLI(op run)、SDK(Python / JS / Go)、Connect Server(セルフホスト REST API)の3つの取得方法に対応しています。AI エージェントとの連携も 公式にドキュメント化 されており、Service Account + SDK による least privilege アクセスのパターンが推奨されています。Filip Hric 氏の記事 (Don't let A.I. read your .env files) でも Claude Code との併用が紹介されています。個人プランは月額 $2.99〜。
Doppler — 環境変数管理に特化した SaaS
doppler run での CLI 注入に対応。無料プラン(5ユーザーまで)があり、個人や小規模チームで手軽に始められます。セルフホスト不可、OSS ではありません。
Infisical (GitHub) — コア部分が MIT ライセンスの OSS
infisical run での CLI 注入に対応。クラウド版(無料枠あり)とセルフホスト(Docker Compose)の両方があります。ダッシュボード UI、シークレットスキャン、自動ローテーション機能を備えていて、OSS のシークレットマネージャーとしては現時点で最も開発者体験が良いと評価されています。なお、エンタープライズ機能(ee ディレクトリ)はプロプライエタリライセンスです。
Phase (phase.dev) — E2E 暗号化の OSS
phase run での CLI 注入に対応。セルフホスト + クラウド版あり。比較的新しいサービスです。
AWS Secrets Manager / SSM Parameter Store — AWS 前提
AWS を使っているなら自然な選択。IAM 連携、自動ローテーション対応。SSM Parameter Store は chamber CLI と組み合わせてローカル開発にも使えます。
GCP Secret Manager / Azure Key Vault — 各クラウド提供
各クラウドの IAM と統合。
Mozilla SOPS — GitOps 向け暗号化ツール
.env や .yaml ファイル自体を暗号化して Git にコミットするアプローチ。AWS KMS, GCP KMS, PGP で暗号化。CLI 注入パターンとは異なり、シークレットマネージャーというより暗号化ツールです。
選び方
判断基準 | 1Password | Doppler | Infisical | Phase | AWS SM |
|---|---|---|---|---|---|
CLI 注入 ( | ◯ | ◯ | ◯ | ◯ | △(chamber 経由) |
SDK ランタイム取得 | ◯(Python/JS/Go) | ◯ | ◯ | ◯ | ◯ |
無料プラン | ✕ | ◯(5名まで) | ◯ | ◯ | 従量課金 |
OSS / セルフホスト | ✕ | ✕ | ◯(コア MIT) | ◯ | ✕ |
導入の手軽さ | 高 | 高 | 中 | 中 | 低(AWS 前提) |
- チームで既に 1Password を使っている → 1Password のシークレットマネージャー機能で統一
- 個人開発・小規模チームで手軽に始めたい → Doppler(無料枠)か Infisical(OSS)
- OSS / セルフホスト必須 → Infisical か Phase
- AWS にインフラが寄っている → AWS Secrets Manager
まとめ
.env自体が悪いのではなく、シークレットの置き場所として使うのが問題- OWASP はシークレットをプレーンテキストの設定ファイルに保存することを非推奨としている。環境変数への保存自体も「他の方法がない場合を除き推奨しない」としている
- OWASP が推奨するシークレット管理の要件(一元管理、アクセス制御、監査、ローテーション、暗号化)を
.envで満たすことはできない - コーディングエージェントの普及と Nx サプライチェーン攻撃のような実例により、
.envにシークレットを入れるリスクは現実的な脅威になっている - Claude Code の
permissions.denyで.envを守ることはできるが、Bash ツール経由の読み込みもブロックされるため、エージェントの自律性を大きく損なう .envには非秘匿な設定値だけを残し、シークレットはシークレットマネージャーに移すのが根本的な解決策になる。CLI 注入(op run,doppler run,infisical run等)なら、アプリケーションコードを変えずに移行を始められる
参考資料
- OWASP Secrets Management Cheat Sheet
- OWASP SAMM - Secure Deployment / Secret Management
- OWASP DevSecOps Guideline - Secrets Management
- Environment Variables Don't Keep Secrets (CyberArk / OWASP 共著者)
- Understanding Claude Code Permissions and Security Settings (Pete Freitag)
- Don't let A.I. read your .env files (Filip Hric)
- Configure permissions - Claude Code Docs
- Nx npm Packages Compromised in Supply Chain Attack (Socket)
- Weaponizing AI Coding Agents for Malware in the Nx Incident (Snyk)
- 1Password Secrets Automation
- 1Password SDK + AI Agent Tutorial