Embulk+Digdagを利用して、個人情報を考慮したマスク処理を開発用DBに行う

みんなのウェディングのインフラエンジニア横山です。 今回は開発用DBのマスク処理にEmbulk+Digdagを利用し始めた話について書きます。

開発用DBのマスク処理とは

弊社では、週次で本番DBのスナップショットから開発環境用DBを作り直しています。 これにより、常に本番環境と同じテーブル定義、データ量で開発を行うことができ、以下のようなメリットがあります。

  • 本番にデプロイする前に、開発、ステージング環境で不具合を早期発見できる
  • 実際に近いデータで、本番を想定した確認ができる

ここで問題になってくるのが、ユーザの氏名やメールアドレスといった個人情報の扱いについてです。 開発用DBは本番DBのスナップショットから作成されているため、開発用DBにも本番DBの個人情報が入ってしまっています。 この状態で利用すると、以下にあげる問題が考えられます。

  • 開発中の機能による、ユーザへのメール誤配信などの事故
  • 開発用DBのみにアクセスできるユーザが本番DBのデータが閲覧可能になってしまう

この問題への対処として、テーブルデータ内の個人情報のマスク処理を行う必要があります。

マスク処理をどのように行うか

マスク処理を行うにあたり、下記3つの方法を比較・検討しました。

shell script

shell scriptでmysqlコマンドを利用して地道にクエリを記載していく方法です。

mysql -e "update users set email = CONCAT('hanakoy', id, '@example.com');"

単純ではありますが、以下の懸念点からこちらの方法は選択しませんでした。

  • 実行内容が把握しづらい
  • クエリを1つずつ実行するので完了までに時間がかかる。

AWS Data Pipeline

AWSには、「AWS Data Pipeline」という複数データソース(S3,RDS,Redhiftなど)間でのデータ移行を行うツールがあります。

データ移行での利用がメインではありますが、調査を進めていくと、任意のSQLの実行もできることがわかりました。

https://docs.aws.amazon.com/ja_jp/datapipeline/latest/DeveloperGuide/dp-object-sqlactivity.html

こちらのツールを使うと、以下のようにグラフィカルに設定を行っていくことができます。

ただ、こちらにも以下のような懸念点があり採用には至りませんでした。

  • 「AWS Data Pipeline」自体の学習コストが高い
  • 実行内容をコード管理できない。

Embulk + Digdag

EmbulkとDigdagは、どちらもTreasure Dataにより開発されているツールです。

Embulkは主にETLに利用されるツールで「AWS Data Pipeline」と同様に複数データソース間でのデータ移行に利用されています。 また、「AWS Data Pipeline」とは異なり、様々なプラグインを利用することができるので、RDSからBigQueryにデータ移行するといった、 複数クラウド間でのデータ移行にも利用することができます。

Digdagはワークフローエンジンと呼ばれるツールで、ファイルベースでワークフローを管理しスケジュール実行することができます。

どちらのツールも学習コストが低く、設定ファイルをコード管理でき、複数クエリの同時実行もDigdagで制御できるので、こちらの方法を採用しました。

方法

Embulk

今回は、embulk-input-mysqlを使い、 after_selectの項目にupdateクエリを記載することで、マスク処理を実現しようと考えました。 after_selectの項目に書かれたクエリは、データ収集後に、同じトランザクション内で実行されます。

設定ファイルは以下のようになりました。outtypeに"null"を指定することで、ログに個人情報が記載されないようにするのがポイントです。

in:
  type: mysql
  host: host
  user: user
  password: password
  database: database
  options: {serverTimezone: Asia/Tokyo}
  socket_timeout: 3600
  query: |
    SELECT * FROM users LIMIT 10;
  after_select: |
    update users set email = CONCAT('hanakoy', id, '@example.com');
out:
  type: "null"

Digdag

前述した、Embulkの設定ファイルをテーブルごとに作成して、Digdagを利用して実行順序を制御しています。

設定ファイルは以下のようになります。

+jobs:
  +job1:
    sh>: embulk run change_user_password.yml.liquid
  +job2:
    _parallel: true
    +child_job1:
      _retry: 3
      sh>: embulk run mask_users.yml.liquid
    +child_job2:
      _retry: 3
      sh>: embulk run mask_mail_data.yml.liquid
    +child_job3:
      _retry: 3
      sh>: embulk run mask_credit_data.yml.liquid
    +child_job4:
      _retry: 3
      sh>: embulk run mask_address_data.yml.liquid

こちらは、以下の順序で実行されます。

  1. job1を実行
  2. job2の子要素であるchild_job1,child_job2,child_job3,child_job4を並列実行

上記の例で記載したケースだと、job1でDBのパスワードを開発環境用のものに変更し、child_jobでDBのマスク処理を行うため、実行順を制御しておく必要がありました。 このような場合にDigdagが有効活用できることがおわかりいただけるかと思います。

実行環境

これらのジョブは、EmbulkとDigdagをインストールしたDockerコンテナ上で実行するようにしています。 設定ファイルもイメージに含めておくことで、デプロイについて考えなくても以下の二つのコマンドを入力するだけでどこでも実行できる作りになっています。 ログ管理にはAWSのCloudWatchLogsを利用しています。

docker pull イメージ名
docker run --rm --log-driver=awslogs --log-opt awslogs-region=ap-northeast-1 --log-opt awslogs-group=container/development イメージ名:latest entry_point.sh db_mask_job.dig

まとめ

EmbulkとDigdagを利用することで、とても簡単に開発用DBのマスク処理を行うことができました。 今回はafter_selectをメインに使うというトリッキーな使い方でしたが、Embulkは本来、複数データソース間のETLに利用します。 ETLに利用した事例についてはまた後日お伝えしたいと思います。