はじめに
外部APIのキー情報やアクセストークンなどの機密情報を外部に漏らしてしまうと悪用される可能性があります。実際、外部APIにアクセスするための機密情報をオンコードで記述し、そのソースコードをGitHubに上げてしまったために、外部APIを不正利用(ただ乗り)されてしまったという事例もあります。
Railsにはそういった機密情報を暗号化し、安全に保護するCredentialsという機能があります。Credentialsを使えば、復号化キーを漏洩/盗難/紛失しない限り、機密情報を保護することができます。
本記事では、Credentialsを使った機密情報の保護について説明します。
Credentialsの基本
CredentialsはRails 5.2から導入された機能です。Railsアプリを作成したときに、暗号化ファイルとその復号化キーのセットが生成されます。
機密情報の復号化
Credentialsで登録した機密情報は暗号化してファイルに書き込まれています。このファイルを復号化するには復号化キーが必要です。復号化キーはconfig/master.key
というファイルかRAILS_MASTER_KEY
という環境変数のどちらかに存在している必要があります。
Credentialsはまずconfig/master.key
に復号化キーを探索しにいき、そこになければ次にRAILS_MASTER_KEY
を探索します。そこにも復号化キーがなければ復号化に失敗し、nil
が返却されます(例外が発生するわけではない)。
Railsアプリのデプロイ先によってはconfig/master.key
の共有ができない場合があります。そのような環境では復号化キーをRAILS_MASTER_KEY
に登録しておくことになります。
master.keyについて
復号化キーが含まれるconfig/master.key
は外部に漏らしてはいけません。.gitignore
(バージョン管理システムへのアップロードを除外するファイルを記載)には最初から記載されています。
secret_key_baseについて
Credentialsにはsecret_key_base
という機密情報が初めから登録されています。これは、Cookieの暗号化に使用される文字列です。使わないからと言って削除してしまわないようにしてください。
Credentialsの使い方
機密情報の確認
登録してある機密情報を確認するには、以下のコマンドを実行します。
$ rails credentials:show
機密情報の登録
Credentialsを使って機密情報を登録するには、以下のコマンドを実行します。Credentialsは環境変数EDITOR
に編集するアプリケーションを登録しておく必要があります。.bash_profile
に環境変数を登録するように書いておけばEDITOR=vi
は省略できます。
$ EDITOR=vi rails credentials:edit
CredentialsはYAML記法で記述します。
mail:
username: info@example.com
password: v8FmvLHB!C*mcGc8
Vimだと保存できない場合
Vim(vim
またはvi
)で機密情報を登録したのに保存されないときがあります。原因は不明ですが、編集アプリケーションをAtomやVScodeにすると保存できるようになります。
# Atomの場合
$ EDITOR="atom -w" rails credentials:edit
# VScodeの場合
$ EDITOR="code -w" rails credentials:edit
AtomやVScodeを使う場合は、引数に-w
または--wait
を指定する必要があります。
オプション | 説明 |
---|---|
-w /--wait |
編集ウィンドウが閉じられるまで、コマンドプロンプト/シェルに制御を返さない。 |
機密情報の使用
登録してある機密情報を使用するには、以下のように記述します。RubyとYAMLで書き方が異なります。Rubyの場合は以下の通りです。
# 以下のどれでも結果は同じ
password = Rails.application.credentials.mail[:password]
password = Rails.application.credentials.dig(:mail, :password)
password = Rails.application.credentials[:mail][:password]
YAMLの場合は以下の通りです。
# 以下のどれでも結果は同じ
password: <%= Rails.application.credentials.mail[:password] %>
password: <%= Rails.application.credentials.dig(:mail, :password) %>
password: <%= Rails.application.credentials[:mail][:password] %>
機密情報にエスケープ文字が含まれる場合
Google Cloud Storageのプライベートキーには\n
(改行)が含まれています。このようなエスケープ文字が含まれている機密情報を登録するには、値をダブルクオーテーション(""
)で括る必要があります。
gcs:
private_key: "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
また、呼び出す際には末尾に.dump
をつける必要があります。
key = Rails.application.credentials.dig(:gcs, :private_key).dump
key: <%= Rails.application.credentials.dig(:gcs, :private_key).dump %>
本番環境へのデプロイ
Capistranoを使ったデプロイ
復号化キーが含まれるconfig/master.key
をバージョン管理システムへアップロードすることはできません。つまり、デプロイツールにCapistranoを使っていると、本番環境にconfig/master.key
がアップロードされないことになります。Capistranoを使ったデプロイでconfig/master.key
を共有するには以下の手順を行います。
本番環境でconfig/master.key
が共有されていないとRailsアプリの起動に失敗する設定を有効にします。config/environments/production.rb
を以下のように修正します。
# 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
Capistranoのデプロイ設定config/deploy.rb
に以下を追記します。デプロイ先のshared/config/master.key
にシンボリックリンクを張ります。
set :linked_files, %w(config/master.key)
デプロイ先のshared/config/
ディレクトリにmaster.key
を作成し、復号化キーを記述します。
$ vi /path/to/shared/config/master.key
デプロイツール「Capistrano」については以下の記事を参照してください。
Herokuへのデプロイ
デプロイ先がHerokuの場合、Capistranoの設定や手動でmaster.key
を作成することができません。Herokuでは復号化キーを環境変数RAILS_MASTER_KEY
に登録します。
heroku config:set RAILS_MASTER_KEY=********************************
Multi Environment Credentials
Credentialsはもともと本番環境における機密情報を保護するための機能でした。RailsにCredentialsが追加された後でも、環境毎に機密情報を保存したい場合はdotenv-rails
というGemを使う必要がありました。
しかし、Rails 6からMulti Environment Credentialsという機能が追加され、Credentialsでも環境毎に機密情報を保存することができるようになりました。
環境毎の機密情報の確認
環境を指定して機密情報を確認するには、以下のコマンドを実行します。
$ bin/rails credentials:show -e <test|development|staging|production>
環境毎の機密情報の登録
環境を指定して機密情報を登録するには、以下のコマンドを実行します。
$ EDITOR=vi rails credentials:edit -e <test|development|staging|production>
環境毎の機密情報の使用
環境毎に登録してある機密情報の使用方法は通常のCredentialsと同じですが、Rails.env
の値によって結果が異なります。
$ rails c
# 開発環境の場合
> Rails.env = "development"
=> "development"
> Rails.application.credentials.mail[:password]
=> abc
# 本番環境の場合
> Rails.env = "production"
=> "production"
> Rails.application.credentials.mail[:password]
=> xyz
復号化キーを紛失した場合
誤ってconfig/master.key
を削除するなどして復号化キーがわからなくなってしまった場合、以下のコマンドを実行すると再作成されます。
$ rails credentials:edit
新しく作成されたconfig/master.key
では既存のconfig/credentials.yml.enc
を復号化することはできません。config/master.key
と一緒にconfig/credentials.yml.enc
も削除して再作成する必要がありますが、当然、もともと登録してあった機密情報は失われてしまうのでご注意ください。
まとめ
Credentialsによって機密情報を安全に保護できるようになりましたが、復号化キーを漏洩してしまうと意味がありません。config/master.key
の取り扱いにはくれぐれもご注意ください。
本記事を参考にして、Credentialsを使用した機密情報の保護を行っていただければと思います。