新しく参画したプロジェクトで、最初に少し気になったのが環境変数の管理方法でした。
config/
├─ stg.env
├─ ppr.env
└─ prod.env
中身を確認すると、APIのエンドポイントだけでなく、APIキーやシークレットなどの機密情報まで含まれており、それらがそのままGitで管理されていました。
運用上は特に問題は起きておらず、実際にこの構成で開発も回っていました。
ただ、「このまま運用し続けても大丈夫だろうか」という違和感がありました。
この記事では、環境変数のGit管理を見直し、機密情報をSecret管理へ移行したときの考え方を紹介します。
当時の構成
環境変数には大きく分けて2種類の情報が入っていました。
| 種類 | 例 |
|---|---|
| 設定値 | API URL、機能フラグ |
| 機密情報 | APIキー、アクセストークン、シークレット |
設定値と機密情報が同じファイルに存在している状態です。
気になった点
リポジトリにアクセスできれば機密情報も見えてしまう
Gitで管理している以上、リポジトリを閲覧できる人は本番環境のキーも確認できます。
もちろん、チーム内で悪用されることを前提にするわけではありません。
ただ、アクセス権は「最小限」であることが望ましいため、少し気になるポイントでした。
一度コミットすると履歴に残る
仮にキーを削除したとしても、Gitの履歴には残ります。
万が一漏洩した場合、履歴まで含めて対応する必要があり、後から完全に消すのは簡単ではありません。
ローカルにも保存される
開発者全員のPCに機密情報が保存されることになります。
管理対象が増えるほど、リスクも大きくなります。
キーの変更が意外と大変
キーを更新するだけでも
- ファイルを修正
- PR作成
- レビュー
- マージ
- リリース
という流れになります。
セキュリティ上の変更なのに、通常の開発フローに依存してしまっていました。
どう改善したか
まず、「設定」と「機密情報」を分けました。
| 分類 | 管理方法 |
|---|---|
| 設定値 | Gitで管理 |
| 機密情報 | Secret管理 |
APIキーやシークレットはリポジトリから削除し、CIのSecretとして管理するように変更しました。
実装方法
iOS
CIで取得したSecretからビルド時に設定ファイルを生成します。
echo "API_KEY=${API_KEY}" >> Generated.xcconfig
その後、Info.plist経由でアプリから参照します。
Android
ビルド時に環境変数を読み込みます。
buildConfigField "String", "API_KEY", "\"${System.getenv("API_KEY")}\""
ローカル開発では環境変数を設定しておけば、そのまま動作します。
移行して感じたこと
以前は「環境変数は設定ファイル」という認識でした。
しかし実際には、
- Gitで管理して問題ない設定
- Gitで管理すべきではない機密情報
は分けて考えるべきだと感じました。
この2つを分離したことで、アクセス権の管理もしやすくなり、キーのローテーションも柔軟に行えるようになりました。
Before / After
| Before | After |
|---|---|
| 機密情報をGit管理 | Secret管理 |
| リポジトリ閲覧者なら確認可能 | 権限を持つ人・CIのみ取得可能 |
| キー変更にリリースが必要 | Secret更新だけで対応可能 |
| 履歴に残る | コードベースに残らない |
まとめ
Gitで管理するのは、「漏れても問題ない設定」だけで十分です。
一方で、APIキーやシークレットのような機密情報は、コードとは分離し、適切なSecret管理サービスで扱う方が安全です。
今回の対応を通して改めて感じたのは、「動いているから問題ない」と「安全に運用できる」は別だということです。
環境変数の管理は目立つ部分ではありませんが、長く運用するプロジェクトほど、その設計の良し悪しが後々効いてくると感じました。