SSN、クレジットカード、メール、住所。これらのカラムは、サポートや分析、開発のためにクエリ可能であり続けなければなりませんが、そこへ到達するために平文アクセスを誰彼構わず配ってよいわけではありません。データマスキングはそのためにあります。GDPR、HIPAA、PCI のワークロードでは、それは任意ではなく法的要件です。
BigQuery は動的データマスキングを、Dataplex Universal Catalog で管理されるポリシータグの上に構築されたカラムレベルセキュリティの一部として同梱しています。Bytebase Dynamic Data Masking はその前段に位置します。すべての BigQuery データセットで、そしてフリート内のあらゆる他エンジンでも、1 つのポリシーモデルが効き、人間のクエリ経路には申請・レビュー・承認が入ります。本記事で両者を比較します。
BigQuery Dynamic Data Masking
動的データマスキングは GA です。カラムレベルセキュリティを拡張するもので、別途のライセンス料金はかかりません。つまりすべての BigQuery プロジェクトで最初から利用できます。(対照的に Snowflake はマスキングを Enterprise へのアップグレードの背後にゲートします。)1 つ注意点があります。特定の BigQuery エディションで作成されたリザベーションではマスキングが適用されない場合があるため、スロット構成を確認してください。
マスキングは 3 つのステップで構成します。
- ポリシータグのタクソノミーを作成する。
- ポリシータグをカラムに付与する。
- マスキングルールと一連のプリンシパルをそのタグにバインドするデータポリシーを定義する。
読み取り時、BigQuery は Masked Reader ロールを持つプリンシパルに対してカラムを書き換えます。保存されたデータは変更されません。
BigQuery は組み込みのマスキングルールのセットを同梱しており、それらでカバーできないものにはカスタムルーチンが使えます。同じ 3 ステップをコマンドで示します。
# 1. Create a taxonomy and a policy tag (Dataplex Universal Catalog).
gcloud data-catalog taxonomies create \
--location=us --display-name=pii
gcloud data-catalog taxonomies policy-tags create \
--location=us --taxonomy=$TAXONOMY_ID --display-name=ssn
# 2. Attach the policy tag to a column through the table schema.
# schema.json:
# [{ "name": "ssn", "type": "STRING",
# "policyTags": { "names": ["projects/$PROJECT/locations/us/taxonomies/$T/policyTags/$P"] } }]
bq update --schema schema.json $PROJECT:sales.customers
# 3. Create a data policy that binds a masking rule to the policy tag.
# There is no SQL DDL or bq command for this. Use the Data Policy API.
curl -X POST \
"https://bigquerydatapolicy.googleapis.com/v1/projects/$PROJECT/locations/us/dataPolicies" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d '{
"dataPolicyId": "ssn_mask",
"dataPolicyType": "DATA_MASKING_POLICY",
"policyTag": "projects/'"$PROJECT"'/locations/us/taxonomies/'"$T"'/policyTags/'"$P"'",
"dataMaskingPolicy": { "predefinedExpression": "LAST_FOUR_CHARACTERS" }
}'
# 4. Grant the principal the Masked Reader role.
gcloud projects add-iam-policy-binding $PROJECT \
--member="user:analyst@example.com" \
--role="roles/bigquerydatapolicy.maskedReader"コンソールは Manage Data Policies で同じフローを実行します。policy-as-code には、Terraform の google_bigquery_datapolicy_data_policy リソースがステップ 3 をラップします。
権限: 3 つの状態
ポリシータグの付いたカラムへのアクセスは、プリンシパルが持つ IAM ロールによって、3 つの状態のいずれかに解決されます。
- Fine-Grained Reader(
datacatalog.categoryFineGrainedReader)は平文を見ます。このロールはマスキングの上位に位置するため、付与は最小限にし、変更を監査してください。 - Masked Reader(
bigquerydatapolicy.maskedReader)はデータポリシーが定義するマスク値を見ます。 - いずれも持たない場合、クエリは拒否されます。カラムレベルセキュリティが読み取りそのものをブロックします。
カラムは 1 つのポリシータグを持ち、そのタグは単一のマスキングルールにマッピングされます。マスキングはカラムごと、タグごとです。その上に重ねる第 2 のルールはありません。
BigQuery のデータマスキングがしないこと
- Fine-Grained Reader を止める。 このロールはマスクされていない値を返します。単なる IAM 付与なので、持つ者を制限し、付与を監査してください。
- カラムごとに複数のルールを適用する。 カラムごとに 1 つのポリシータグ。タグのデータポリシーは 1 つのマスキングルールを選びます。合成はできません。
- 直接アクセスやサービスアクセスをレビューに通す。 BI ツール、スケジュールジョブ、アプリケーションのサービスアカウントは、自身が持つロールのままウェアハウスをクエリします。Fine-Grained Reader を付与されたサービスアカウントは、申請もレビューもなく平文を読みます。
- 承認ワークフローやアンマスクの監査証跡を提供する。 Fine-Grained Reader の付与は IAM 編集です。申請・レビュー・承認の経路はなく、その付与はファーストクラスの監査対象マスキングイベントではありません。
- レガシー SQL、ワイルドカード(
*)テーブルクエリ、コピージョブで動作する。 マスキングはこれら 3 つすべてと互換性がありません。 - カスタムルーチンでパーティショニング/クラスタリングカラムをマスクする。 カスタムマスキングルーチンは、パーティショニングまたはクラスタリングに使われるカラムには適用されません。
- 行をフィルタする。 マスキングはカラムレベルです。行レベルの制御には、行レベルセキュリティ(row access policy)を使ってください。
Bytebase Dynamic Data Masking
ネイティブマスキングには文書化された隙があります。Fine-Grained Reader の付与は平文を返し、それは単なる IAM 編集です。申請なし、レビューなし、監査されたアンマスクイベントなし。アクセスの付与と、誰が何を見たかの証明は、別々の手動ステップになります。原因は構造的です。マスキングはウェアハウス内部でカラムを書き換えますが、それをバイパスするロール付与は上流の IAM にあります。この隙を塞ぐには、カラムだけでなくクエリそのものを統制する必要があります。
Bytebase Dynamic Data Masking はクエリを統制します。クエリは Bytebase の SQL Editor を経由し、Bytebase は結果がエディタから出る前にマスクします。バックエンドのプロジェクトで Fine-Grained Reader を付与されていても、ポリシーをバイパスできません。アンマスクはアクセス判断になります。Query 権限の付与は組み込みのワークフロー(申請・レビュー・承認)を通り、すべてのステップが監査されます。
ポリシーは固定の優先順位で評価される 3 つのレイヤーから構成されます。マスキング例外 > グローバルマスキングルール > カラムマスキング。
- グローバルマスキングルール。 ワークスペース単位。ルールは上から評価され、最初に一致したものが勝ちます。一致条件は環境、プロジェクト、データベース、データ分類にまたがります。一致するたびに Semantic Type が適用され、それがマスキングアルゴリズム(full、partial、MD5、range、カスタム)を選びます。
- カラムマスキング。 プロジェクト単位のオーバーライド。グローバルルールが該当しない特定カラムに適用します。
- マスキング例外。 指名されたユーザーが、特定のデータベースまたはテーブルに対して期限付きの
QueryまたはExport例外を受けます。サービスアカウントは対象外です。すべての付与が記録され、すべてのアクセスが記録されます。
マスキングは伝播します。カラムがマスクされると、そのポリシーは依存するすべてのビューと派生構造に及びます。マスク済みカラム上の式もマスクされたままです。
ポリシーは GitOps でコード化することもできます。
マスキングの決定は監査ログに記録されます。SQL 実行エントリは、マスクされたカラム、Semantic Type、一致したルールというカラム単位のマスキングメタデータを、ユーザー、送信元 IP、ステートメント、行数とともに記録します。例外の付与、例外の行使、ポリシーの編集はファーストクラスの監査イベントです。アクセス判断と強制の証跡は同じレコードに収まります。
1 つはっきりさせておきたいのが、強制の境界です。Bytebase は SQL Editor を経由するクエリをマスクします。BigQuery に直接到達するトラフィック(BI ツール、スケジュールジョブ、サービスアカウント)はこれをバイパスし、そこはネイティブのデータマスキングと IAM がカバーします。この分担は対称的です。ウェアハウスではネイティブマスキング、承認と監査が要となる人間のクエリ経路では Bytebase。1 つのポリシーが BigQuery と、その隣にある Postgres、MySQL、SQL Server、Oracle、Snowflake のインスタンスに適用されます。
比較
| BigQuery Dynamic Data Masking | Bytebase Dynamic Data Masking | |
|---|---|---|
| 互換性 | BigQuery のみ | BigQuery を含むすべてのエンジン ⭐️ |
| メカニズム | カラムごとのポリシータグ + データポリシー ⭐️ | Bytebase 内のポリシー、SQL Editor で適用 |
| 強制位置 | ウェアハウス、全読み取り経路 ⭐️ | SQL Editor |
| マスキングルール | 組み込みルール + カスタムルーチン ⭐️ | full、partial、MD5、range、カスタム |
| ポリシー管理 | コンソール / Data Policy API / Terraform | 集中 UI、付与、監査ログ ⭐️ |
| 権限スコープ | カラム(ポリシータグ 1 つ) | プロジェクト、データベース、テーブル、カラム ⭐️ |
| ワークフロー | IAM 付与のみ | 申請。レビュー。承認。 ⭐️ |
| 行レベル制御 | 無し(row access policy と併用) | 無し(アクセスポリシーと併用) |
| コスト | BigQuery に含まれる ⭐️ | Bytebase Enterprise |
選び方
- 単一の BigQuery エステートで、あらゆるクライアントを通じてマスキングを維持しなければならない場合。 ネイティブのデータマスキングを使ってください。ウェアハウス内、全読み取り経路で強制され、直接接続する BI ツール、スケジュールジョブ、サービスアカウントも含まれます。行レベルの制御には row access policy を併用し、
Fine-Grained Readerの付与は少数に留めてログに記録してください。 - 承認ワークフローとアンマスクの監査証跡が必要な場合。 ネイティブマスキングの付与は単なる IAM 編集です。人間のクエリ経路には Bytebase を使ってください(申請・レビュー・承認)。すべての例外とアクセスがログに記録されます。
- 混在フリート。BigQuery を Postgres、MySQL、SQL Server、Snowflake と併用する場合。 Bytebase を使ってください。1 つのポリシーモデル、すべてのエンジン、すべてのアンマスクに監査付きの付与、アクセスログと同じ場所に記録されます。
- 両方。 ウェアハウスではネイティブマスキングが直接接続、BI ツール、サービスアカウントを処理します。Bytebase は人間のクエリ経路を SQL Editor 経由で統制し、承認と監査を提供します。両者は組み合わさります。
このチュートリアルで Bytebase Dynamic Data Masking を試せます。