![]() |
このテキストは、 Flutter Meetup Osaka #4 - 2020/11/27 - LT発表 フラッター開発でのシークレット情報取扱考察 の検証編です。
GitHub リポジトリに秘匿情報を commit させない で、ビルド前に ビルド環境内で秘匿情報ファイルを復元 させて、
$ flutter run コマンド実行時に、復元した秘匿情報ファイルを伴なわせてビルドさせる、
Flutter開発における リポジトリでのシークレット情報取扱考察 の 考察検証リポジトリ での検証方法と、
「リポジトリに存在しない秘匿情報を復元するために、具体的に何をしているのか」についての解説です。
Flutter に関する技術的情報は、ほとんどないことや、
シークレット情報の取り扱いには、秘匿化専用サービスやツールもありますが、
ここでは簡易に内製化できる範囲にとどめます旨、御了承願います。
本当のシークレット情報をサンプルとして提供する訳には行きませんので、
具体的には、 $ flutter run で実行した際のアプリ名 memojudge が、
環境変数にパスワード内容等を設定すれば、
リポジトリ内に存在しない別名称 記憶力判定 などでビルドされるサンプルを提供します。
リポジトリ内のスクリプトは、macOS および Linux での bash や zsh での実行を想定しています。
Windows 10環境での動作確認はできていません。
検証リポジトリでは、秘匿情報を復元する基本的なパターンを行う2種類のスクリプトを実装しました。
スクリプトを使わない⇒リポジトリ内情報のみのビルド結果は、アプリ名がmemojudgeになります。
メモ判定)をビルド結果に反映できるスクリプト。記憶力判定)をビルド結果に反映できるスクリプト。秘匿情報を復元する基本的なパターンを実現するためには、各種機能ごとの連携が必要です。
スクリプトを機能させるには、入力元や出力先の規定や、ビルド中に処理をキックさせる設定も必要です。
検証リポジトリでは、各機能ごとに連携できるよう、以下の全体構成を採りました。
秘匿情報復元作業ディレクトリ構成
入力元とエンコードやデコードの出力先およびスクリプトの配置を定めます。
秘匿情報復元処理スクリプト
入力された秘匿情報のエンコードやデコードおよびビルド中処理を役割ごとに分けます。
秘匿情報復元ビルド設定
ビルド中処理(復元秘匿情報ファイルの配置先コピー)をビルド中にキックさせる設定を追加します。
![]() |
| ディレクトリ名 | 公開 / 非公開 | 役割概要 |
|---|---|---|
| build_assists | 公開 | 秘匿情報復元作業ディレクトリのルートディレクトリ |
| scripts | 公開 | スクリプト配置先ディレクトリ |
| work_private | 非公開 | 入力用の秘匿情報ファイル配置先ディレクトリ |
| encode_private | 非公開 | 秘匿情報ファイルの Base64エンコード出力配置先ディレクトリ |
| encode_public | 公開 | 秘匿情報ファイルの OpenSSLエンコード(暗号化済)出力配置先ディレクトリ |
| decode_private | 非公開 | エンコードファイルのデコード(復号化済)出力配置先ディレクトリ |
| .gitignore | 公開 | 上記作業ディレクトリの非公開指定設定ファイル |
| スクリプト名 | 機能種別 | 役割概要 |
|---|---|---|
| encode_base64_work_to_private.sh | Base64エンコード | work_private/に配置された秘匿情報ファイルを Base64エンコードして encode_private/に出力します。 |
| encode_openssl_work_to_public.sh | OpenSSLエンコード | work_private/に配置された秘匿情報ファイルを OpenSSLエンコード(暗号化)して encode_public/に出力します。 |
| decode_from_private.sh | Base64デコード | encode_public/に配置された暗号化済秘匿情報ファイルを OpenSSLデコード(復号化)して decode_private/に出力します。 |
| decode_from_public.sh | OpenSSLデコード | encode_private/に配置されたBase64エンコード済ファイルを Base64デコードして decode_private/に出力します。 |
| アプリ名変更専用 リソース置換用スクリプト名 |
||
| restore_app_name_secret_by_openssl.sh | 一括処理 | アプリ名変更用の補助スクリプト⇒OpenSSLを使った秘匿情報復元(暗号化済ファイルの復号化)から $flutter runまでを一括して実行する。(環境変数 PASSWDに復号化キー(パスワード)を設定しておく必要があります ) |
| replace_app_name_ios.sh | ビルド中処理 | iOS用のアプリ名変更専用スクリプト⇒decode_private/に配置された復元済の秘匿情報ファイル(decode_app_name_ios.txt)をios/Runner/Info.plistにコピーします。 |
| replace_app_name_android.sh | ビルド中処理 | Android用のアプリ名変更専用スクリプト⇒decode_private/に配置された復元済の秘匿情報ファイル(decode_app_name_android.txt)をandroid/app/src/main/AndroidManifest.xmlにコピーします。 |
| アプリ名変更専用 リソース編集用スクリプト名 |
||
| restore_app_name_secret_by_base64.sh | 一括処理 | アプリ名変更用の補助スクリプト⇒Base64を使った秘匿情報復元(変更するアプリ名の取得)から $flutter runまでを一括して実行する。(環境変数 APP_NAMEに Base64エンコードした変更アプリ名を設定しておく必要があります) |
| rewrite_app_name_ios.sh | ビルド中処理 | iOS用のアプリ名変更専用スクリプト⇒decode_private/に配置された変更アプリ名(decode_app_name.txt)の内容で、ios/Runner/Info.plistのアプリ名値を置換編集します。 |
| rewrite_app_name_android.sh | ビルド中処理 | Android用のアプリ名変更専用スクリプト⇒decode_private/に配置された変更アプリ名(decode_app_name.txt)の内容で、android/app/src/main/AndroidManifest.xmlのアプリ名値を置換編集します。 |
| プラットフォーム | 設定場所 | 設定方法 |
|---|---|---|
| iOS | Xcodeプロジェクト > Runner > TARGETS > Build Phase > Run Script | Run Script設定に、sh からビルド中スクリプトをキックさせるコマンドを追加する。 |
| Android | app: build.gradle | build.gradleファイルの末尾に project.afterEvaluate{}を追加して、ビルド中スクリプトをキックさせる関数を追加する。 |
| iOSビルド処理のキック設定例 (Xcodeプロジェクト) |
|---|
![]() |
| Androidビルド処理のキック設定例 (app:build.gradle) |
|---|
|
秘匿情報を復元する基本的なパターン実現するためには、
入力秘匿情報ファイルのエンコード〜秘匿情報ファイル復元のデコード〜復元秘匿情報ファイルの配置…までのフローを行います。
検証リポジトリでは、以下の全体フロー(秘匿情報の入力から復元ファイルの配置までのフロー)を採っています。
秘匿情報ファイルをBase64でエンコードして、秘匿情報ファイルのBase64エンコード文字列を生成
encode_base64_work_to_private.sh スクリプトで、
work_private/に配置した秘匿情報ファイルをエンコードして、encode_private/に出力します。
work_private/は、非公開ディレクトリのためリポジトリに存在しないので、エンコード前に手動生成しておきます。
生成したBase64エンコード文字列(Base64エンコードファイル)は、リポジトリ外で管理する必要があります。
ビルド中処理(復元秘匿情報ファイルの配置先コピー)をビルド中にキックさせる設定を追加
【ビルド中処理】の 復元秘匿情報ファイルをリソース先に配置(コピー)を参照
指定名の環境変数に 秘匿情報ファイルのBase64エンコード文字列(秘匿ファイルの復元データ)を設定
設定するエンコード文字列は、リポジトリ外で管理しておいたBase64エンコードファイルなどから取得します。
環境変数の 秘匿情報ファイルのBase64エンコード文字列をデコードして、秘匿情報ファイルを復元
decode_from_private.sh スクリプトで、
環境変数に設定された秘匿情報ファイルのBase64エンコード文字列をデコードして、decode_private/に出力します。
decode_private/に配置された復元秘匿情報ファイルは、
ファイルごとかつプラットフォームごとにコピー先が異なるため、専用配置スクリプトをプラットフォーム別で用意します。decode_privateに復元秘匿情報ファイルが存在していれば、秘匿情報ファイルを復元する必要はありません。decode_privateに配置された復元秘匿情報ファイルから取得しています。秘匿情報ファイルをOpenSSLでエンコード(暗号化)して、秘匿情報ファイルのエンコード(暗号化)ファイルを生成
encode_openssl_work_to_public.sh スクリプトで、
指定された暗号キー(パスワード文字列)を使い work_private/に配置した秘匿情報ファイルをエンコード(暗号化)して、encode_public/に出力します。
work_private/は、非公開ディレクトリのためリポジトリに存在しないので、エンコード前に手動生成しておきます。
encode_public/に出力された、秘匿情報ファイルの OpenSSLエンコード(暗号化)ファイルは、暗号化済なのでリポジトリに commitできます。
暗号キー(パスワード文字列)は、リポジトリ外で管理する必要があります。
ビルド中処理(復元秘匿情報ファイルの配置先コピー)をビルド中にキックさせる設定を追加
【ビルド中処理】の 復元秘匿情報ファイルをリソース先に配置(コピー)を参照
指定名の環境変数に 秘匿情報ファイルのOpenSSLエンコード(暗号化)に使用した、復号キー(パスワード文字列)を設定
設定する復号キー⇒暗号キー(パスワード文字列)は、リポジトリ外の管理先などから取得します。
環境変数の 複合キー(パスワード文字列)を使い、暗号化された秘匿情報ファイルをOpenSSLデコード(復号化)して、秘匿情報ファイルを復元
decode_from_public.sh スクリプトで、
環境変数に設定された複合キー(パスワード文字列)を使い暗号化された秘匿情報ファイルをOpenSSLデコード(復号化)して、decode_private/に出力します。
decode_private/に配置された復元秘匿情報ファイルは、
ファイルごとかつプラットフォームごとにコピー先が異なるため、専用配置スクリプトをプラットフォーム別で用意します。decode_privateに復元秘匿情報ファイルが存在していれば、秘匿情報ファイルを復元する必要はありません。decode_privateに配置された復元秘匿情報ファイルから取得しています。秘匿情報を復元するために何をしているのかを確認したので、
実装したスクリプトが機能するか否かの検証に移ります。
$ git clone https://github.com/cch-robo/memojudge_with_secret_consideration.git
リポジトリ内のスクリプトは、macOS および Linux での bash や zsh での実行を想定しています。
Windows 10環境での動作確認はできていません。
検証に使うスクリプト(下記)は、プロジェクト・ルートディレクトリからの実行を想定しています。
decode_from_private.sh、 decode_from_public.sh、
encode_base64_work_to_private.sh、 encode_openssl_work_to_private.sh、
restore_app_name_secret_by_base64.sh、 restore_app_name_secret_by_openssl.sh
リポジトリに秘匿情報を保管させないコンセプトについては、
リポジトリでのシークレット情報取扱考察 全般を御確認ください。
秘匿情報のエンコード/デコードおよび暗号化/復号化に利用する
Base64や OpenSSL コマンドについては、P.12 〜 P.20 を御確認ください。
秘匿情報の暗号化/復号化には、OpenSSL 1.1.1 以上の共通鍵暗号方式を使います。
$ openssl version で、お使いの環境が OpenSSL 1.1.1 以上になっているか確認してください。
homebrew を使って最新の OpenSSL をインストールするかアップデートしてください。
macOS 標準の openssl コマンドの実態は LibreSSL になっています。
OpenSSLのインストールや環境設定の概要については、
リポジトリでのシークレット情報取扱考察 の P.20 を御確認ください。
Android Studio の terminalでは、OpenSSLを優先化するパス設定を行ってください。
Android Studio の Terminalでは、LibreSSLが優先化されるようです。
このため ~zshrcや ~bashrcで OpenSSLへのパス設定を行っていても、
このTerminalで、$ export "PATH=$(brew --prefix openssl)/bin:$PATH" を実行して、
インストールした OpenSSL へのパス /usr/local/opt/openssl@1.1 を優先化してください。
LibreSSLが有効になっている場合、暗号化や復号化処理がマルウェアと判断される場合があります。

検証リポジトリでは、秘匿情報を復元する基本的なパターンを行う2種類のスクリプトを実装しています。
メモ判定)をビルド結果に反映できるスクリプト。記憶力判定)をビルド結果に反映できるスクリプト。【検証概要】
環境変数に何も設定していなければ、
ビルド前に 秘匿情報ファイルの復元を実行してもエラーにされ、
$flutter runを実行させても、
通常のビルド(アプリ名がmemojudge)しか行われないことを確認する。
環境変数に、秘匿情報の復元データ または 復号キーを設定(A/Bパターン)して、
ビルド前に 秘匿情報ファイルの復元を実行し、$ flutter runビルドを行なわせれば、
リポジトリに存在しない秘匿情報を伴ったビルド(アプリ名の変更)が行われることを確認する。
$ flutter runビルドを行わせます。memojudgeになる)# flutter run 実行前に、iOS シミュレーターを起動しておいてください。
$ ./build_assists/scripts/decode_from_private.sh APP_NAME_IOS decode_app_name_ios.txt
# 上記スクリプト実行は、指定環境変数設定がないのでエラーにされます。
$ flutter run
| ビルド後のホーム画面 | アプリアイコン |
|---|---|
![]() |
# flutter run 実行前に、Android エミュレーターを起動しておいてください。
$ ./build_assists/scripts/decode_from_private.sh APP_NAME_ANDROID decode_app_name_android.txt
# 上記スクリプト実行は、指定環境変数設定がないのでエラーにされます。
$flutter run
| ビルド後のホーム画面 | アプリアイコン |
|---|---|
![]() |
$ flutter runビルドさせるパターン。Info.plist と AndroidManifest.xmlファイルが置換されます。build_assists/experimentのファイルから取得していますが、# flutter run 実行前に、iOS シミュレーターを起動しておいてください。
$ export APP_NAME_IOS=`cat ./build_assists/experiment/encode_app_name_ios.txt`
$ ./build_assists/scripts/decode_from_private.sh APP_NAME_IOS decode_app_name_ios.txt
$ flutter run
| ビルド後のホーム画面 | アプリアイコン |
|---|---|
![]() |
# flutter run 実行前に、Android エミュレーターを起動しておいてください。
$ export APP_NAME_ANDROID=`cat ./build_assists/experiment/encode_app_name_android.txt`
$ ./build_assists/scripts/decode_from_private.sh APP_NAME_ANDROID decode_app_name_android.txt
$ flutter run
| ビルド後のホーム画面 | アプリアイコン |
|---|---|
![]() |
$ flutter runビルドさせるパターン。Info.plist と AndroidManifest.xmlファイルが置換されます。build_assists/encode_publicのファイルから取得しています。# flutter run 実行前に、iOS シミュレーターを起動しておいてください。
$ export PASSWD=hogefuga
$ ./build_assists/scripts/decode_from_public.sh encode_app_name_ios.txt decode_app_name_ios.txt PASSWD
$ flutter run
【補足】秘匿情報の復元と$ flutter runまでを一括して行うスクリプトも用意しています。
# flutter run 実行前に、iOS シミュレーターか Android エミュレータを起動しておいてください。
$ export PASSWD=hogefuga
$ ./build_assists/scripts/restore_app_name_secret_by_openssl.sh
| ビルド後のホーム画面 | アプリアイコン |
|---|---|
![]() |
# flutter run 実行前に、Android エミュレーターを起動しておいてください。
$ export PASSWD=hogefuga
$ ./build_assists/scripts/decode_from_public.sh encode_app_name_android.txt decode_app_name_android.txt PASSWD
$ flutter run
【補足】秘匿情報の復元と$ flutter runまでを一括して行うスクリプトも用意しています。
# flutter run 実行前に、iOS シミュレーターか Android エミュレータを起動しておいてください。
$ export PASSWD=hogefuga
$ ./build_assists/scripts/restore_app_name_secret_by_openssl.sh
| ビルド後のホーム画面 | アプリアイコン |
|---|---|
![]() |
復元した秘匿情報ファイルを配置先にコピー(リソースファイルの追加/置換)するだけでなく、
アプリ名を変更するため、リソースファイルの一部分のみを「復元した秘匿情報で置換」するサンプルも作りました。
ブランチを rewrite_secret_item切り替えれば、ビルド中にキックされるスクリプトが、
iOS ⇒ rewrite_app_name_ios.sh に、
Android ⇒ rewrite_app_name_android.sh に変更されます。
この状況で、環境変数 APP_NAME に「変更する任意のアプリ名を Base64エンコードした文字列」を設定して、
restore_app_name_secret_by_base64.sh を実行すれば、
アプリ名を任意のアプリ名に変更することができます。
処理内容的には、アプリ名を変更するため、ios/Runner/Info.plistの CFBundleNameのアプリ名値と、
android/app/src/main/AndroidManifest.xmlの android:labelのアプリ名値の置換を行っています。
下記のコマンドを実行すると、アプリ名が 名前置換に変更されますよ。
# アプリ名を設定するリソースファイルのアプリ名部のみを置換するサンプルのブランチ
$ git checkout rewrite_secret_item
# flutter run 実行前に、iOS シミュレーターか Android エミュレータを起動しておいてください。
$ export APP_NAME=5ZCN5YmN572u5o+b
$ ./build_assists/scripts/restore_app_name_secret_by_base64.sh
フラッター開発でのシークレット情報取扱考察 と
考察検証説明の Flutter 開発リポジトリにシークレット情報を保管させない。
および 考察検証リポジトリ の内容は、簡易に内製化できる範囲にとどまっています。
このため商用 CI/CD サービスを使ってシークレット情報管理をされている方から見れば、初歩レベルと思います。
また注意事項として、この検証リポジトリでは変更がわかりやすくなるように、
秘匿情報を反映させるファイル(Info.plistやAndroidManifest.xml)を公開設定しています。
このため秘匿情報が反映(名前変更)された版をリポジトリに commitすることができることに留意ください。
秘匿情報を反映させるファイルは、本来非公開設定にして誤コミットされないようにすることが必須でしょう。
もしもこのリポジトリに秘匿情報を保管させない考察と 考察検証リポジトリが、お役に立つことがあれば幸いです。