BigQueryで構築するマスキングデータベースについて
はじめに
こんにちは、システム統括グループ、システム基盤チームの有山です。
普段の業務では、ウェルスナビで運用するシステムの性能改善や運用の自動化を担当しています。
最近、Amazon Auroraで構築していたマスキングデータベースをBigQueryに移行し、性能改善を行いました。
この記事では、既存のマスキングデータベースの紹介や性能改善を行なった背景、また、今回個人情報を新たにBigQueryに格納したため、セキュリティ周りで気をつけた点などについてお伝えしていきます。
対象の読者
以下のような方を想定しています。
- BigQueryで分析基盤を構築したい方
- アクセス制限をかけるなどBigQueryに関するセキュリティ施策について知りたい方
- データのマスキングをどのように実施しているか、実例を知りたい方
プロジェクトの背景
現在、ウェルスナビでは、アプリケーションのデータベースとしてAmazon Auroraを利用しています。顧客情報のような機密情報を保存するため、データベースには、特定の運用端末から限られた運用メンバーのみアクセスできる決まりとなっています。
他方で開発チームから下記のようなニーズがあり、システム基盤チームとして、機密情報をマスキングしたデータベースを日次で構築し、開発チームに提供しています。
- バックエンドのアプリケーションと繋いで開発をしたい。
- 障害調査やデバッグ目的でデータベースをクエリしたい。
- データ分析基盤のデータソースにしたい。
既存の方法では、本番のデータベースをクローンし、レコードを直接Update文で更新するという方法で作成しています。
この方法でしばらく運用してきたのですが、マスキング処理のパフォーマンスが悪化してきていました。
理由の一つとして、データマスキング時に発生するテーブルのロック競合が考えられました。
Update文でレコードを直接更新する場合、他のテーブルと同期を取るため、テーブルにロックをかける必要があります。
マスキング処理の過程で、データベース内のほぼ全てのテーブルのレコード全体に対してUpdate文を実行していたため、テーブルへロックが発生しやすく、その結果大量の書き込み待ち時間が発生してしまっているという状態でした。
マスキングデータベースは開発やテスト以外にも、弊社で運用しているデータ分析基盤のデータソースとしても利用されています。
このデータ分析基盤を利用して、経営層向けにKPIに関するダッシュボードを指定の時間までに提供しているのですが、マスキング処理がボトルネックとなり、近い将来、ダッシュボードの作成が定常的に指定の時間までに間に合わなくなるという懸念がありました。
したがって、このマスキング処理の仕組みを改善し、KPIダッシュボードの作成時間を早めたいということが、今回取り組んだ背景となります。
改善後のアーキテクチャ
改善案を考えるにあたり、下記の観点で改善ができないかを考えました。
- Auroraではなく、何か別のストレージにオフロードする。
- レコードを更新する以外の方法でマスキング処理を行う。
まず一つ目の観点について、分析基盤では、データウェアハウスにBigQueryを利用していたため、AuroraのデータをBigQueryへ転送することで実現できると考えました。
二つ目の観点について、データベースの値を更新するのではなく、データを取り出す際に、Update文で実行していたマスキング処理ロジックをSelect文を介して実行することで実現できると考えました。
具体的には、下記のような構成を考えました。
マスキングデータベース用のプロジェクトを新規に作成し、このプロジェクトのBigQueryに下記の流れでマスキングデータベース相当のデータベースを構築しました。
- AuroraのレコードをS3へエクスポート
- BigQuery Data Transfer Serviceを利用し、S3からBigQueryのテーブルへデータを転送
- 転送後のデータを元にマスキングロジックが書かれたViewをクエリし、分析基盤のテーブルに連携
実装したViewは、たとえば下記のようなものになります。
-- Update文
Update User
SET Name = "***" -- UserテーブルのNameカラムに機密情報が入るため、一律***で置き換える。
-- Select文
SELECT
"***" AS Name
FROM
User
このような改善を行うことで、下記のパフォーマンス改善を行い、従来3時間ほどかかっていた処理を1時間程度に抑えることができました。
- BigQueryにオフロードすることで、クエリ全体のパフォーマンスを向上させた。
- 値を直接書き込まないことで、他のテーブルと同期する必要がなくなった。
パフォーマンスを改善できる一方で、この構成を取ることにより、BigQueryに機密情報を格納することが必要となりました。
次章では、機密情報を格納するにあたり実施したセキュリティ施策についてご紹介します。
実施したセキュリティ施策について
BigQueryへアクセス制限をかける。
BigQueryをAuroraと同等に扱うために、個人情報を保持するデータセットには下記のようなアクセス制限をかける必要がありました。
- インフラメンバーとサービスに必要なシステムアカウントのみがアクセス可能にする。
- 特定の運用端末からのみアクセス可能にする。
- BigQueryのデータの持ち出し先は分析基盤プロジェクトに制限する。
一つ目の要件については、IAMによる制限で対応することができますが、二つ目の要件については、何か別の方法を考える必要がありました。
GCPリソースへのアクセス管理のサービスとして、VPC Service Controlsがあります。こちらを利用することで、GCPのリソースをプライベートな境界に置き、アクセスを許可するIPアドレスとIAMを指定することでサービスへのアクセスを制限することができます。
今回はこのサービスを利用し、図のように運用メンバーのIDと運用端末が使うグローバルIPをインバウンドで許可することによって、本番リソースに対するオペレーションを可能にしました。
また、BigQueryリソースのデプロイにはTerraform Cloudを利用しており、今回のアクセス制限に合わせてTerraform Cloudの実行環境についても変更を加える必要がありました。
Terraform Cloudを利用する場合、コマンドの実行環境を選択することができ、通常は、Terraform Cloud内の環境になります。この場合、実行環境のグローバルIPも動的に変化してしまいます。
インバウンドルールで許可するグローバルIPを固定化するため、Terraform Cloud Agentを利用することにしました。Agentを利用することで、terraformコマンドの実行場所を自前で構築した環境に指定することができます。
今回はGCEインスタンスを構築し、インスタンス内でコンテナを起動するようにしてAgentの構築を行いました。
Agentの説明や細かい設定方法などは公式ドキュメントに記載がありますが、取得したAgent名とトークンをもとに下記のシェルスクリプトをGCEのスタートアップスクリプトとして実行することで、インスタンス実行時にAgentを起動することができました。
#!/bin/bash
sudo apt-get update && sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update && sudo apt-get install -y \
containerd.io \
docker-ce \
docker-ce-cli \
docker-compose-plugin
TFC_AGENT_TOKEN=${tfc_agent_token} \
TFC_AGENT_NAME=${tfc_agent_name} \
docker run -d -e TFC_AGENT_TOKEN -e TFC_AGENT_NAME hashicorp/tfc-agent:latest
三つ目の要件について、GCP全体のETLをCloud workflowsを用いて行なっていたため、Cloud workflowsのサービスアカウントと分析基盤のプロジェクトをアウトバウンドで許可することで解決しました。
サービスアカウントキーをクレデンシャルを発行せずに利用する。
今回、Terraform CloudやAWSからGCPのリソースにアクセスするため、GCP外部からサービスアカウントを利用してリソースを操作する必要がありました。
サービスアカウントをGCP以外のクラウド等から利用する場合、クレデンシャルを発行して使う方法がありますが、こちらは下記の理由で発行をしませんでした。
- 万が一鍵が漏洩してしまうと、誰でもサービスアカウントの権限を実行できる。
- クレデンシャルに有効期限がないため、自前でローテーションする必要がある。
代わりに、Workload Identityを使用し、サービスアカウントキーを発行せずにAWSやTerraform CloudからGCPのリソースを操作することにしました。
例えば、Terraform CloudでWorkload Identityを利用する場合、下記のようなイメージとなります。
こちらの公式ドキュメントの記載通り、下記のような手順で認証を行います。
- Terraformコマンド実行時に、認証用のトークンをGCPに送信する
- トークンの妥当性を確認し、問題なければ一時トークンを発行、Terraform Cloudに送信する
- 一時トークンを環境変数にセットし、コマンドを実行する
- コマンド終了後、一時トークンを破棄する
設定方法はGCP Configuration通りに進めていきます。大まかには下記の手順で進めます。
- Workload Identity PoolとProviderの作成
- 属性マッピングの値に何を入れれば良いか分かりづらいですが、サンプルコードが参考になります。
- サービスアカウントを作成し、必要な権限を付与する
- Terraform Cloud側の環境変数に下記の値をセットする
- TFC_GCP_PROJECT_NUMBER: GCPのプロジェクト番号
- TFC_GCP_PROVIDER_AUTH: true
- TFC_GCP_RUN_SERVICE_ACCOUNT_EMAIL: 使用したいサービスアカウントのEmail
- TFC_GCP_WORKLOAD_POOL_ID: Workload Pool ID
- TFC_GCP_WORKLOAD_PROVIDER_ID: Workload Provider ID
このようにサービスアカウントキーを使わずに一時的な認証情報を使うことで、キーの漏洩リスクを避けるようにしました。
さいごに
所感
以上を行うことで、機密情報をBigQueryでセキュアに扱った上で、性能を改善することができました。
BigQueryをVPCサービスのように扱い、機密情報を扱えるストレージの選択肢を増やせたことで、データ活用やパフォーマンス改善の選択肢を増やすことができたのは良かったと考えています。
また、今回の構築にあたりセキュリティチームや分析基盤チームの方々、およびシステム基盤チームのメンバーから多大なサポートを受け、リリースすることができました。この場を借りてお礼申し上げます。
課題や今後の展望
今回、マスキング処理をSQLで行いましたが、当初はData Catalogの動的データマスキングの機能を利用して行おうと考えていました。
こちらは、マスキングしたいカラムにタグを付与し、データ取り出し時にタグのマスキングポリシーに従ってデータをマスキングするというサービスになります。
マネージドでデータをマスキングできるため、利用を検討していましたが、既存のマスキング処理にCase文による分岐処理やテーブルをジョインした複雑な処理があり、現在用意されているマスキングポリシーでは既存の処理を再現することができないと判断し、利用を見送りました。今後の機能改善でより高度なマスキングをマネージドにできるようになった際には、リプレイスを検討したいと考えています。
📣ウェルスナビは一緒に働く仲間を募集しています📣
著者プロフィール
有山 涼(ありやま りょう)
2021年6月にウェルスナビに、エンジニアとして入社。
コードを書いてシステム運用を楽にするのが好きです。
登山と筋トレが趣味です。
Discussion