はじめに
Rails 5.2から、config/secret.ymlは廃止され、基本的にconfig/credentials.yml.encで管理するように変更されています。credentials.yml.enc自体は暗号化されているので、通常通りgit管理下に置いておいて、master.keyという復号キーのみを別管理にするという仕組みに変わりました。
credentials.yml.encにはsecret.ymlで書いていたようなsecret_key_baseを記述します。(他にもAPIキーなども記述できます)
production環境だと上のような形で問題ないのですが、development, test環境ではsecret_key_baseを指定できません><Rails側で適当に作られてしまっているのです!!
どういうこと?
Rails 5.2.0ブランチにおけるsecret_key_baseを取得するメソッドは下のようになっています。
def secret_key_base
if Rails.env.test? || Rails.env.development?
Digest::MD5.hexdigest self.class.name
else
validate_secret_key_base(
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
)
end
end
お分かりいただけただろうか……development, test環境だと適当な文字列が適当にハッシュ化されたもの以外設定できません。
ついでに、productionでの仕様もわかりやすいですね、ENV→credentials→secrets(config/secrets.yml)の順に優先度が低くなっていきます。
これは流石にまずかったのか、Rails 5.2-stableブランチでは以下のように修正されました。config/secrets.ymlがあればそちらが優先されます。
def secret_key_base
if Rails.env.test? || Rails.env.development?
secrets.secret_key_base || Digest::MD5.hexdigest(self.class.name)
else
validate_secret_key_base(
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
)
end
end
なんでこの問題にハマったか
message_verifierの暗号化と復号化をそれぞれ別Railsプロジェクトで行おうとすると、secret_key_baseを同じ値にする必要が出てきますが、Rails5.2.0のdevelopmentだとどうしてもInvalidSignatureエラーが出てくるので、不審に思いソースまで追ってみました。
そもそもsecret_key_baseを複数プロジェクトで共有するという作りもどうなんだろう?という感じはしています。