本番RDSスナップショットをそのままテスト用に使うわけにいかない。個人情報とか業務上の機密とか。マスクします。みなさんどうやってるんですかね。
全体像
こんな流れで作ります。
- create RDS Instance
- Data masking
- RDS create snapshot
- RDS instance shutdown
この記事では 2. のところを扱います。ほかは手作業。そのうちawscliとCodeBuildで自動化する。
マスク設定ファイルをつくるのに必要な情報を用意する
- 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マイグレの都度、マスク定義ファイルのアップデートもしていくよう、ルール作りを忘れずに。