GitHubでプライベートな情報を隠す

Posted by rhoboro on 2016-06-28

皆さんはGitHub使ってますか?
GitHubとても便利なのですが、無料プランだとパブリックなリポジトリしか作成できません。 そこで気になってくるのが、APIキーなどのプライベートにしておきたい情報の隠し方だと思います。

今回はその方法をいくつか紹介します。
ほぼろの経験と思い付きがベースになっているので間違っているところやもっといい方法もあると思いますのでそこはご注意ください。
何か思うところのあった方は気軽にTwitterでツッコんでいただければと思います。

プライベートな情報の隠し方一覧

パッと思いついた方法を一覧にしてみました。
各方法の詳細はこれから個別に見ていきます。

  1. 環境変数に入れる
  2. 別ファイルに書き出し、そこから読み取る
  3. ビルド時にスクリプトでファイルを直接書き換える
  4. ビルドコマンドの引数として渡す
  5. サーバーに保存して、アプリ起動後にAPI経由で取得する

環境変数に入れる

  • メリット
    • アプリケーションを問わずいつでも使える
    • HerokuやCircleCIなどのSaaSを利用する際にも、WEB画面から簡単に設定できることが多い
  • デメリット
    • 環境変数から値を取得する方法がフレームワークにより様々
    • なければないで空文字になる(ことが多い)ためビルドは通ってしまう
    • ターミナル起動後に環境変数を読み込んでいる場合、アプリケーションはそのターミナルから起動する必要がある

王道ですね。
ほぼろが現在開発中のAndroidアプリはこの方法をとっていて、 Gradleからこんな感じで参照しています。

google_map_apikey: System.getenv("GOOGLE_MAP_APIKEY") != null ? System.getenv("GOOGLE_MAP_APIKEY") : ""

ちなみにほぼろの場合、環境変数をenvsというファイルに記載して、source envsで読み込んでから、openコマンドでAndroidStudioを起動しています。 もちろんenvsファイルは.gitignoreに追加しています。

別ファイルに書き出し、そこから読み取る

  • メリット
    • ファイルをプロジェクトの一部として組み込んでおける
    • Androidならxml、iOSならplistなど簡単にアクセスできる方法が用意されていることが多い
    • 必要なデータを1箇所にまとめられる
  • デメリット
    • ファイルがなくてもビルドを通すことは可能(最悪の場合、ランタイムで落ちるまで気づかない)
    • ビルドしたバイナリにこのファイルがそのまま含まれる場合は簡単に漏れる可能性がある

基本的には環境変数と同じくらい使い勝手はいいと思っています。 AndroidやiOSでない場合でも、iniファイルやjsonなど汎用的な形式がたくさんあるので値の取得にはさほど困ることはないはず。
このファイルをプロジェクト内に含めるかどうかでgitignoreへ追加するかどうかが決まります。

ビルド時にスクリプトでファイルを直接書き換える

  • メリット
    • お手軽で万能
  • デメリット
    • このスクリプト自体の管理の問題
    • リポジトリ上のコード=ビルドに利用されたコード、という関係性が薄くなる

grepsedを使うのが一般的ですかね。 問題はやはりこのスクリプト自体の管理が必要になることです。 JenkinsなどのCIツールで書き換える場合は、そもそもスクリプトがファイルとして存在しなくなるので手動でビルドするときに困ったことに。。。
(Jenkinsの場合は、シェルスクリプトなりMakefileなりを作ってそれをJenkinsから叩くほうがバージョン管理できるのでお勧め)

ただ、文字列置換の処理は応用力が非常に高いので覚えておくといいです。
「ビルドに使ったソースコードのgitのハッシュを設定画面に埋め込む」みたいな処理が簡単に実装できるようになります。

ビルドコマンド、実行の引数に渡す

  • メリット
    • CLIでビルド、実行するなら一番手軽にできる
    • 文字列としてはソースコードに記載されないので秘匿性は高い
  • デメリット
    • IDEを使うようなプロジェクトには向かない
    • CIサービスでビルドスクリプトが公開されてしまう場合には使えない

APIを利用するBotみたいな簡単なスクリプトだと重宝する方法です。
CLI系に強い言語だと、引数から値を取得するライブラリなんかもたくさんあります。 Androidもgradlewはたしか任意の引数取れるはず(うろ覚え(笑))

ただ、IDEからビルドする場合引数を渡すことができるかはそのIDE次第となってしまいます。 (私自身はXCodeでもAndroid Studioでもこういう使い方はしたことないのでそもそもできるか不明)

サーバーに保存しておき、アプリ起動後にAPI経由で取得する

  • メリット
    • バイナリには埋め込まれないのでバイナリ解析されても他に比べると安心
    • (アプリなどの場合)リリース後でも値の変更が可能になる
  • デメリット
    • サーバーAPIを用意する必要がある
    • 正しいクライアントであることをどうやって保証するか

アプリバイナリに文字列が含まれないので、情報の秘匿性はこれが一番強固だと思います。
また、リリース後にいつでも値を変更できるというのは他の方法ではできないメリットとなります。

しかし、強固になる分、実装コストは他より高くなるはず。(サーバーもあるし当然といえば当然ですが)
また、アプリの通信環境によりアプリが正常に動作しなくなる可能性もあるでしょう。

まとめ

いかがでしたでしょうか。
個人的には環境変数にしておくのが一番カバーできる範囲が広くて、デメリットも少ないのかなと思います。

ただ、「基本的には環境変数を利用するけど、一番大事な情報のみはAPIで取得する」のように複数の方法を組み合わせることもできますので、 各々の環境にあった最適な解を見つけ出していただけたらと思います。 また、今回紹介した方法以外にもっといい方法がある方は教えていただけると助かります。

ちなみに、GitHubはPersonalプランであれば$7/monthで無制限にプライベートリポジトリを作成できますので、 いろいろとややこしいことを考えるのが面倒な方には素直に課金することをお勧めします(笑)

それでは!