AI
コーディングツールが当たり前になってきて、.env(環境変数ファイル)をそのまま置く怖さが目に見えるようになりました。
ファイルが読めるなら、秘密も読めます。ここはAI時代のセキュリティ として、無視しにくい問題だと思います。
この記事では、enject (旧enveil)を中心に、「AIが読める場所に秘密を置かない」という発想を整理します。
(補足)プロジェクトは以前 enveil という名前でしたが、現在は enject にリネームされています。
その上で、dotenvx を比較対象として出し、チーム/CIまで含めた運用で何が変わるかも見ます。
まず脅威モデルを分解する(どこで漏れる?)
「.env を安全にする」と言っても、漏れる経路は複数あります。ここでは3つに分けて考えます。
- ファイル漏洩:
.envをAIや別プロセスが読める - プロセス漏洩: プロセス環境変数(
os.environ)のダンプやログ出力で漏れる - ネットワーク漏洩: 悪意あるコードが外部送信する
今回フォーカスするのは主に(1)です。(2)(3)まで本気でやるなら、権限分離やサンドボックス(隔離実行)など別の対策が必要になります。
2つのアプローチの狙い
enject(旧enveil)の狙い
enject は「.env を参照テンプレにする」設計です。.env に値は書かず、en:// 参照だけを置き、実体は暗号化ローカルストアに保存します。
結果として、「AIがディレクトリを覗いても .env に秘密がない」状態を作ります。反面、プロセス上の秘密やネットワーク送信は別の対策が必要です。
enject のデータ(秘密)はどこに保存される?
ここが一番気になるところなので、先に書きます。
- プロジェクト側(リポジトリ内)
.env:秘密の値は書かず、en://参照だけを書く(テンプレ).enject/:プロジェクトごとの設定と暗号化ストア.enject/config.toml:設定(salt等).enject/store:暗号化された秘密の実体(バイナリ)
- あなたの頭(=マスターパスワード)
- store を復号するためのパスワードは、基本的にファイルには残しません(対話入力)
運用上は、.enject/ は 必ず .gitignore に入れて「ローカル専用」にするのが前提になります。
# enject
.enject/
(補足)READMEによると、内部では Argon2id で鍵を導出して AES-256-GCM でストアを暗号化、という構成です。ここは“暗号が強い”より「平文がディスクに無い」という性質のほうが効きます。
dotenvx の狙い
dotenvx は .env を中心に、暗号化・複数環境・配布まで扱うツール群です。GitHub リポジトリ
と公式のドキュメント
では .env.keys(復号鍵ファイル)を使った暗号化フローや、CI連携のガイドが整理されています。
ここでは「チーム/CIで回す」前提のよくある使い方を想定します。
.envを使ったローカル開発の互換性をなるべく壊さない- CIやチーム配布を含めて回す
比較
| 観点 | dotenvx | enject |
|---|---|---|
| 狙っている主問題 | .env運用全般(配布/互換/暗号化など) | 平文の秘密をディスクに置かない |
| ファイル漏洩への強さ | 運用次第で強くも弱くもなる | 参照テンプレなので強い設計 |
| プロセス漏洩への対応 | 別途対策が必要 | 別途対策が必要 |
| ネットワーク漏洩への対応 | 別途対策が必要 | 別途対策が必要 |
| チーム/CI適性 | ガイドがあり導入しやすい | 追加設計が必要になりやすい |
| 運用負荷 | 鍵配布や環境分離の運用が必要 | パスフレーズ(長めのパスワード)管理が必要 |
既存 .env 互換 | 高め | 参照テンプレに書き換える必要 |
この表を見て「どっちが勝ち」というより、 どのレイヤをどのツールに任せるかが設計になります。
最小手順で触ってみる
dotenvx を試す
前提: Node.js
が使える環境です。ここでは npx(パッケージ実行ツール)経由で実行します。ダミー値を使うので、実際の秘密は入れないでください。
dotenvx は「値をファイルに書く」以外に、dotenvx set で 値を設定しつつ暗号化できるのが便利です(Quickstart
にも出てきます)。
作業ディレクトリを作る
1 2mkdir dotenvx-demo cd dotenvx-demosetで値を入れる(暗号化)これで
.env(または.env.production等)と.env.keysが作られます。1npx @dotenvx/dotenvx@latest set API_KEY dummy-123実行して読み込めているか確認する
loaded trueが出れば読み込み確認は完了です。1npx @dotenvx/dotenvx@latest run -- node -e "console.log('loaded', !!process.env.API_KEY)"
.env.keys には復号鍵が入るので、コミットしない運用が前提になります。
# dotenvx
.env.keys
enject を試す
前提: Rust(システムプログラミング言語)が必要です。rustup
が使える環境で試してください。.enject/ はローカルストアなので、.gitignore に入れる前提です。
インストール
これで enject の CLI(コマンドラインツール)が使えるようになります。
1cargo install enject --version 0.2.0-alphaプロジェクトで初期化
.enject/が作られ、ローカル暗号化ストアが初期化されます。1 2 3mkdir enject-demo cd enject-demo enject init秘密を登録(対話入力なので、シェル履歴に残りにくい)
ここではダミー値を入力します。
1 2enject set database_url # Value for 'database_url': (hidden).envは参照テンプレにするen://参照を置き、実体はローカルストアに任せます。1DATABASE_URL=en://database_url実行は
enject run経由で確認loaded trueが出れば参照が解決できています。1enject run -- node -e "console.log('loaded', !!process.env.DATABASE_URL)"
この時点で「AIが .env を読んでも値が出ない」状態にはできます。
インフラ間で共有・移動するならどっちが現実的?
ここが enject を触って一番「思想の差」を感じるところです。
dotenvx: 暗号文を共有して、鍵だけを別経路で渡す
dotenvx は “共有” の作法が比較的分かりやすいです。
- 暗号化された
.env(=暗号文)は、リポジトリやアーティファクトとして配れる - 復号に必要な
.env.keys(鍵)は、別経路で渡す(=ここを厳重に)
暗号文と鍵を分離できるので、「インフラ間で同じ設定を回す」用途に向きます。
もちろん、鍵が漏れたら終わりです。 ただ、鍵の取り扱いを “ここだけ注意” に寄せられるのが運用上ありがたいです。
enject: .enject/ を束ねて“持っていく”になりがち
enject はローカルに閉じた設計が主役なので、「複数マシンで同じ秘密を回す」をやろうとすると、結局こうなります。
.enject/config.tomlと.enject/store(暗号化ストア)を含む.enject/を、何らかの安全な経路で移動
例えば、プロジェクトルートで
| |
を作って、別マシンで展開する、のような運用です。
これは “できる” けど、dotenvxの「暗号文と鍵を分離する」感じとは違います。
.enject/は暗号化されていても 機密ファイル です(漏れたらオフライン攻撃の対象)- 共有した後は
enject rotateでパスフレーズを更新して、被害範囲を区切りたくなります
制作者へのリスペクトは前提として、 enject は共有(チーム/CI)より、ローカルの覗き見耐性に賭けたツール、という評価になります。
一方でこの割り切りは、個人的にはかなり好感があります。 「秘密を取り出せるコマンド(get/export)を提供しない」という方針は不便でも、 うっかりを減らすには効きます。
- ターミナルのコピペ
- ログへの出力
- AIが読めるファイルへの書き出し
この辺の“人間のミス”を、ツール側が最初から潰しに来ている感じです。
落とし穴(ここを外すと事故る)
- enject は(1)を強くする代わりに、(2)(3)は止めません
- dotenvx は汎用性が高い分、運用設計が甘いと(1)が残ります
つまり、
- 守る対象が(1)中心なら enject の思想は刺さる
- チーム/CI含めた運用が主戦場なら dotenvx のほうが自然
という整理になります。
選び方
次の問いに答えると、選びやすいです。
- 「AIが読む場所から秘密を消したい」か
- 「CIまで含めて回す」ことが主目的か
- 「ローカル開発の互換性」をどこまで保ちたいか
- 「鍵やパスフレーズの配布」を運用で回せるか
まとめ: まず“守りたい経路”を決めてから選ぶ
- 「AIが読む場所から秘密を消す」が主目的なら、enject は分かりやすい
- 「配布/互換/CIまで含めた運用」が主目的なら、dotenvx は強い
自分はこの2つを “代替” というより、守るレイヤが違う道具として見ています。
