41
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RDSスナップショットを、テスト用にマスクする、CodeBuildとdbtestdataで

Last updated at Posted at 2019-08-04

本番RDSスナップショットをそのままテスト用に使うわけにいかない。個人情報とか業務上の機密とか。マスクします。みなさんどうやってるんですかね。

全体像

こんな流れで作ります。

  1. create RDS Instance
  2. Data masking
  3. RDS create snapshot
  4. RDS instance shutdown

この記事では 2. のところを扱います。ほかは手作業。そのうちawscliとCodeBuildで自動化する。

スクリーンショット 2019-06-24 19.00.07 (1).png

マスク設定ファイルをつくるのに必要な情報を用意する

  • information_schema.tables, columnsを漁る
  • テーブルそのものの要否をふりわける
  • 必要なテーブルについて、マスクすべきカラムを選別する
  • カラムごとに、どんなデータパターンでマスクするか決める

マスク設定ファイルをつくる

マスクツールは dbtestdata を使います。dbtestdata用のマスク設定ファイルを作ります。dbtestdataがMySQLしか対応してないので、MySQLかAurora(MySQL互換)にしか使えないのがツラい。

DBマイグレーションを管理しているgitリポジトリに、 dbmask/dbtestdata.update.${TABLE_NAME}.conf と作っていくことにします。テーブルごとに1ファイル作ります。このように。

package sample;

use strict;
use warnings;
use data::VariableDataGenerator;
use sql::VariableSQLGenerator;
use utf8;

return {
    name => __PACKAGE__,
    update => {
        users => {
            primary => "id",
            clazz => {
                name => RANDOM_JA_NAME_KAN,
                email => RANDOM_EMAIL,
                address => RANDOM_JA_PREF,
                tel => RANDOM_JA_TEL,
            }
        }
    }
};

カラムごとに、どのようにマスクするかをチクチク書いていきます。マスク不要なカラムは記載不要です。なにがどうなってるのかは、 GitHub - dino-tools/dbtestdata: database testdata generator を漁ってください。

DBマイグレのgitリポジトリに入れておきたいのは、DBマイグレによるスキーマ変更と同調して、マスク設定もアップデートしていきたいからです。テーブルごとにしたいのは、gitでコンフリクトを少なくしたいのと、CodeBuildで並列実行させたいからです。

RDSインスタンスを立てる

RDSスナップショットから、RDSインスタンスを立てます。本番環境とは別のVPCにするのが事故防止のためにも良いでしょう。CodeBuildから接続できるよう、RDSインスタンス側のセキュリティグループを調整しておきます。

Auroraなら、たとえばこのように。

CodeBuildビルドプロジェクトをつくる

buildspec.ymlはこんな。 envの部分は、よしなに置き換えて使ってください。RDSに接続するので、このCodeBuildはVPC内で動かします。Dockerイメージは、惰性で python:3.8-buster を利用してます。wgetとか要るのか、、、なんか要らない気がしてきた。

version: 0.2

env:
  variables:
    RDS_ENDPOINT: "hoge"
    RDS_USER: "hoge"
    CONF_FILE: "hoge"
    PERL5LIB: "."
  parameter-store:
    RDS_PASSWD: /CodeBuild/RDS_PASSWD

phases:
  install:
    commands:
      - env | sort
      - echo "dash dash/sh boolean false" | debconf-set-selections
      - DEBIAN_FRONTEND=noninteractive dpkg-reconfigure dash
      - apt update
      - apt install -y wget unzip jq mariadb-client libdbi-perl libdbd-mariadb-perl
      - git clone https://github.com/dino-tools/dbtestdata.git /usr/local/dbtestdata
  build:
    commands:
      - |
        cd /usr/local/dbtestdata
        echo ${RDS_PASSWD} \
        | perl dbtestdata.pl update \
            --hostname=${RDS_ENDPOINT} \
            --database=production_asp \
            --username=${RDS_USER} \
            --password \
            --conf=${CODEBUILD_SRC_DIR}/dbmask/${CONF_FILE}

ちなみにCodeBuildは実行時間が8時間までの制限があるので、クソデカいテーブルには制限時間オーバーで駄目になります。ラッキーなことに、8時間以内に終わるテーブルだけだったので、今後そのうち考えます。たぶんFargateとかでやると思います。いやどうだろう、わからない。

マスクする

こちらもCodeBuildにやらせます。テーブル数が多い場合は、同時実行数を絞ったり、RDBのグレードを上げたりの工夫が必要になるかと思います。両方で同じバージョンを利用するよう、 --source-version "${CODEBUILD_SOURCE_VERSION}" を付けてます。

phases:
  install:
    commands:
      - env | sort
      - echo "dash dash/sh boolean false" | debconf-set-selections
      - DEBIAN_FRONTEND=noninteractive dpkg-reconfigure dash
      - apt update
      - apt install -y wget unzip jq
      - pip install --upgrade --quiet pip
      - pip install --quiet awscli
      - aws --version
  build:
    commands:
      - |
        cd ${CODEBUILD_SRC_DIR}/dbmask;
        ls dbtestdata.update.*.conf \
        | sort \
        | while read CONF_FILE; do
            aws codebuild start-build \
                --source-version "${CODEBUILD_SOURCE_VERSION}" \
                --project-name dbtestdata-runner \
                --environment-variables-override name="CONF_FILE",value="${CONF_FILE}",type="PLAINTEXT"
        done

要らんテーブルは空にする

テストの要件などから、空でいいテーブルが多々あります。dbtestdataにもdeleteする機能はありますが使いません。外部キー制約の on delete が動いてしまったりで厄介だったので、mysqlコマンドでtruncateすることにしました。 --init-command="SET SESSION FOREIGN_KEY_CHECKS=0;" を付けたかった。 ${CODEBUILD_SRC_DIR}/dbmask/delete.conf は、1行1テーブル名の、ただのテキストファイルです。

version: 0.2

phases:
  install:
    commands:
      - env | sort
      - echo "dash dash/sh boolean false" | debconf-set-selections
      - DEBIAN_FRONTEND=noninteractive dpkg-reconfigure dash
      - apt update
      - apt install -y wget unzip jq mariadb-client
  build:
    commands:
      - |
        cat ${CODEBUILD_SRC_DIR}/dbmask/dbtestdata.delete.conf \
        | sort -u \
        | while read TABLE_NAME; do
            mysql -u ${RDS_USER} -p${RDS_PASS} -h ${RDS_HOST} production_asp \
                --init-command="SET SESSION FOREIGN_KEY_CHECKS=0;" \
                -e "truncate table ${TABLE_NAME};"
        done

RDSスナップショットを作って、開発アカウントに共有し、RDSを立てる

他のアカウントに共有するにはこのように。

aws rds modify-db-snapshot-attribute \ 
    --db-snapshot-identifier masked-snapshot \ 
    --attribute-name restore \ 
    --values-to-add '["xxxxxxxxxxxxxxxxx"]'

DBマイグレーションに並走する

ほっとくとマスク定義が古くなっていきます。テーブルの追加削除もあります。カラムの追加削除もあります。アプリケーションチームと、DBマイグレの都度、マスク定義ファイルのアップデートもしていくよう、ルール作りを忘れずに。

41
30
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
41
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?