Railsを5.1系から5.2.0.rc1にアップグレードする際に、secrets周りだけ結構変わってるなーと思ったのでまとめときます。
簡単に言っておくと、平文のsecretsは全て廃止して暗号化されたcredentials.yml.encのみを扱うようになりました。また、secrets.ymlは自動生成はされなくなりましたが、ファイルがあれば以前のようにRails.application.secrets
で参照することは出来るのでアップグレードの際にすぐに対応する必要があるわけでは無いです。
発端
DHHいわく、
-
secrets.yml
secrets.yml.enc
ENV['SECRET_KEY_BASE']
の3つの組み合わせだと、環境毎に何処に値を設定すれば良いのかわかりづらいし複雑だよね。 - 新しく
config/credentials.yml.enc
を追加して一元管理できるようにして、環境に関係なくconfig/master.key
かENV['RAILS_MASTER_KEY']
で復号化できるようにしようよ。 -
credentials.yml.enc
は本番でのみ使われる想定だから、secrets.yml
みたいに環境毎に分割されたりしないよ。 - Rails自体は復号化のkeyが無くても動くようにしておくから、開発やテストみたいな復号化の必要がない環境ではkeyは要らないようにしておくよ。
- localとかテストみたいな環境では攻撃に耐える必要無いから、簡単な値を代わりに使っても問題ないよ。
-
secrets.yml*
は動くようにしておくから、アプリケーションが壊れたりすぐに移行する必要が有るわけでは無いよ。
という感じで、Encrypted secretsは中途半端だったから止めて新しい暗号化の機構を追加した感じですね。
暗号化
Rails 5.2 で新しく rails newすると、config/master.key
とconfig/credentials.yml.enc
が生成されるようになっています。(config/master.keyは.gitignoreに最初から追加されてますが、アップグレードする人は注意しておいたほうが良いです)
編集する場合には bin/rails credentials:edit
で復号化されたファイルがエディターで開けます。エディタ指定したい場合は環境変数EDITOR
でエディタを開く際のコマンドを指定しましょう。(EDITOR=vim bin/rails credentials:edit
)
復号
読み込みの際には、config/master.key
に復号化用の文字列を書き込むか、環境変数ENV['RAILS_MASTER_KEY']
を使って復号化します。
開発環境やテストではsecret_key_baseは復号化出来なくても仮の値が使われると書かれているとおり、デフォルトではnilが返るだけです。本番で誤って値を設定しないままデプロイ/サービスインしてしまわないように値が設定されていない場合は例外を投げるオプションが有ります。
config.require_master_key = true
また、Deviseやその他でRails.application.secrets.secret_key_base
をsaltに使ってるようなケースでは修正が必要です。自分のケースではsecrets.ymlはほとんど使ってなかったのでcredentialsに統一したので、ここでアプリの修正をする必要が有りました。
フォーマット
追記
Rails 6 以降からは複数環境に対応したファイルを作成できるようになります。
https://github.com/rails/rails/pull/33521
secretsと大きく変わる点として、各環境毎に設定値が分割されずにフラットな構造になりました。設定することは可能ですが、Railsが自動で読み分けてくれるわけではないという意味です。
secret_key_base: a
aws:
access_key_id: 1
secret_access_key: 2
これは結構困る人が多そうな感じが有りますね。Rails本体でも議論されてましたが、DHHが意図してフラットな構造にしてると言っていたので恐らくこれはしばらくこのままな気がします。
ただ個人的にはこの方向性は正しいかなと感じていて、環境毎に細かく分けたい場合はsecrets経由ではなく環境変数をそのまま使うようにすれば良いかなと。
どうしても環境別に暗号化してgitにpushしておきたいとかがあれば
# config/credentails.yml.enc
development:
aws:
access_key_id: 12345
# lib/credentails.rb
class Credentials
def self.env
Rails.application.credentials[Rails.env.to_sym]
end
end
Credentials.env.dig(:aws, :access_key_id) # => 12345
みたいなのを簡易的に用意してあげれば良いかなー。
おわり
最近はKubernetesで運用することがほとんどなので、そもそもRails.envをデフォルトの3つしか使わずに、ローカル以外はRAILS_ENV=productionで全て環境変数で設定みたいな運用をすることが多いのでsecrets.ymlもcredentials.yml.encもあまり必要としていなかったので、SECRET_KEY_BASE
からRAILS_MASTER_KEY
に統一されたのは分かりやすくなってよかったなという印象でした。おわり。