チーム開発やってると、必ずぶつかる壁がある。それが「.env ファイルどうやって共有する問題」よね
Slack で送る? Notion に貼る? 1Password で管理する?どれも一長一短で、結局「安全性」と「手軽さ」のバランスが難しい。特に新しくプロジェクトに参加したメンバーに環境変数を渡すとき、めっちゃ気を使うんよな
そこで便利なのが dotenvx というツール。これ、あの有名な dotenv の作者が作った後継ツールで、.env ファイルを暗号化したまま Git にコミットできるっていう、なかなか画期的なやつよ
dotenvx ってなに?
dotenvx は、環境変数を安全に管理するためのツール。従来の dotenv は単純に .env ファイルを読み込むだけやったけど、dotenvx は暗号化機能が標準搭載されてる
仕組みとしては、公開鍵暗号方式を採用してる。具体的には、各シークレットを AES-256 で暗号化して、その暗号鍵を Secp256k1 という楕円曲線暗号(Bitcoin と同じアルゴリズム)で保護する二重構造になってる。めっちゃ堅牢やな
dotenvx の特徴をざっくりまとめると、こんな感じになる
- .env ファイルを暗号化して Git にコミットできる
- 公開鍵で暗号化、秘密鍵で復号という仕組み
- 複数環境(development、production など)に対応
- 実行時に自動で復号してくれる
PayPal、NASA、Supabase、AWS なんかも採用してるらしく、週間 100 万回以上インストールされてる人気ツールやな
インストール方法
Mac なら Homebrew で一発インストールできる
npm でもインストールできるから、Node.js 環境なら npm install -g @dotenvx/dotenvx でもいける。Windows の場合は npm 経由が無難かな
暗号化の仕組みを理解しよう
dotenvx の暗号化は、2 つの鍵を使う仕組みになってる
- DOTENV_PUBLIC_KEY(公開鍵):.env ファイルの先頭に配置される。チーム全員が使える暗号化用の鍵
- DOTENV_PRIVATE_KEY(秘密鍵):.env.keys ファイルに保存される。復号化に必要な鍵
公開鍵はその名の通り公開しても問題ない。Git にコミットしても大丈夫。でも秘密鍵は絶対にコミットしたら駄目やん。これを漏らしたら全部のシークレットが見られてしまう
この仕組みのいいところは、暗号化された .env ファイルが万が一漏れても、秘密鍵がなければ復号できないこと。セキュリティ的にかなり安心できるよね
実際の運用フロー(管理者編)
まず、プロジェクトの管理者がやることを説明するね
最初に既存の .env.local を開発用の .env.dev にコピーする。なんで .env.dev にするかというと、環境ごとに分けて管理したいから。本番用なら .env.production、ステージング用なら .env.staging みたいに分けられる
次に、この .env.dev を暗号化する
このコマンドを実行すると、.env.dev の中身が暗号化される。元の内容がこんな感じだったとする
暗号化後はこうなる
見ての通り、各値が encrypted: というプレフィックス付きの暗号文に置き換わってる。元の値は完全に隠されてるから、このファイルを Git にコミットしても安全やな
同時に .env.keys というファイルも生成される。これが秘密鍵を格納するファイル
.env.keys は絶対に Git にコミットしたら駄目。.gitignore に追加しておくこと
.gitignore にはこんな感じで追加しておこう
ここまでできたら、暗号化された .env.dev を Git にコミットする
最後に、.env.keys の中身(秘密鍵)だけを共同開発者に安全な方法で共有する。1Password Environments 、直接会って伝えるなど、セキュアな経路で渡すのが大事
実際の運用フロー(共同開発者編)
次に、共同開発者側の手順を説明するね
まず、管理者から受け取った秘密鍵を .env.keys ファイルに保存する。プロジェクトのルートディレクトリに .env.keys を作成して、秘密鍵を貼り付ける
次に、Git からクローンしてきた暗号化済みの .env.dev を .env.local にコピーする
最後に、復号化コマンドを実行する
これで .env.local が復号化されて、元の環境変数が使えるようになる。めっちゃ簡単やな
復号化には .env.keys に正しい秘密鍵が必要。秘密鍵がないと復号できない仕組みになってる
複数環境を管理する場合
本番環境とか、ステージング環境とか、複数の環境を管理したい場合も dotenvx で対応できる
例えば、こんな構成で管理できる
- .env.dev - 開発環境
- .env.staging - ステージング環境
- .env.production - 本番環境
それぞれ個別に暗号化する
暗号化すると、.env.keys にはそれぞれの環境用の秘密鍵が追加される
本番環境の秘密鍵は、本番にアクセスできる人だけに共有するとか、環境ごとにアクセス制御できるのがいいよね
実行時に自動で復号する方法
dotenvx run コマンドを使えば、復号化しなくても暗号化されたままアプリを実行できる
このコマンドは .env.keys から秘密鍵を読み込んで、実行時に自動で復号してくれる。.env.local を復号化した状態で保存しなくていいから、よりセキュアな運用ができるな
本番環境では、環境変数として秘密鍵を設定しておけば同様に動作する
よくある質問と注意点
暗号化された .env を間違ってコミットしても大丈夫なん?という疑問があると思う
答えは「大丈夫」。暗号化されてるから、秘密鍵がなければ復号できない。むしろ、暗号化された状態でコミットするのが dotenvx の正しい使い方やな
.env.keys を間違ってコミットしたらどうする?これはヤバい。すぐに以下の対応が必要になる
- Git の履歴から削除する(git filter-branch や BFG Repo-Cleaner を使う)
- 新しい鍵で再暗号化する
- 影響を受けた環境変数(API キーなど)をすべてローテーションする
だから .gitignore の設定は最初にちゃんとやっておこう
既存の .env に新しい変数を追加したい場合はどうする?暗号化された .env ファイルに変数を追加するには、一度復号化してから変数を追加して、再度暗号化すればいい
もしくは dotenvx set コマンドで直接追加することもできる
従来の方法との比較
dotenvx を使わない従来の方法と比較してみよう
Slack や DM で .env を送る方法は、履歴が残るし、転送されるリスクもある。退職者のアカウントに残ってたりするとセキュリティ的に問題やな
1Password などのパスワードマネージャーで管理する方法は、セキュアやけど、毎回コピペするのが面倒。環境変数が多いと特にしんどい
Notion やドキュメントで管理する方法は、検索しやすいけど、アクセス権限の管理が大変。退職時の対応も面倒
dotenvx の方法は、Git で管理できるから変更履歴も追えるし、秘密鍵だけ管理すればいいからシンプル。新しいメンバーにも秘密鍵を渡すだけで環境構築完了するのがいいよな
セキュリティのベストプラクティス
dotenvx を使う上でのセキュリティベストプラクティスをまとめておく
秘密鍵の管理について。.env.keys は絶対に Git にコミットしない。秘密鍵の共有は安全な経路(1Password、対面など)で行う。定期的に鍵をローテーションすることも検討する
環境の分離について。本番環境の秘密鍵は限られたメンバーだけに共有する。開発環境と本番環境の鍵は別々に管理する。CI/CD では環境変数として秘密鍵を設定する
監査について。誰が秘密鍵を持っているか把握しておく。メンバーの退職時は鍵のローテーションを検討する。不要になった環境の鍵は削除する
CI/CD での使い方
GitHub Actions などの CI/CD 環境で使う場合は、秘密鍵を Secrets として設定しておく
この設定なら、暗号化された .env.production を使いながら、安全にビルドできる
トラブルシューティング
復号化できない場合は、まず秘密鍵が正しいか確認しよう。.env.keys のキー名が環境に対応しているか(.env.dev なら DOTENV_PRIVATE_KEY_DEV)もチェックする
暗号化コマンドがエラーになる場合は、dotenvx のバージョンを確認する。brew upgrade dotenvx で最新版にアップデートしてみるのもいい
ファイルが見つからないエラーが出る場合は、-f オプションで指定したファイルパスが正しいか確認する。相対パスと絶対パスの違いに注意やな
まとめ
dotenvx を使えば、.env ファイルの共有問題がかなりスッキリ解決する
- 暗号化された .env を Git にコミットできる
- 秘密鍵だけを安全に共有すればいい
- 複数環境も柔軟に管理できる
- 実行時に自動復号もできる
チーム開発での環境変数管理に悩んでるなら、一度試してみる価値あると思うな。従来の方法より圧倒的にシンプルで安全やから
特に新しいメンバーが参加したときの環境構築が楽になるのがいい。「.env.keys の中身送るから、あとはコマンド叩くだけ」で済むのは、めっちゃ効率的よな