Rails
Vault
Hashicorp

vault-railsを利用してカラムの暗号化・復号化を行う

はじめに

HashiCorpからVaultとRailsを連携させるためのgemvault-railsが提供されていたのでサンプルアプリを作成して動作確認してみました。

HashiCorp Vaultとは?

HashiCorpが提供している機密情報の管理ツールです。

vault-railsとは?

HashiCorpから提供されているVaultとRailsを連携させるためのgemです。
データの暗号化・復号化をvault-railsが透過的に処理してくれるため、利用するデータの暗号化・復号化をあまり意識せずにコードを記述することができます。
データの暗号化・復号化に利用するKeyがVaultに格納され、暗号化したデータ自体はRailsのDBに格納されるようです。

参考

公式サイト : Vault by HashiCorp
Gihub : hashicorp/vault-rails

バージョン

Vault

v0.8.0

Rails

rails(5.1.3)
vault (0.10.1)
vault-rails (0.3.2)

Vault

起動

Vaultを起動して「127.0.0.1:8200」でHTTPリクエストを受信できる状態にしておく。
(unsealも忘れずに)

参考:HashiCorp Vault で HTTP API を利用する - Qiita

補足:
Vaultがunsealされてないとデータの読み込みが出来ず、以下のようなエラーが発生します。

The Vault server at `http://127.0.0.1:8200' responded with a 503.
Any additional information the server supplied is shown below:

  * Vault is sealed

mount

vault-railsではsecret backendとしてtransitを利用するので、マウントしておく。

$ vault mount transit
Successfully mounted 'transit' at 'transit'!

補足:
transitのマウントを忘れるとRailsでデータを読み書きする際に以下のようなエラーが発生します。

The Vault server at `http://127.0.0.1:8200' responded with a 404. 
Any additional information the server supplied is shown below: 
* no handler for route 'transit/encrypt/my_app_users_ssn//' 
* Please refer to the documentation for help.

Rails

hashicorp/vault-railsのREADMEを参考にアプリを準備していきます。

Gemfile

Gemfile
gem "vault-rails", "~> 0.1", require: false

initializer

READMEのサンプルはProduction環境だけで動作させる内容になっていたので、develop環境でも利用できるようにvault.enabledを書き換えました。vault.addressvault.tokenは環境変数でも指定できるようですが、今回は動作確認なのでベタ書きしました。

config/initializers/vault.rb
require "vault/rails"

Vault::Rails.configure do |vault|
  # Use Vault in transit mode for encrypting and decrypting data. If
  # disabled, vault-rails will encrypt data in-memory using a similar
  # algorithm to Vault. The in-memory store uses a predictable encryption
  # which is great for development and test, but should _never_ be used in
  # production.
  #vault.enabled = Rails.env.production?
  vault.enabled = true

  # The name of the application. All encrypted keys in Vault will be
  # prefixed with this application name. If you change the name of the
  # application, you will need to migrate the encrypted data to the new
  # key namespace.
  vault.application = "my_app"

  # The address of the Vault server. Default: ENV["VAULT_ADDR"].
  vault.address = "http://127.0.0.1:8200"

  # The token to communicate with the Vault server.
  # Default: ENV["VAULT_TOKEN"].
  vault.token = "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx"
end

Model

READMEではpersonでしたが、userでモデルを作成しました。
暗号化の対象はREADMEと同じくssnとします。
暗号化したデータを格納するssn_encryptedも合わせて用意します。

$ rails g scaffold user name:string ssn:string ssn_encrypted:string
$ rake db:migrate
app/models/user.rb
class User < ApplicationRecord
  include Vault::EncryptedModel
  vault_attribute :ssn
end

データの暗号化・復号化

http://localhost:3000/users/new にアクセスして、scaffoldで自動生成されたフォームからデータを入力します。ssn_encryptedには自動的にデータが挿入されるため、空のままにします。

vault-rails3.png

データの保存に成功するとssn_encryptedに暗号化したデータが保存されます。

vault-rails4.png

画面を見た時に「あれ?入力した値がssnに表示されてるぞ?暗号化されてないんじゃない?」と思いますが、テーブルをselectするとssnカラムに実データが保存されてないことがわかります。

rails-vault5.png

user.ssnを呼び出す際にrails-vaultが自動的にデータを復号化してくれていたようです。
データの暗号化・復号化をvault-railsが透過的に処理してくれるのは便利ですね。