memojudge_with_secret_consideration

Flutter #2 Advent Calendar 2020

12月01日 Flutter 開発リポジトリにシークレット情報を保管させない。

はじめに

秘匿情報が漏出すれば

このテキストは、 Flutter Meetup Osaka #4 - 2020/11/27 - LT発表 フラッター開発でのシークレット情報取扱考察 の検証編です。
GitHub リポジトリに秘匿情報を commit させない で、ビルド前に ビルド環境内で秘匿情報ファイルを復元 させて、
$ flutter run コマンド実行時に、復元した秘匿情報ファイルを伴なわせてビルドさせる、
Flutter開発における リポジトリでのシークレット情報取扱考察考察検証リポジトリ での検証方法と、
「リポジトリに存在しない秘匿情報を復元するために、具体的に何をしているのか」についての解説です。




秘匿情報を復元するために何をしているのか

検証リポジトリでは、秘匿情報を復元する基本的なパターンを行う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プロジェクト)
Xcodeプロジェクト Run Script
Androidビルド処理のキック設定例 (app:build.gradle)

def replace_app_name() {
    exec {
        commandLine 'sh', '-c', '../../build_assists/scripts/replace_app_name_android.sh'
    }
}
project.afterEvaluate {
    replace_app_name()
}
  


秘匿情報を復元する基本的なパターンの全体フロー

秘匿情報を復元する基本的なパターン実現するためには、
入力秘匿情報ファイルのエンコード〜秘匿情報ファイル復元のデコード〜復元秘匿情報ファイルの配置…までのフローを行います。
検証リポジトリでは、以下の全体フロー(秘匿情報の入力から復元ファイルの配置までのフロー)を採っています。



秘匿情報を復元するために何をしているのかを確認したので、
実装したスクリプトが機能するか否かの検証に移ります。




検証準備と注意事項


リポジトリに保管されていない秘匿情報の復元検証

検証リポジトリでは、秘匿情報を復元する基本的なパターンを行う2種類のスクリプトを実装しています。


【検証概要】

  1. 環境変数に何も設定していなければ、
    ビルド前に 秘匿情報ファイルの復元を実行してもエラーにされ、
    $flutter runを実行させても、
    通常のビルド(アプリ名がmemojudge)しか行われないことを確認する。

  2. 環境変数に、秘匿情報の復元データ または 復号キーを設定(A/Bパターン)して、
    ビルド前に 秘匿情報ファイルの復元を実行し、$ flutter runビルドを行なわせれば、
    リポジトリに存在しない秘匿情報を伴ったビルド(アプリ名の変更)が行われることを確認する。



通常パターンの検証 (秘匿情報を復元しない)


iOS 検証手順
# flutter run 実行前に、iOS シミュレーターを起動しておいてください。
$ ./build_assists/scripts/decode_from_private.sh APP_NAME_IOS decode_app_name_ios.txt
# 上記スクリプト実行は、指定環境変数設定がないのでエラーにされます。

$ flutter run
ビルド後のホーム画面アプリアイコン
ホーム画面 アイコン


Android 検証手順
# flutter run 実行前に、Android エミュレーターを起動しておいてください。
$ ./build_assists/scripts/decode_from_private.sh APP_NAME_ANDROID decode_app_name_android.txt
# 上記スクリプト実行は、指定環境変数設定がないのでエラーにされます。

$flutter run
ビルド後のホーム画面アプリアイコン
ホーム画面 アイコン



Aパターンの検証 (環境変数に復元データをもたせる)


iOS 検証手順
# 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
ビルド後のホーム画面アプリアイコン
ホーム画面 アイコン


Android 検証手順
# 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
ビルド後のホーム画面アプリアイコン
ホーム画面 アイコン



Bパターンの検証 (環境変数に復号キーをもたせる)


iOS 検証手順
# 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
ビルド後のホーム画面アプリアイコン
ホーム画面 アイコン


Android 検証手順
# 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.plistCFBundleNameのアプリ名値と、 android/app/src/main/AndroidManifest.xmlandroid: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.plistAndroidManifest.xml)を公開設定しています。
このため秘匿情報が反映(名前変更)された版をリポジトリに commitすることができることに留意ください。
秘匿情報を反映させるファイルは、本来非公開設定にして誤コミットされないようにすることが必須でしょう。

もしもこのリポジトリに秘匿情報を保管させない考察考察検証リポジトリが、お役に立つことがあれば幸いです。