【Rails】Credentialsを使用した機密情報の保護

はじめに

外部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を使用した機密情報の保護を行っていただければと思います。

関連記事

【Rails】Paranoiaを使用した論理削除(ソフトデリート)
# はじめに Paranoiaは、Railsアプリケーションで論理削除(ソフトデリート)を実現するためのGemです。 論理削除は、データベースのレコードを物理的に削除するのではなく、削除フラグを設定することで「削除済み」とみなす方法です。こ [...]
2024年7月20日 21:33
【Rails】activerecord-multi-tenantを使用したマルチテナントアプリケーションの作成
# はじめに マルチテナントアプリケーションでは、複数の顧客(テナント)が同じアプリケーションを利用するため、データの分離が必要です。 activerecord-multi-tenantは、このようなマルチテナント環境をサポートするための便 [...]
2024年7月18日 16:50
【Rails】RubyとRailsにおけるattr_reader, attr_writer, attr_accessorの概念と使用方法
# はじめに RubyとRailsの開発において、`attr_reader`,`attr_writer`,`attr_accessor`は非常に便利なメソッドです。これらは、クラス内でインスタンス変数に対するゲッターおよびセッターメソッドを簡単に [...]
2024年7月17日 18:11
【Rails】RubyとRailsにおけるyieldの概念と使用方法
# はじめに RubyとRailsにおける`yield`は、メソッドやテンプレートの中で動的にコードブロックを実行する能力を提供し、これによってコードの再利用性と拡張性が大幅に向上します。本記事では、RubyとRailsにおける`yield`の概 [...]
2024年7月17日 13:15
【Rails】AASMを使用してオブジェクトの状態遷移を効率的に管理
# はじめに Railsアプリケーションにおいて、オブジェクトの状態管理は重要な課題の一つです。AASM (Acts As State Machine) gemは、複雑な状態遷移を効率的に管理します。本記事では、AASMの基本的な使い方を解説して [...]
2024年7月16日 18:00
【Rails】RSpec + Swagger + rswagでアプリケーションのAPIをテストおよびドキュメント化する方法
# はじめに Railsアプリケーションの開発において、APIのテストとドキュメント化は重要な要素です。 RSpecはテストフレームワークとして広く利用されており、SwaggerはAPIの設計とドキュメント化を支援します。これらを統合するr [...]
2024年7月16日 14:27
【Rails】mailcatcherを使用して開発環境でメール送信をテストする方法
# はじめに mailcatcherは、開発環境でのメール送信をキャプチャするためのツールです。ローカルで送信されたメールをブラウザ上で簡単に確認できるようにします。mailcatcherをRailsアプリケーションで使用する方法について説明しま [...]
2024年7月15日 16:37
【Rails】impressionistを使用してページビューやクリック数を追跡する方法
# はじめに impressionist Gemを使用してRailsアプリケーションでページビューやクリック数を追跡する方法について説明します。 # 実装方法 ## impressionist Gemのインストール まず、impre [...]
2024年7月15日 14:18