0
0

Rails6+attr_encryptedの環境をRails7にアップデートするときにやったこと

Last updated at Posted at 2023-07-29

はじめに

Rails6.0からRails7.0(正確には7.0.3)にアップグレードするにあたり、データの暗号化処理をを attr_encrypted からRails7の標準機能に置き換えた話を以下にまとめます。

Rails7にアップブレードする際に発生した問題点

アップグレードの際に以下の諸問題が発生しました。

graphqlのpreloader
https://michiomochi.com/blog/rails-v6047-to-v7023

sessionが見つからない問題
https://ta-watanabe.hatenablog.com/entry/2022/03/14/140128
https://blog.dnpp.org/api_only_rails7_with_devise

Enumerable.sumがRails7から非推奨
https://www.bigbinary.com/blog/rails-7-deprecates-enumerable-sum-and-array-sum

graphql-fragment-cacheが最新だと動かない問題
https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/

strip_tagsの仕様変更に伴う修正
https://techracho.bpsinc.jp/hachi8833/2022_06_06/118470#1-1

stylesheetのmedia属性
https://qiita.com/SoarTec-lab/items/9832bb89402e452b20bb#railsapplicationconfigaction_viewapply_stylesheet_media_default--false

これらは大体対処法がありましたが、一点非常に難儀したのは attr_encrypted の内容とRails7の標準機能がバッティングしたことです。

attr_ecnryptedとは

要約すると、指定したカラムに対してデータを入力する際に、自動的に暗号化して保存、取り出すときは暗号をデコードしてくれます。
例として、user モデルに email の情報を暗号化して保存するとします。
userモデルには以下のように定義します。

  t.string "encrypted_email", null: true

user.rbには

attr_encrypted :email, key: your_encrypted_key, algorithm: 'aes-256-cbc', mode: :single_iv_and_salt

を設定します。(オプション等はマニュアル参照ですが、既に非推奨)
上記によって、user.email を参照すると、実態は user.encrypted_email にある暗号化されたデータを透過的に扱うことが出来ます。

Rails7での標準暗号化機能

Railsはver7から attr_encrypted で提供している物と大体同等のカラム暗号化機能を提供するようになりました。問題は attr_encrypted で提供しているメソッドと同名のメソッドが含まれるようになり、Rails7上で attr_encrypted が提供するメソッドを実行するとエラーが発生するようになります。
そこで、暫定的に以下のブランチに切り替えます。
https://github.com/InvestIMBY/attr_encrypted/tree/rails-7-0-support

gem "attr_encrypted", github: 'InvestIMBY/attr_encrypted', branch: 'ruby-3-rails-7-0-support'

また、今まで encrypted というメソッドで暗号化していた物がRails7の標準機能とバッティングしてしまったため、以下のようにリネームします。

- encrypted_email = User.encrypt(:email, email)
+ encrypted_email = User.attr_encrypted_encrypt(:email, email)

元々 attr_encrypted 自体更新が停滞していたこともあり、この機会にRails7の標準暗号化機能に移行することにしました。
移行を行った事例について調べてみると、1件該当しました。
https://pagertree.com/blog/migrate-attr_encrypted-to-rails-7-active-record-encrypts

概ねこの内容に従いますが、こちらの環境ではスキーマ管理を Ridgepole で行っているので、細かい点では読み替えが必要です。

移行手順

以下の3つの段階に分けて行います。

  1. 既存の encrypted_email の設定を oldemail のメソッドで取得するように変更
  2. 標準encrypt用のemailカラムの email を追加
  3. バッチで oldemail から email にデータコピー

3.で行うバッチファイルの作成とテストまでは事前に行っておきます。

暗号化キーの作成

bin/rails db:encryption:init

によって以下の様なキーが出力されます

active_record_encryption:
  primary_key: EGY8WhulUOXixybod7ZWwMIL68R9o5kC
  deterministic_key: aPA5XyALhf75NNnMzaspW7akTfZp0lPY
  key_derivation_salt: xEY0dt6TZcAMg52K7O84wYzkjvbA62Hz
EDITOR=vim bin/rails credentials:edit

などでcredentialファイルを編集して追記しておきます。

新暗号化用カラム

  email           :text(65535)      not null #今回追加した物
  encrypted_email :string(255)

今までは encrypted_email によって透過的に email を扱っていましたが、新暗号化方式からそのまま email カラムを扱います。
同時に旧暗号化方式を以下のように修正します。

-  attr_encrypted :email, key: your_attr_encrypted_key, algorithm: 'aes-256-cbc', mode: :single_iv_and_salt
+  attr_encrypted :oldemail, key: your_attr_encrypted_key, algorithm: 'aes-256-cbc', mode: :single_iv_and_salt, attribute: 'encrypted_email'
+  encrypts :email, deterministic: true

上記の設定により、user.oldemail が旧暗号化方式を指すようになります。

データ移行バッチ

抜粋すると以下のような形になります。

      User.all.find_each do |user|
        if user.email.blank?
          user.email = user.oldemail
          user.save!
        end
      end

サービスをメンテインの後に、暗号化処理を新方式に切り替えたコードをマージし、バッチを実行します。
emailのデータが問題なく移行済みになっていることを確認し、 attr_encrypted gemと encrypted_email カラムを削除します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0