まっしろけっけ

めもてきなやーつ

Rails の Credentials で使用する yml.enc を変えたい

はじめに

Rails の Credentials の機能がどんなものなのか?は割愛しますが、デフォルトで読み込まれる yml.enc 以外を使いたい場合ってありませんか?
一般的には無いかもしれませんが自分の環境ではあったんですよ。その為に credentials で読み込まれる yml.enc がどのように決まるか?というあたりのコードを少し前に読んで理解〜となったのでメモを残す。

環境は Rails7.0

デフォルトで読み込まれる yml.enc に関して

まずは rails new した後の config 内はこんな感じ

$ ls -1 config
application.rb
boot.rb
cable.yml
credentials.yml.enc
database.yml
environment.rb
environments
importmap.rb
initializers
locales
master.key
puma.rb
routes.rb
storage.yml

# credentials.yml.enc を編集したい場合は下記のようにすればよい
$ EDITOR=vi bundle exec rails credentials:edit

# 下記で中身の確認ができる
$ bundle exec rails credentials:edit

次に environment 毎に yml.enc を分けたい場合はどうするか?というと下記のようにする

$ EDITOR=vi bundle exec rails credentials:edit --environment development
# 保存すると
Adding config/credentials/development.key to store the encryption key: xxxxxxxxx

Save this in a password manager your team can access.

If you lose the key, no one, including you, can access anything encrypted with it.

      create  config/credentials/development.key

Ignoring config/credentials/development.key so it won't end up in Git history:

      append  .gitignore

File encrypted and saved.
# production の場合は
$ EDITOR=vi bundle exec rails credentials:edit --environment production

$ ls -1 config
application.rb
boot.rb
cable.yml
credentials
credentials.yml.enc
database.yml
environment.rb
environments
importmap.rb
initializers
locales
master.key
puma.rb
routes.rb
storage.yml

$ ls -1 config/credentials
development.key
development.yml.enc
production.key
production.yml.enc

こんな感じになります。.key に関しては下記のように環境変数で指定する方が楽かなと個人的には思います。

$ RAILS_MASTER_KEY=xxxxx EDITOR=vi bundle exec rails credentials:edit --environment production

この状態だと RAILS_ENV が development/production の場合はそれぞれ config/credentials/development.yml.enc と config/credentials/production.yml.enc が読み込まれます。
では RAILS_ENV test だとどうなるかというと config/credentials.yml.enc が読み込まれます。

このようにどの yml.enc を使うか?を決めているのが下記のコード
難しいコードでは無いので読んでもらえればわかりますが config/credentials/#{Rails.env}.yml.enc が存在すればそちらを、存在しない場合は config/credentials.yml.enc を読み込むという感じになっています。

github.com

基本的な挙動はこれでおしまいです。

独自のルールで yml.enc を指定したい

ここからが本題
上記で基本的に読み込まれる yml.enc に関しては理解できましたが独自のルールで読み込まれる yml.enc を決めたいとなった場合にどうするか?というと下記のようにします。

# config/application.rb などで

module Testapp
  class Application < Rails::Application
    config.credentials.content_path = Rails.root.join("config/credentials/#{ENV.fetch('CREDENTIALS_FILE')}.yml.enc")
    # key を RAILS_MASTER_KEY で指定せず file として読み込ませたい場合
    config.credentials.key_path = Rails.root.join("config/credentials/#{ENV.fetch('CREDENTIALS_FILE')}.key")
  end
end

もちろん file name を決める部分は環境変数である必要はなく独自のロジックを書いて決定しても問題ありません。

編集する場合は下記のようにします。

$ RAILS_MASTER_KEY=xxxxx EDITOR=vi bundle exec rails credentials:edit --environment hoge

ただし上記の場合若干罠があり file 名を dev や prod にしたい場合できないという問題が発生します。
dev にすると config/credentials/development.yml.enc が prod にすると config/credentials/production.yml.enc が編集されます。

これはなぜかというと下記のようなコードになっているからです。
environment で渡した値が env として渡ってくるのですが config/environments/ 内に該当の file が存在しない場合 production/development/test に前方一致で正規表現をかけられ match したものが採用されます。そのため dev を指定しても config/credentials/development.yml.enc が編集されるということになります。

github.com


ではこういう場合はどうするかというと下記のコマンドで編集が可能です。

$ RAILS_MASTER_KEY=xxxxxx EDITOR=vi  bundle exec rails encrypted:edit config/credentials/dev.yml.enc

最後に

config.credentials.content_path をいじったりしないでそのまま使えるのが一番ですよ