patorashのブログ

方向性はまだない

Rails 6のCredentials方式をRails 5.2にバックポートした

私が担当している製品の機密情報の管理は、Rails 5.1で導入されたEncrypted Secrets(secrets.yml.encを使う方式)を使っていて、5.2になって導入されたCredentials方式の導入は見送っていました。

理由は、5.2のCredentials方式だと、各環境毎の設定が行えなかったからです。そのため、5.2のリリース後にはCredentialsを複数の環境で扱えるようにするためのgemがいくつか出てきました。しかし、そこまでしてCredentialsに移行しても、ある意味レールから外れたカスタマイズをすることになりますし、Encrypted Secretsが非推奨になったわけではなかったので、Encrypted Secretsを使い続けていました。

現在もまだRails 5.2系を使っているのですが、これを6系にバージョンアップするために引っかかりそうなところを調査していたところ、Rails 6からはCredentials方式を後方互換性を保ったまま、各環境で使えるようになったという記事をRails 6エンジニア養成読本で読みました。

これを使えるようにしたいのですが、いきなり6にアップグレードすることは難しいです。

そこで、まずこの機能を先に取り込めるかどうかを検証しようと思いました。

バックポート用のコードを発見

調べ始めてちょっとしたら、gistで希望通りのコードと思われるものが公開されていました。

Backport Rails 6 per-environment credentials · GitHub

これを検証したところ、Rails 6のCredentialsと同様に各環境用のcredentials.yml.encとmaster.keyが作られました。

導入

導入に関しては、上記のgistを参考にしてください。

各環境のCredentialsを作成する

Rails 6のCredentialsの作成と同様の手順で行えます。下記のコマンドを実行すると、config/credentials/staging.yml.encconfig/credentials/staging.keyが生成された後、VSCodeでstaging用のCredentialsの設定ファイルが開きます。

env EDITOR="code --wait" bin/rails credentials:edit --environment=staging

適当に入力後に保存して、そのファイルのタブを閉じると、設定完了です。簡単。

各環境のCredentialsを見る

Encrypted Secretsの頃は設定項目を見るだけのコマンドがなかったので、わざわざ編集モードで開く必要があったのですが(変更なしでも変更と見なされるのでgitで戻す必要があった)、Credentialsならば、閲覧用のコマンドがあります。便利!

bin/rails credentials:show --environment=staging

Credentialsに移行するために行なった作業

ざっくりとした手順は、以下の通りです。

  1. secrets.yml.keyをコピーしてmaster.keyを作る。
  2. secrets.yml.encから各環境用に値をコピーする。
  3. Rails.application.secretsRails.application.credentialsに一斉置換する。
  4. config/environments/production.rbをはじめとする全ての環境でEncrypted Secretsを使う設定を削除、RAILS_MASTER_KEYを必須とする設定を行う
  5. 開発環境で動作検証を行う
  6. stagingの環境変数RAILS_MASTER_KEYの値をconfig/credentials/staging.keyの値に変更する
  7. stagingにデプロイして動作検証を行う
  8. 問題ないことを確認後、secrets.yml, secrets.yml.enc, secrets.yml.keyを削除する。

master.keyを作る

master.keyには、本番環境で設定されている環境変数RAILS_MASTER_KEYと同じ値を設定します。これはsecrets.yml.keyと同様のはずですので、コピーしてしまいます。

cp config/secrets.yml.key config/master.key

また、忘れずに.gitignoreにmaster.keyを追加しておきましょう。

/config/master.key

各環境用に機密情報をコピーする

以下のコマンドでEncrypted Secretsを表示します。

env EDITOR="code --wait" bin/rails secrets:edit

Encrypted Secretsの頃は、yamlのrootに環境名を設定する必要がありました。

production:
  aws:
    access_key: foo
    access_secret_key: bar

staging:
  aws:
    access_key: foo_staging
    access_secret_key: bar_staging

これを、各環境のCredentialsにコピーしていきます。

production環境

まず、production環境です。以下のコマンドを実行すると、config/credentials.yml.encが生成され、編集モードで開きます。

env EDITOR="code --wait" bin/rails credentials:edit

以下のように設定し、保存します。

aws:
  access_key: foo
  access_secret_key: bar
staging環境

次に、staging環境です。以下のコマンドを実行すると、config/credentials/staging.yml.encconfig.credentials/staging.keyが生成され、編集モードで開きます。

env EDITOR="code --wait" bin/rails credentials:edit --environment=staging

以下のように設定し、保存します。

aws:
  access_key: foo_staging
  access_secret_key: bar_staging

こんな感じで環境の数だけ作っていきます。

development, test環境

secrets.ymlも削除したいため、development, test用のCredentialsも作成しました。 secrets.ymlに設定していた内容をコピーします。

env EDITOR="code --wait" bin/rails credentials:edit --environment=development

test環境も同様に行いました。

機密情報の参照先を一斉置換する

Credentialsは指定方法がRails.application.credentialsなので、Rails.application.secretsRails.application.credentialsに一斉置換します。

各環境でEncryped Secretsを使う設定を削除

config/environments/production.rbなど、Encrypted Secretsを使っていた環境で、以下の行を削除します。

# Attempt to read encrypted secrets from `config/secrets.yml.enc`.
# Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
# `config/secrets.yml.key`.
config.read_encrypted_secrets = true

そして、環境変数RAILS_MASTER_KEY、又はmaster.keyに該当するものを必須とする設定を行います。

# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
config.require_master_key = true

開発環境で動作検証を行う

ここまでできれば、設定が間違っていないか動作検証を行います。

bin/rails s

アプリが起動することと、ある程度動作することを確認します。

staging環境のRAILS_MASTER_KEYを変更する

先に、staging環境の環境変数RAILS_MASTER_KEYを、config/credentials/staging.keyの値に変更します。

うちではHerokuを使っているので、この設定を先にせずにコードをデプロイして検証しようとしたところ、RAILS_MASTER_KEYの値が異なるためCredentialsが解読できずにデプロイが失敗しました。忘れずにデプロイ前に変更しましょう。

stagingにデプロイして動作検証を行う

ここまでできれば、stagingにデプロイできていると思いますので、動作検証をします。

Encrypted Secretsに関するファイルの削除

問題ないことを確認後、secrets.yml, secrets.yml.enc, secrets.yml.keyを削除しましょう。

これで、あとは本番環境にデプロイすれば大丈夫だと思います。

と思いきや…

落とし穴(RAILS_MASTER_KEYがなくてCIがコケた)

secrets.ymlを削除したことで、CIでコケていました…。うちではCircleCIを使っているので、CircleCIにて、環境変数RAILS_MASTER_KEYを作ってconfig/credentials/test.keyの値を設定したところ、テストも無事に通りました。

忘れずにCIにもRAILS_MASTER_KEYの設定を!!