Edited at

Rails 5.2 で ActiveSupport::MessageEncryptor::InvalidMessage

間違いがあったらご指摘ください。


何が起こった


コケるまでのところ

手許のマシンで Rails 5.2.0 を使って

$ rails new hoge

してアプリを作った。

ファイルは Git で管理しており,リモートリポジトリーに push していった。

リモートリポジトリーから本番サーバー(VPS)上に clone した。


コケるところ

本番サーバーにて。

$ rails console

は問題ない。

ところが

$ rails console -e production

だと例外

`validate_secret_key_base': Missing `secret_key_base` for 'production' environment, set this string with `rails credentials:edit` (ArgumentError)

が出る。

あー,そういえば Rails 5.1 までのときも production 環境では環境変数 SECRET_KEY_BASE が必要だったから,それに似た話か。

ともかく「rails credentials:edit をやれ」と言っているみたいなので,そうしよう。

$ sudo rails credentials:edit

すると,

No $EDITOR to open file in.

と文句が出た。どうやら EDITOR という環境変数で,使うテキストエディターを指定しておかなければならないようだ。

そこで,vim を使うことにして,

$ sudo EDITOR=vim rails credentials:edit

とやったら,今度は

ActiveSupport::MessageEncryptor::InvalidMessage

が出た。

これがさっぱり分からなかった。


原因は

Rails 5.2 が秘匿情報を扱う仕組みをよく理解していれば解決は早かったと思う。


秘匿情報を扱う仕組み

Rails には,secret_key_base のような値や,SMTP のパスワードなど,漏れてはマズい情報を取り扱う仕組みがある。

何が問題かというと,そういう情報たちも Git 管理下のファイルに書きたいのだけれど,そうするとリポジトリーが見られる人にはバレてしまう,ということ。

そこで,Rails 5.2 では,そういう情報を記述したテキストを暗号化し,その暗号化したファイルを Git で管理できるようにしている。

そしてその暗号を解くための鍵だけは Git 管理せずに取り扱う。

どうもそういうことらしい。

具体的に言うと,暗号化したあとのファイルは config/credentials.yml.enc に保存される。ファイル名で分かるとおり,YAML 形式で記述して暗号化したものだ。

鍵のほうは環境変数 RAILS_MASTER_KEY で与えるか,あるいは config/master.key ファイルで与える。

rails credentials:edit というのは,暗号化したファイルを復号して,指定のエディターで編集させ,その結果を再び暗号化して config/credentials.yml.enc に保存するためのコマンドらしい。


で,なんでエラー?

rails new すると,config/credentials.yml.encconfig/master.key も自動的に作られる。

config/master.key のほうは,.gitignore によって,Git 管理せぬよう指定されている。

よって,本番サーバー上でプロジェクトのリポジトリーを clone しても,このファイルは付いてこないわけだ。

つまり,この状態では本番サーバー上で暗号化ファイルが復号できない。だから secret_key_base の値も得られない。

と,そういうことのようだ。

そこで,rails credentials:edit を促されるわけだが,このコマンドは,鍵が存在しないとき,勝手に鍵を生成して config/master.key に保存してくれちゃったりするらしい。

ところが,新しく生成された鍵は,既存の config/credentials.yml.enc の復号には当然ながら使えない。

玄関の鍵を紛失して,鍵屋が別の鍵を持ってきても開くわけないものな。

それが

ActiveSupport::MessageEncryptor::InvalidMessage

の言わんとすることらしい。


解決

原因が分かったので,rails new した環境の config/master.key の中身をコピーして,本番サーバーの config/master.key に持ってきた。

これで本番サーバーでも production 環境で動くようになった。


参考(追記)

Rails5.2から追加された credentials.yml.enc のキホン


master.key を紛失したらどうなる?(2018-08-01 追記)

もし,鍵(master.key)を紛失してしまっていたらどうなるのか。

〔よくあるのが,新規のプロジェクトを生成したあと,リモートのリポジトリーに push し,元のファイルは削除して,改めてリモートから clone して開発を始めるような場合。〕

鍵が無かったらどうしようもない。だから絶対に無くしてはダメ。

ただ,例えば開発の初期で,credentials.yml に大したことが書かれておらず(secret_key_base 程度),捨ててもよいのであれば,再作成すればよい。

つまり,config/credentials.yml.enc をいったん削除して,

$ sudo EDITOR=vim rails credentials:edit

のようにすれば,新しく config/credentials.yml.enc が作られる。

このとき,config/master.key は,存在していなければ作られるし,存在していればそれが使われる。