Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduce AR::Encryption

Takumi Shotoku
September 02, 2021

Introduce AR::Encryption

Takumi Shotoku

September 02, 2021
Tweet

More Decks by Takumi Shotoku

Other Decks in Technology

Transcript

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  6. ユースケースの紹介
    8

    View full-size slide

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

    View full-size slide

  8. 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
    #=> ## updated_at: Fri, 09 Jul 2021 06:39:53.651449000 UTC +00:00>
    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
    #=> ## updated_at: Fri, 09 Jul 2021 06:39:54.587980000 UTC +00:00>
    10

    View full-size slide

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

    View full-size slide

  10. ユニーク制約をつける
    12

    View full-size slide

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

    View full-size slide

  12. 既存のカラムを暗号化する 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  16. バックポート 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

    View full-size slide