はじめに
iOSアプリにおいて、サードパーティSDKなどから提供されるAPI KeyやSecretsなど、機密情報をどのようにセキュアに管理するといいでしょうか。
単純に実装するとハードコーディングや、設定ファイルなどに記述し、リポジトリにpushするようになってしまうと思いますが、セキュリティの観点からはアプリと同じリポジトリにpushするのはよろしくありません。
例えばリポジトリに閲覧権限を持っている場合、API Keyを使ってAPIサービスの実行ができてしまったり、CIツールなどでソースコードを外部からアクセスさせている場合、CIツールへ不正アクセスされ漏洩する可能性や、ipaファイルからリバースエンジニアリングツールを使って文字列を抽出される可能性もあります。
そのため、例えGitHubのプライベートリポジトリだったとしても、機密情報の扱い方を考える必要性があります。
注意
この手法は、あくまで難読化やリポジトリから除外することで、漏洩リスクを下げる方法で、完全にセキュアというわけではありません。
完全にセキュアにするためには、そもそもアプリには埋め込まないことです。
cocoapods-keys
これまでiOSアプリでは、cocoapods-keysが使われることが多かったと思います。
cocoapods-keysはCocoapodsのプラグインとしてGemで作られています。
しかしながら、昨今のiOSアプリではSwift Package Managerの登場により、CocoaPodsからなるべく依存を減らそうという流れが強くなっています。
Arkana
そこで、2022/6に新たな代替えライブラリとして「Arkana(アルカナ)」が登場しています。
Arkanaの特徴
- Gem
- Swift Package Manager/CocoaPods対応
-
.env
ファイルからSwiftコード自動生成 - 将来的にAndroidも対応予定?(2022/7時点ではまだAndroid未対応)
使い方
インストール
通常のGemインストールになります。READMEにもbundlerを使うことが推奨されていますので、以降もbundlerを使用した前提で記載します。
gem 'arkana', '~> 1.1.1'
$ bundle install
ちなみにRubyは2.7.0以上が対応となっています。
.arkana.yml
作成
次に、.arkana.yml
を作成します。template.ymlが用意されていますので、それに従ってルートディレクトリに配置します。
日本語訳を載せておきます。
import_name: 'ArkanaKeys' # オプション。インポートするフレームワークの名前。デフォルトはArkanaKeys。
namespace: 'Keys' # オプション。コードベース内のシークレットにアクセスするために使用する名前空間。デフォルトは ArkanaKeys です。
pod_name: 'ArkanaKeys' # オプション。Podfileで宣言するPodの名前。デフォルトはArkanaKeysです。
result_path: 'dependencies' # オプション。この設定ファイルのパスに関連する、生成されたコードのデスティネーションパス。デフォルトはArkanaKeys。
flavors: # オプション。 Flavorsは、環境変数から読み込む際に、すべてのシークレットに接頭辞として追加されるキーワードです。これは、例えばホワイトレーベルのプロジェクトで便利です。詳しくはREADMEの「使い方」のセクションをご覧ください。
- FrostedFlakes
- FrootLoops
swift_declaration_strategy: let # オプション。lazy var, var, letから選ぶ。デフォルトはlet。
should_generate_unit_tests: true # オプション。true, falseから選ぶ。デフォルトはtrue。
package_manager: cocoapods # オプション。spm, cocoapodsから選ぶ. 両方使う場合は、cocoapodsを宣言してください。デフォルトはspmです。
environments: # オプション。環境間で異なるキーがある場合 (例: debug/staging/prod) にsecret keyを生成するために使用される環境のリストです。デフォルトは空です。
- Debug
- Release
global_secrets: # オプション。どの環境を構築するかに関係なく同じであるsecretのリスト。デフォルトは空です。
- MySecretAPIKey
- AppStoreAppID
- BackendDomain
environment_secrets: # オプション。このリストの各エントリに対して、envの名前に対応するサフィックスを付加して1つのsecretを作成します。デフォルトは空です。
- MyServiceAPIKey # MyServiceAPIKeyDebug と MyServiceAPIKeyRelease の環境変数を検索します (フレーバーが宣言されていない場合)。
import
の名前なども細かく指定できるのは面白いなと思います。とはいえ特にこだわりがなければ、global_secrets
だけ設定でも十分だと思いました。
environments
やenvironment_secrets
でうまく分けられればそれはそれでいいと思いますが、サービスによって2種類があるものと、3種類以上の環境で分けているものなどバラバラになる可能性があると思いますので、それにより冗長な設定をするよりはシンプルにglobal_secrets
だけを使った方がいいかもしれません。
.env
作成
次に、.env
ファイルを作成します。
MySecretAPIKey=hogehoge
MySecretAPIKey2=hogehogehoge
.env
ファイルは、key=value
の形式でテキストファイルで作成します。
この.env
ファイルをアプリのリポジトリとは別に管理する必要があります。もし社内ホスティングのgitサーバーがあれば、そちらに保管すると良いでしょう。
コード生成
コードの生成はarkana
コマンドを使用します。
$ bundle exec arkana -c /path/to/your/.arkana.yml -e /path/to/your/.env
-c
は.arkana.yml
のpath、-e
は.env
のpathで、省略すると、それぞれルートディレクトリから探されます。
実行すると、Swiftコードが生成されます。
keyはバイトコードに難読化されたコードで生成され、実行の度に変更されます。
Package追加
package_manager
をデフォルトのspmにしていれば、Swift Packageが同ディレクトリに生成されますので、アプリにlocal packageとして追加します。
ArkanaKeys
とArkanaKeysInterfaces
の2つのPackageが生成されますが、アプリからはArkanaKeys
だけを参照として追加すればOKです。
Xcode > File > Add Packages...
Swiftコードからのアクセス
Swiftコードでアクセスするには、global_secrets
を設定するとGlobal()
でstructを生成し、key名でアクセスできます。
import ArkanaKeys
let mySecretAPIKey = ArkanaKeys.Global().mySecretAPIKey
git監視対象から除外
関連ファイルは.gitignore
に記載して、git監視対象から除外しましょう。
.env
ArkanaKeys/*
Makefileでコマンドを登録
チーム開発する場合は、.env
ファイルとArkanaの実行を自動化すると良いでしょう。
Makefileを作り、以下のようなコマンドを登録しておくと良いと思います。
# make env
# - 社内ホスティングサーバーから`.env`ファイルをcloneする
# - `.env`ファイルをルートディレクトリにコピー
# - cloneしたディレクトリを削除
env:
git clone git@my-internalserver.example.com/my-secrets.git
cp ./my-secrets/.env ./.env
rm -rf ./my-secrets
# make secrets
# - arkana実行
secrets:
bundle exec arkana -c ./.arkana.yml -e ./.env
Bitrise上で.env
を生成
次に、CIサービスにBitriseを使用している場合に、.env
を生成します。GitHub Actionsでも同様の設定でできると思います。
BitriseのWorkflowにはSecretsが登録できます。
ここに、base64でエンコードした.env
ファイルの中身を設定します。
$ base64 .env | pbcopy
pbcopy
でクリップボードにコピーできますので、ここではENV_FILE
とkey名を設定します。
次に、
$ echo $ENV_FILE | base64 -d > .env
のscriptで環境変数からbase64でデコードして、.env
ファイルを生成して書き込みます。
- script@1:
title: generate .env file
inputs:
- content: |-
#!/usr/bin/env bash
# fail if any commands fails
set -e
# debug log
set -x
echo $ENV_FILE | base64 -d > .env
このscriptステップをarkana
コマンド実行前に追加すれば、CI上でもビルドすることができます。
さいごに
今回はiOSアプリにおける機密情報の取り扱いと、新しいライブラリArkanaをご紹介させて頂きました。
お役に立てば幸いです。