secret_key_baseがどういうふうに扱われているか
Railsアプリを本番デプロイしたらsecret_key_baseが未定義っておこられたので、どういう扱いになってるのか確認してみた。
確認したRailsのバージョンは6.0.0.rc1。
はじめにまとめ
secret_key_baseの設定場所は4箇所ある:
- 環境変数:
ENV["SECRET_KEY_BASE"]
- credencials:
config/credentials.yml.enc
- secrets:
config/secrets.yml
(Encrypted secretsが有効ならconfig/secrets.yml.enc
) tmp/development_secret.txt
環境ごとの評価順:
- developmentかtestなら、secrets、
tmp/development_secret.txt
の順 - それ以外の環境なら、環境変数、credencials、secretsの順
secret_key_baseの取得
Rails.applicatin.secret_key_base
#=> "bb7a320962dda4262e21262f80229946f5a3b3c05cc8968d71d1ae9e40c64b5d7afb5340c196134089590b69d8a51a05ee801217b90eb859236bf4b14f8d5a76"
secret_key_baseの定義場所
Rails::Application
にメソッドとして定義されている。
railties/lib/rails/application.rb
module Rails
# snip
class Application < Engine
# snip
def secret_key_base
if Rails.env.development? || Rails.env.test?
secrets.secret_key_base ||= generate_development_secret
else
validate_secret_key_base(
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
)
end
end
end
end
- 環境がdevelopmentかtestの場合
secrets.secret_key_base
が未設定なら、generate_development_secret
を実行し結果をsecrets.secret_key_base
に保存するsecrets.secret_key_base
を返す
- それ以外の場合
ENV["SECRET_KEY_BASE"]
、credentials.secret_key_base
、secrets.secret_key_base
の順番で評価してバリデーションした上で結果を返す
secrets.secret_key_baseとは
Rails::Application#secrets
が定義されてる。
railties/lib/rails/application.rb
def secrets
@secrets ||= begin
secrets = ActiveSupport::OrderedOptions.new
files = config.paths["config/secrets"].existent
files = files.reject { |path| path.end_with?(".enc") } unless config.read_encrypted_secrets
secrets.merge! Rails::Secrets.parse(files, env: Rails.env)
# Fallback to config.secret_key_base if secrets.secret_key_base isn't set
secrets.secret_key_base ||= config.secret_key_base
secrets
end
end
config/secrets.yml
を読み込む- Rails 5.1で導入されたEncrypted secretsが有効なら
config/secrets.yml.enc
を読み込む config/secrets.yml
にsecret_key_baseが未定義ならconfig
から読み込む
config/secrets.yml
はRails 4.1で導入されたようなので、それ以前はconfig/application.rb
とかに書いてたのかな?
https://guides.rubyonrails.org/4_1_release_notes.html#config-secrets-yml
generate_development_secretとは
railties/lib/rails/application.rb
def generate_development_secret
if secrets.secret_key_base.nil?
key_file = Rails.root.join("tmp/development_secret.txt")
if !File.exist?(key_file)
random_key = SecureRandom.hex(64)
FileUtils.mkdir_p(key_file.dirname)
File.binwrite(key_file, random_key)
end
secrets.secret_key_base = File.binread(key_file)
end
secrets.secret_key_base
end
secret_key_baseが未設定ならtmp/development_secret.txt
を自動生成してその内容を返すらしい。へー。
まとめ
- 開発中はsecret_key_baseが自動生成されるので未設定で良さそう
- 本番環境は環境変数、credencials、secretsなど適切な方法で設定しておく