Unity ビルドへ .env の秘密情報を焼き込む:失敗時に残さない設計
Installer Asset に Webhook URL を書く運用をやめ、.env からビルド時だけ焼き込む。callbackOrder の向き、OnPostprocessBuild が呼ばれない失敗ビルド、BOM と引用符の往復バグ。
何に困っていたか
当初、YouTube 用の JWT や Discord の Webhook URL を、各パッケージの Installer Asset(ScriptableObject)に直接保存していた。Inspector から編集できて手軽だが、Asset はリポジトリにコミットされる。「この Asset を公開リポジトリへコミットしないでください」という注意書きを添えるしかなく、人間の注意力に依存していた。
さらに環境名が二重管理だった。YouTube 側の Installer が独自に環境名を持ち、Core の McSettings.Environment(Develop / Production)と切り替え場所が 2 か所に分かれていた。「本番の .env を読んでいるつもりで develop を読んでいた」が起きうる構造である。
どう設計したか
- 秘密情報は
.env.<環境名>に置き、Editor 実行時はファイルを直接読む。 - ビルド時だけ、選択中の
.envの全エントリをResources配下の一時 ScriptableObject(McEnvBakedSecrets)へ焼き込み、ビルド後に削除する。 - 公開窓口は
McEnv.TryGetの 1 本。追加パッケージは Core を通してだけ読む。 - 環境名は
McSettings.Environmentに統合し、切り替えは Project Settings の 1 か所にする。 - Installer の Inspector からの入力は書き込み専用の伏せ字欄にする。既存の値を読み戻さず、Asset にも保存せず、入力中の文字列もシリアライズしない。
// 読む側
McEnv.TryGet("MIMICATHUB_DISCORD_WEBHOOK_" + McEnv.ToKeySegment(key), out url, out reason);
// Installer から書く側(追加パッケージが触れる唯一の窓口)
McEnvEditorUtility.SetValue("MIMICATHUB_YOUTUBE_JWT", input.Trim());
ログには値もキー名も出さない。出すのは環境名とエントリ件数だけである。.env が無くてもビルドは止めず警告に留め、必要キーの有無は各パッケージの検証処理が判定する。
何が起きたか
焼き込みの順序が逆だった。 焼き込み処理の callbackOrder を当初 -1000 にしていた。追加パッケージ側の検証(callbackOrder = 0)より先に焼き込みが走るので、検証が BuildFailedException でビルドを止めても、秘密情報はすでに Assets 配下へ書き出されていた。+1000 に変えて「検証が通ってから焼き込む」順にした。
public int callbackOrder => 1000; // 検証(0)より後に焼き込む
失敗ビルドでは OnPostprocessBuild が呼ばれない。 後処理での削除だけを想定していたので、失敗のたびに焼き込んだ Asset が残った。起動時の掃除([InitializeOnLoadMethod])を保険として入れたが、「次の Domain Reload まで残る」時間窓は消えない。最終的に McBuildPipeline.Build の finally から必ず削除を呼ぶようにした。
.env の読み書きで刺さった。 先頭に UTF-8 の BOM が残っていると 1 行目のキーだけ読めない。前後に空白のある値や引用符付きの値をそのまま書くと、読み直した時に別の値になる。設定 Asset を新規作成した直後にキャッシュが古いまま残る。いずれも「単純な形式」ほど往復(書いて読む)テストを厚くすべき類型だった。
教訓
- 秘密情報が「残る」経路を全部数える。 正常系の後処理だけでは足りない。失敗・例外・中断のすべてで削除が走るか、
finallyまで降りて確認する。 - ビルドフックの実行順は仕様である。
callbackOrderの符号ひとつで「検証失敗時に秘密が書き出されるか」が変わる。意図をコメントに残す。 - 設定の持ち場所は 1 か所に寄せる。 二重管理は切り替え忘れの温床になる。
- 秘密情報の UI は書き込み専用が正しい既定。 読み戻さないので、画面共有経由の漏洩が構造的に消える。伏せ字欄は入力の有無が分からないので「入力中:N 文字」を併記する。
- テキスト設定ファイルは BOM・空白・引用符で必ず刺さる。
注意点
焼き込み先は暗号化していない。ビルド成果物を解析すれば値は読める。自分たちで運用する配信用ビルドを前提にしており、第三者へ配布するビルド向けの保存方式は別途設計する。起動時の掃除は保険として残しているが、これが発火したら finally を通らないビルド手段があったということなので、原因を追う。
Related Articles