モヒカンは正義

プログラマー風林火山で言う「風のエンジニア」になりたい(比較的)若者Webエンジニアの備忘録

travis encrypt-fileに気をつけろ!2回コマンド叩くと復号に失敗する!?

なんか釣りっぽいタイトルになってしまいましたが、そんな意図はありませんw

CI/CDツールとして良くTravis CIを使っています。CDの際などにアプリ設定やDB接続情報と言った機微情報を扱うとき、travis-cliの travis encrypt-file というコマンドを使うとTravis CIだけが複合可能な形で暗号化することができ、とても便利です。

github.com

ですが、その travis encrypt-file というコマンドにはトラップが有って、最近そのトラップを盛大に踏み抜いて爆死したので注意喚起とワークアラウンドをまとめます。

f:id:pinkumohikan:20190124201752p:plain
やっちまったらすぐ共有!

“travis encrypt-file” を同じディレクトリで2回叩くと、以前暗号化したものが復号できなくなる

これは仕様らしいです。

例:

  1. travis encrypt-file aaa.json叩く -> aaa.json.encが出来る -> aaa.json.encは復号可能
  2. travis encrypt-file bbb.json叩く -> bbb.json.encが出来る -> aaa.json.encは復号できない、 bbb.json.encは復号可能

qiita.com

ところで、travis encrypt-fileで複数ファイルを暗号化すると、最後に暗号化したファイルしか復号できません。このことはTravis CIのマニュアルにも記載があり、必要ファイルをtarに固めて1ファイルにするというワークアラウンドが紹介されています。

本当にドキュメントにもしれっと書かれていた。 まあでもドキュメントって細部まではあんまり読みませんよね。

docs.travis-ci.com

The Command Line Client overrides encrypted entries if you use it to encrypt multiple files. If you need to encrypt multiple files, first create an archive of sensitive files, then decrypt and expand it during the build.

元issueはこれっぽい

github.com

ワークアラウンド1: tarで固めて1個だけ travis encrypt-file する

まずは公式に乗っている正攻法から。

手順:

  1. 必要なアレコレをtarで固める
  2. travis encrypt-file コマンドを叩く
  3. .encファイルをcommit
  4. before_install hookとかで復号
  5. tarを展開
  6. 必要な場所に配置して使う

この方法のデメリットは、tarで固めるべきファイルが何かを誰でも分かる状態にするのが難しいこと。

自分だけが暗号化するならあまり問題にはならないかもですが、誰か別の人が暗号化しうるなら気にすべき。一度暗号化したものはTravisCIしか復号できないので、何がtarに入っているべきかをtarで固める人は知っていないといけない。必要なファイルが1個2個ぐらいならREADMEとかに書くでどうにかなりそうだけど、5個とか6個とかになってくると手動では抜け漏れが起きそう。

ワークアラウンド2: ディレクトリユニークであれば良いことを利用したハック

下記記事の 1つのディレクトリで1つのファイルしか使えない? で知った、ディレクトリユニークであれば復号できるという振る舞いを利用したハック。

rcmdnk.com

手順:

  1. ランダムな名前のディレクトリをつくる
  2. 今回暗号化したいファイルをそのディレクトリへコピー
  3. そのディレクトリで travis encrypt-file コマンドを叩く
  4. .encファイルをcommit
  5. before_install hookとかで復号
  6. 必要な場所に配置して使う

この方法のメリットは、暗号化する人はそのとき暗号化したいファイルのことだけ気にすれば良くなること。

この方法のデメリットは、もしディレクトリ名がかぶったら先に暗号化したものが復号できなくなること。

個人的な一押しは、ディレクトリユニークを利用したハック

名前がかぶったらダメっていうのはそれはハッシュにおける衝突と似たような問題なので、ディレクトリ名を長く複雑にすればリスクとしては低減できそう。仕組みさえ用意できれば、都度必要なファイルを全部用意するよりも楽そう。

そして、ここに便利Makefileを用意しました。

encrypt: FILE_NAME=
encrypt:
    test -n "$(FILE_NAME)" && ls $(FILE_NAME) >/dev/null
    $(eval TEMP_DIR=$(shell mktemp -d tmp-XXXXXXXXXX))
    cp $(FILE_NAME) $(TEMP_DIR)
    cd $(TEMP_DIR) && travis encrypt-file $(FILE_NAME)
    cp $(TEMP_DIR)/*.enc .
    rm -rf $(TEMP_DIR)

使い方は $ make encrypt FILE_NAME=sensitive-data.json みたいな感じ。これをTravis CI用のファイルをまとめているディレクトリにボンっと置いて使っています。

やっていることは、ランダムな名前で一時ディレクトリを作り、そこに指定されたファイルをコピーしてtravis encrypt-fileコマンドを叩き、作られた.encファイルをコピーしたのち一時ディレクトリを削除する、といったことです。

実行例はこんな感じ

$ make encrypt FILE_NAME=sensitive-data.json
test -n "sensitive-data.json" && ls sensitive-data.json >/dev/null
cp sensitive-data.json tmp-1pBHxolDaS
cd tmp-1pBHxolDaS && travis encrypt-file sensitive-data.json
encrypting sensitive-data.json for pinkumohikan/some-repository
storing result as sensitive-data.json.enc
storing secure env variables for decryption

Please add the following to your build script (before_install stage in your .travis.yml, for instance):

    openssl aes-256-cbc -K $encrypted_xxx_key -iv $encrypted_xxx_iv -in sensitive-data.json.enc -out sensitive-data.json -d

Pro Tip: You can add it automatically by running with --add.

Make sure to add sensitive-data.json.enc to the git repository.
Make sure not to add sensitive-data.json to the git repository.
Commit all changes to your .travis.yml.
cp tmp-1pBHxolDaS/*.enc .
rm -rf tmp-1pBHxolDaS

ちなみに、travis encrypt-fileコマンドを叩くときのディレクトリがgitリポジトリ外だと「このリポジトリどこやねん?」って聞かれてうざいので注意。