環境変数を暗号化してgitで管理する
はじめに
はじめましての方ははじめまして!もひこ(@andmohiko)と申します。
チーム開発をするとき、みなさんは環境変数をどのように管理しているでしょうか。先輩からDMで渡されたり、開発ドキュメントにまとめているチームもあるのではないでしょうか。
筆者はTypeScriptでのアプリケーション開発をしているのですが、環境変数の管理方法に課題を感じることがありました。
そこで今回は、その課題をどのように解決したのかについて書いていきます。
モチベーション
アプリケーション開発では、APIキーやデータベース接続情報などの機密情報を環境変数として管理するのが一般的です。
筆者も.env
ファイルを利用しており、ローカル環境・開発環境・本番環境の3つの環境の.env
ファイルがあります。
これらは機密情報であるため、たとえプライベートリポジトリであったとしてもGitHubにアップロードしたくないという利用から、.env
をGitの管理対象にはしていません。
その結果、以下のような課題が出てきました。
運用面の課題感
チーム開発において、環境変数を安全に共有・更新することがむずかしいと感じる場面が多くありました。
開発を進める中で、環境変数を追加・更新すること場面は少なくありません。
これまでは、環境変数をNotionに記載し、変更があればチームにアナウンスするという運用をしてきました。
しかし、この運用には以下のような問題があります。
- Notionへの更新漏れが発生する
- チームメンバーが変更を手元の
.env
に反映し忘れる - そのままデプロイした結果、一部の機能が動作しなくなるリスクがある
-
.env
をGitで管理していないため、更新漏れに気付きにくい
このように、手作業による管理の限界を感じていました。
実装面の課題感
もう一つの課題として、CI/CDで環境変数を扱う際の煩雑さも気になっていました。
スーパーハムスターでは、GitHub Actionsを使ってアプリケーションをデプロイしています。
そのため、環境変数はGithub Secretsに登録していました。
しかし、ここで問題になるのは、環境変数の数が増えるほど設定する項目も増えるという点です。さらに、開発環境と本番環境のように環境が増えると、設定する変数の数も倍に増えてしまいます。
解決策の比較検討
これらの課題を解決するため、環境変数を暗号化してGitで管理するというアプローチを採用しました。
.env
自体はgitignoreしますが、暗号化された.env.enc
はGitの管理対象とします。
暗号化の方法としてGPGを使用する方法と、OpenSSLでAES-256による暗号化を行う方法の2つが考えられます。
方法 | 特徴 |
---|---|
GPG | 開発者ごとにアクセス制御ができ、安全性が高い |
OpenSSL | 簡単でセットアップが楽だが、秘密鍵の管理が必要 |
どちらの方式でも、環境変数のバージョン管理が可能になり、運用面の課題は解決できそうです。
しかし、GitHub Actionsで環境変数を復号することを考えると、鍵の管理がシンプルで、復号の手順が簡単なものを選びたいです。
GPGは鍵管理が複雑だったり、復号の際に鍵のインポート手順が必要になってきます。
一方で、OpenSSLは、GitHub Secretsにパスフレーズを保存しておけば、openssl enc -aes-256-cbc
コマンドですぐに復号できるという手軽さがあります。
この手軽さを考慮し、今回はOpenSSLを使った方法を選択しました。
OpenSSLを使った暗号化の仕組み
OpenSSLの enc -aes-256-cbc とは
OpenSSLでAES-256による暗号化を行うには次のコマンドを実行します。
$ openssl enc -aes-256-cbc -salt -pbkdf2 -in .env -out .env.enc -pass pass:${YOUR_SECRET_KEY}
こちらのコマンドの仕組みを分解しながら、なぜPBKDF2(Password-Based Key Derivation Function 2)を使うのかについて説明します。
このコマンドを分解すると、それぞれ以下の意味を持ちます。
オプション | 説明 |
---|---|
enc -aes-256-cbc | AES-256-CBC(Cipher Block Chaining)を使用して暗号化 |
-salt | ランダムなソルトを追加し、同じパスワードでも異なる暗号データを生成 |
-pbkdf2 | PBKDF2 を使用して安全な鍵導出を行う |
-in .env | 暗号化する元のファイル |
-out .env.enc | 暗号化後の出力ファイル |
-pass pass:YOUR_SECRET_KEY | 暗号化に使うパスワード |
OpenSSLのencコマンドは、AES-256などの対称鍵暗号方式を利用してデータを暗号化するために使用されます。
しかし、単純にパスワードを鍵として使うと脆弱性が生じるため、PBKDF2を利用した鍵導出が重要になります。
鍵導出(Key Derivation)とは
暗号化アルゴリズム(AES-256 など)では、暗号鍵(Encryption Key)を元にデータを暗号化します。
しかし、人間が覚えやすいパスワードを直接暗号鍵として使うのは危険です。以下の理由が挙げられます。
- 短いパスワードは簡単に推測される
- 同じパスワードを使い回すと、暗号化データのパターンがバレやすい
- レインボーテーブル(Rainbow Table)攻撃を受けやすい
そこで、パスワードを安全な暗号鍵に変換する技術が鍵導出関数(KDF: Key Derivation Function)です。
-pbkdf2 の仕組みと必要性
PBKDF2はパスワードを暗号鍵に変換するための鍵導出関数(KDF)です。これを利用することで、パスワードから安全な暗号鍵を生成し、ブルートフォース攻撃に対する耐性を高めます。
PBKDF2の鍵導出の流れ
- ソルト(Salt)の追加
ランダムなソルトを生成し、パスワードと組み合わせる。
同じパスワードでも異なる暗号鍵が生成されるため、レインボーテーブル攻撃を防げる。 - ハッシュ関数(SHA-256 など)の適用
ハッシュ関数(HMAC-SHA256 など)を何千回も繰り返し適用し、計算コストを増やす。
OpenSSLのデフォルトでは10,000 回の反復を行う。 - 暗号鍵を生成
導出された値をAES-256の暗号鍵として使用。
PBKDF2 の導出式
DK = PBKDF2(P, S, c, dkLen)
- P = パスワード(Password)
- S = ソルト(Salt)
- c = 反復回数(Iteration Count)
- dkLen = 生成する鍵の長さ(AES-256 の場合は 32 バイト)
従来の方法(EVP_BytesToKey)との違い
PBKDF2を使わない場合、OpenSSLはEVP_BytesToKeyという関数を使ってパスワードから鍵を導出していました。
しかし、この方法には以下のような問題があります。
従来方式(EVP_BytesToKey) | PBKDF2 | |
---|---|---|
鍵導出の回数 | 1回のみ | 10,000回以上 |
攻撃耐性 | ブルートフォース攻撃に弱い | 攻撃に対して強い |
ソルトの使用 | なし or オプション | 必須 |
計算コスト | 低い(攻撃しやすい) | 高い(その分安全) |
EVP_BytesToKey の問題点
- 1回の計算しか行われない → 簡単に総当たり攻撃が可能。
- ソルトを使わない場合がある → レインボーテーブル攻撃に弱い。
- 計算コストが低いため、パスワードクラックが容易。
このような理由から、PBKDF2を使わないとセキュリティが低くなるため、OpenSSLでは-pbkdf2
を使うことが推奨されています。
暗号化と復号の手順
それでは実際に実行するコマンドを紹介します。
暗号化する際は次のコマンドを実行します。
$ openssl enc -aes-256-cbc -salt -pbkdf2 -in .env -out .env.enc -pass pass:${キー}
復号する際は次のコマンドを実行します。
$ openssl enc -aes-256-cbc -d -salt -pbkdf2 -in .env.enc -out .env -pass pass:${キー}
.env.enc
から復号した.env
が元の内容と一致していれば成功です🎉
運用方法
さいごに、運用方法について説明します。
環境変数を安全に管理しつつ、チーム全員がスムーズに運用できるように、以下のフローを採用します。
準備
暗号化された環境変数はGitの管理対象にしますが、環境変数自体はgitignoreしておく必要があります。
.env
は環境ごとに.env.local
, .env.develop
, .env.production
というようにファイルが分かれています。
そこで、次のように.gitignore
を編集します。
# .gitignore
.env*
!.env*.enc
更新手順
- 環境変数の変更とGitへのpush
環境変数を変更した際は、必ず暗号化してGitにpushし、Pull Requestに含めます。 - チームメンバーは手元に反映する
環境変数を更新したらチームに周知し、メンバーはpullしたタイミングで手元の.env
ファイルを更新します。 - 暗号化キーは定期的に変更する
暗号化キーは数ヶ月ごとやメンバーの入れ替わりがあったタイミングで更新するとよいかもしれません。
さいごに
環境変数の管理は、アプリケーション開発においてセキュリティと運用の両面で重要な課題です。
Gitでのバージョン管理のメリットを活かしつつ、機密情報を安全に扱うための方法としてOpenSSLを用いた環境変数の暗号化を導入しました。
同じような課題感を抱えている方はぜひ試してみてください。
Discussion