Slide 1

Slide 1 text

Introduce AR::Encryption Omotesando.rb #66 2021/09/02 1

Slide 2

Slide 2 text

自己紹介 • 名前: 神速 • 会社: メドピア株式会社 • 所属: CTO室SRE • GitHub: @sinsoku (画像右上) • Twitter: @sinsoku_listy (画像右下) 2

Slide 3

Slide 3 text

AR::Encryption の使い方1 1 https://edgeguides.rubyonrails.org/activerecordencryption.html 3

Slide 4

Slide 4 text

4

Slide 5

Slide 5 text

5

Slide 6

Slide 6 text

属性にアクセスすると平文を返す 復号は自動的に行われる。 Article.last.title # => "Encrypt it all!" 6

Slide 7

Slide 7 text

基本的な挙動 1. 暗号化の種を用意 2. モデルに encrypts :attr_name を定義 3. SQLの値は自動的に暗号化 serialize と同じ挙動だと考えると分かりやすい。 7

Slide 8

Slide 8 text

ユースケースの紹介 8

Slide 9

Slide 9 text

暗号化したカラムでの find 9

Slide 10

Slide 10 text

deterministic: true は同じ文字になる Author.create(email: '[email protected]') # TRANSACTION (0.0ms) begin transaction # Author Create (1.1ms) INSERT INTO "authors" ("email", "created_at", "updated_at") VALUES (?, ?, ?) \ # [["email", "{\"p\":\"zicjhoOToWeYJ8SLsHr0\",\"h\":{\"iv\":\"er70ewKN9j8AAd1m\",\"at\":\"BuSV3TSxAZkM8t/uD0UvtA==\"}}"], \ # ["created_at", "2021-07-09 06:39:53.651449"], ["updated_at", "2021-07-09 06:39:53.651449"]] # TRANSACTION (0.9ms) commit transaction #=> # Author.create(email: '[email protected]') # TRANSACTION (0.0ms) begin transaction # Author Create (0.4ms) INSERT INTO "authors" ("email", "created_at", "updated_at") VALUES (?, ?, ?) \ # [["email", "{\"p\":\"zicjhoOToWeYJ8SLsHr0\",\"h\":{\"iv\":\"er70ewKN9j8AAd1m\",\"at\":\"BuSV3TSxAZkM8t/uD0UvtA==\"}}"], \ # ["created_at", "2021-07-09 06:39:54.587980"], ["updated_at", "2021-07-09 06:39:54.587980"]] # TRANSACTION (1.1ms) commit transaction #=> # 10

Slide 11

Slide 11 text

ユニークバリデーションをつける 11

Slide 12

Slide 12 text

ユニーク制約をつける 12

Slide 13

Slide 13 text

既存のカラムを暗号化する 暗号化していない文字列も扱えるように設定を変更する。 config.active_record.encryption.support_unencrypted_data = true モデルに encrypts を定義した後に encrypt メソッドを呼ぶ。 Article.find_each(&:encrypt) 13

Slide 14

Slide 14 text

既存のカラムを暗号化する 2 レコードが多い場合は upsert_all を使う方が良さそう。 type = Article.attribute_types["title"] Article.find_in_batches do |group| attributes = group.pluck(:id, :title).map do |id, title| { id: id, title: type.serialize(title) } end Article.upsert_all(attributes, unique_by: :id) end 14

Slide 15

Slide 15 text

non-deterministic -> deterministic サービス運用が始まってから「やっぱりfindしたい」となった場 合の対応方法。 class Article < ApplicationRecord encrypts :title, deterministic: true, previous: { deterministic: false } end 15

Slide 16

Slide 16 text

16

Slide 17

Slide 17 text

Viewでの復号を禁止する # TODO: ௐ͕ࠪؒʹ߹Θͳ͔ͬͨ 17

Slide 18

Slide 18 text

バックポート 1 関連するコードをRailsのリポジトリからコピペする。 $ mkdir lib/active_record $ cp -r ~/ghq/github.com/rails/rails/activerecord/lib/active_record/encryption* \ lib/active_record 18

Slide 19

Slide 19 text

バックポート 2 # config/application.rb require 'active_record/encryption' ActiveRecord::Railtie.initializer "active_record_encryption.configuration" do |app| # config.active_record.encryption ૬౰ͷม਺ config_encryption = ActiveSupport::OrderedOptions.new ActiveRecord::Encryption.configure \ primary_key: app.credentials.dig(:active_record_encryption, :primary_key), deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key), key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt), **config_encryption # ҎԼུ end 19