本番データを安全、簡単に利用する

こんにちは、Speee唯一の踏韻エンジニア@mncです。
ライフスタイルメディア事業でヌリカエというサービスのエンジニアをしています。

Speeeでは半期に一度SpeeeKaigiというエンジニアのお祭りを開催しています。
今回は、「本番データを安全,簡単に利用する」というテーマで話しました。

SpeeeKaigiについてはこちらを参考にしてください。

tech.speee.jp

スライド

背景

本番データを使用したテストにはいくつものメリットがあると思います。

  • ユーザー目線にたってテストができる
  • 色々なパターンのデータでテストができる
  • パフォーマンスの検証ができる

しかし本番データを利用するためには個人情報の保護が必要で、これが結構な手間だと感じていました。

作ったもの

そこでコマンド一発で指定したカラムをマスクしてダンプファイルを吐き出すmozaicというGemを作りました。

使い方

↓のようにYAML形式で「どのテーブルのどのカラムをどんなマスク方式でマスクするか」を記載します。

# tables.yml
---
user: root # credentialsはENVから読み込めるようにする予定
host: localhost
port: 3306
db: 
  name: sample_development
  rdbms: mysql
tables: 
  - name: owners
    columns: 
      - name: phone_number
        method: tel # Data Masking方式
  - name: users
    columns: 
      - name: mail
        method: email # Data Masking方式

その後、以下のようにコマンドを実行するとマスクしたダンプファイルが生成されます。

コマンド実行

$ mozaic tables.yml --path sample

吐き出されたダンプファイル

# テーブル定義のdumpは省略

INSERT INTO admin_users (id, sei, mei, email, tel, password_digest, status, created_at, updated_at) VALUES ('1', '###', '##', 'cfcd208495d565ef66e7dff9f98764da@example.com', '08000000000', '', '0', '2017-08-01 14:00:08 UTC', '2017-08-01 14:00:08 UTC'), ('2', '###', '##', 'c4ca4238a0b923820dcc509a6f75849b@example.com', '03-1000-0000', '', '0', '2017-08-01 14:00:08 UTC', '2017-08-01 14:00:08 UTC'), ('3', '#####', '####', 'c81e728d9d4c2f636f067f89cc14862c@example.com', '050-2000-0000', '', '0', '2017-08-01 14:00:08 UTC', '2017-08-01 14:00:08 UTC'), ('4', '###', '###', 'eccbc87e4b5ce2fe28308fd9f2a7baf3@example.com', '+813000000000', '', '0', '2017-08-01 14:00:08 UTC', '2017-08-01 14:00:08 UTC'), ('5', '###', '##', 'a87ff679a2f3e71d9181a67b7542122c@example.com', '0354000000', '', '0', '2017-08-01 14:00:08 UTC', '2017-08-01 14:00:08 UTC'), ('6', '####', '####', 'e4da3b7fbbce2345d7772b0674a318d5@example.com', '090-5000-0000', '', '0', '2017-08-01 14:00:08 UTC', '2017-08-01 14:00:08 UTC');

INSERT INTO owners (id, sei, mei, sei_kana, mei_kana, tel, email, address, created_at, updated_at) VALUES ('1', '######', '######', '###', '##', '08000000000', 'cfcd208495d565ef66e7dff9f98764da@example.com', '', '', ''), ('2', '##', '####', '###', '####', '03-1000-0000', 'c4ca4238a0b923820dcc509a6f75849b@example.com', '', '', ''), ('3', '######', '######', '##', '###', '+812000000000', 'c81e728d9d4c2f636f067f89cc14862c@example.com', '', '', ''), ('4', '#####', '######', '##', '###', '090-3000-0000', 'eccbc87e4b5ce2fe28308fd9f2a7baf3@example.com', '', '', '');

このGemの特徴

カラムごとにData Masking方式を切り替えられること

デフォルトで以下のData Masking方式が用意されています。
これにより、より本番のデータに近い形式でマスクできます。
また、DBのUnique制約も回避できます。

方式 マスク方法
tel 電話番号の体裁を保ったままマスクする
email メールアドレスの体裁を保ったままマスクする
shuffle 各レコードの順番を入れ替える
blackout 任意の文字、数字で埋める

適切なData Masking方式がなかったら、ユーザーが自分でRubyのマスク処理を行えること

maskメソッドとコンストラクタを持つRubyのクラスを指定ディレクトリに格納し、YAMLの設定ファイルにクラス名を小文字で記載すると独自のマスク処理を行えるようにしました。

module Mozaic::MaskMethod::Plugin
  class SampleMask
    def initialize(records, column_name); ;end
    
    def mask; ;end
  end
end  

まとめ

基礎の部分の実装はできたので、今後は以下の対応を行いOSS化しようと思います。

  • クレデンシャルをENVから読み込めるようにする
  • 大規模データでも利用できるようにする
  • 独自のマスク処理をPluginで追加できるようにする
  • PostgreSQL対応

反省

今回初参加だったためSpeeeKaigiの雰囲気がわからずお硬いテーマで話してしまいました。
みんな遊び心たっぷりの発表で非常に楽しかったため、次回は僕が大好きなHipHopとラップをテーマに韻を踏みながら発表しようと思います。