はじめに
データ分析基盤として BigQuery を採用する方は多いかと思いますが、エンタープライズ環境においては「誰にどのデータを見せるか」というアクセス制御の設計が課題となります。顧客の個人情報(PII)やクレジットカード番号、地域・部門ごとの売上情報など、 同じテーブル内でも閲覧権限を切り分けたいケース が発生します。
今回は BigQuery が提供する 行レベルセキュリティ(Row-Level Security, RLS) と 列レベルセキュリティ(Column-Level Security, CLS) について、実際のハンズオン手順を整理してみたいと思います。
なお、Google Cloud を活用したシステム開発については、Udemy にて関連コースをリリースしておりますので、ご興味のある方はご覧ください。
1. 行レベル・列レベルセキュリティとは
BigQuery には、テーブル単位の IAM 権限制御に加え、より細粒度なアクセス制御の仕組みが提供されています。
-
行レベルセキュリティ(RLS):ユーザーごとに「見える行」をフィルタリングする仕組み。例:東京拠点のユーザーには
region_id = 'tokyo'の行のみ表示する。 -
列レベルセキュリティ(CLS):ユーザーごとに「見える列」を制御する仕組み。例:一般ユーザーには
credit_id列を非表示にする。Data Catalog のポリシータグ(Taxonomy)と連携して制御する。
これらは、 「テーブル自体は1つだが、ユーザーごとに見える範囲を変えたい」 という、典型的なマルチテナント・多部門共用のデータ基盤において重要な機能です。データを複製してビュー単位で権限管理する従来の方式と比べ、運用負荷とデータ整合性リスクを削減できます。
2. ハンズオン:BigQuery における行レベル・列レベルセキュリティ
2-1. データセットとテーブルの作成
まずは Cloud Shell から、検証用のデータセットを作成します。(東京リージョンを想定)
export PROJECT_ID=$(gcloud config get-value project)
export REGION="asia-northeast1"
bq --location=${REGION} mk --dataset ${PROJECT_ID}:sec_handson
続いて、BigQuery Studio(SQLワークスペース)から、サンプルテーブルを作成し、検証用データを投入します。
CREATE TABLE sec_handson.transactions (
user_id STRING,
region_id STRING,
credit_id STRING,
amount INT64
);
INSERT sec_handson.transactions VALUES
('u001','tokyo','c-1001',5000),
('u002','tokyo','c-1002',7000),
('u003','osaka','c-2001',8000),
('u004','osaka','c-2002',3000),
('u005','nagoya','c-3001',6000);
このテーブルには、東京・大阪・名古屋の3拠点のトランザクションデータと、クレジットカード番号(credit_id)が含まれている想定です。
2-2. 行レベルセキュリティ(RLS)の設定
「東京拠点のユーザーには、東京の行のみを見せる」という行アクセスポリシーを作成します。
CREATE ROW ACCESS POLICY tokyo_only
ON sec_handson.transactions
GRANT TO ('user:あなたのメールアドレス@example.com')
FILTER USING (region_id = 'tokyo');
ポリシー作成後、対象ユーザーで以下の SELECT を実行すると、東京(region_id = 'tokyo')の2行のみが表示される ことが確認できます。
SELECT * FROM sec_handson.transactions;
ポイントは、アプリケーション側で WHERE 句を意識する必要がない点です。 データベース側で行がフィルタリングされる ため、アプリのバグや SQL の書き忘れで意図しないデータが漏洩するリスクを構造的に防げます。
動作確認後は、ポリシーを削除し、全件が見える状態に戻しておきます。
DROP ALL ROW ACCESS POLICIES ON sec_handson.transactions;
SELECT * FROM sec_handson.transactions;
2-3. 列レベルセキュリティ(CLS)の設定
列レベルセキュリティは、Data Catalog のポリシータグ(Taxonomy)と連携して設定します。まず、必要な API を有効化します。
gcloud services enable datacatalog.googleapis.com bigquery.googleapis.com
次に、BigQuery Studio または Google Cloud コンソールから、以下の手順で Taxonomy(分類体系)とポリシータグを作成します。
- Google Cloud コンソール → 「BigQuery」→「ポリシータグ」を開く。
- Taxonomy を新規作成(例:
pii-taxonomy、ロケーションはasia-northeast1)。 - その下にポリシータグ(例:
high-confidential)を作成。
作成したポリシータグを、保護したい列(今回は credit_id)に紐付けます。BigQuery Studio のテーブルスキーマ編集画面から credit_id 列に high-confidential タグを付与します。
この時点で、ポリシータグの「Fine-Grained Reader」ロールを持たないユーザーが該当列を SELECT すると、アクセス拒否エラーになります。
-- credit_id を含む列を取得 → 権限がなければエラー
SELECT * FROM sec_handson.transactions;
-- credit_id を除外すれば取得可能
SELECT user_id, region_id, amount FROM sec_handson.transactions;
列を閲覧可能にしたいユーザーには、以下のコマンドで Fine-Grained Reader 権限を付与します。TAXONOMY_ID は、コンソール上で確認した Taxonomy の ID に置き換えてください。
gcloud data-catalog taxonomies add-iam-policy-binding TAXONOMY_ID \
--location=asia-northeast1 \
--member="user:見せたい人のメール@example.com" \
--role="roles/datacatalog.categoryFineGrainedReader"
2-4. クリーンナップ
検証が終わったら、データセットを削除して環境をクリーンナップします。
bq rm -r -f -d ${PROJECT_ID}:sec_handson
ポリシータグおよび Taxonomy も、コンソールから合わせて削除しておくとよいでしょう。
3. 行レベル vs 列レベル:使い分けの考え方
実務において両者は対立するものではなく、 組み合わせて使う ケースがほとんどです。設計上の使い分けの観点は以下の通りです。
- 行レベル(RLS):ユーザーの「所属」「担当範囲」によって見えるデータが変わる場合。例:拠点別、事業部別、顧客別。
- 列レベル(CLS):データの「機密度(カラム属性)」によって閲覧可否が変わる場合。例:個人情報、クレジットカード番号、年収。
例えば「東京拠点の一般スタッフ」には RLS で東京の行のみを見せつつ、CLS でクレジットカード列を非表示にする、といった重ね掛けが可能です。
4. おわりに
エンタープライズのデータ基盤においては、 「全員に同じテーブルを見せる」設計はそもそも成立しません。 部門・拠点・職位ごとにアクセス権限を細かく設計することが、ガバナンス上の前提条件となります。
従来は、データを複製したビューを大量に作成し、ビュー単位で権限管理するという運用が一般的でしたが、データ二重管理によるコスト増・整合性リスク・運用負荷の高さが大きな課題でした。BigQuery の行レベル・列レベルセキュリティを活用することで、「単一のテーブルを正とし、論理的にアクセス制御だけを切り分ける」 というシンプルなアーキテクチャを実現できます。
データ基盤のセキュリティ設計を検討されている方は、ぜひ一度この機能を検証されることをお勧めします。
プロフィール
[Maruchin Tech]
AWS、Google Cloud、製造業・SCM DXを専門とするUdemy講師・技術顧問。
新卒で日産自動車に入社。その後アクセンチュア、NTTデータを経て独立。
大手製造業の基幹システム刷新やDXプロジェクトにおいて、要件定義からアーキテクチャ設計までをリード。
現在は「現場で本当に使える技術と視点」をテーマに、エンジニア教育に従事。