はじめに
企業のデータプラットフォームを運用する上で、
データガバナンスの確保は避けて通れない課題の一つです。
特に、以下のようなデータセキュリティに関する要件は、多くの現場で頻繁に発生します。
- 特定の部署(例:営業部)には、他部署の売上データを見せたくない(行レベルの制御)
- 全社で共有するユーザーテーブルだが、クレジットカード番号やメールアドレスなどの個人情報(PII)はマスクして隠したい(列レベルの制御)
Databricksでは、これらのセキュリティ要件を強力かつシンプルに実現するために、Unity Catalogのアクセス制限の機能として行フィルターと列マスクが提供されています。
これらを利用することで、データそのものを物理的に分けることなく、アクセスするユーザーの権限(所属グループなど)に応じて、動的に表示するデータを制御することが可能になります。
動的なアクセス制御として、タグベースで一元管理できるABAC(属性ベースのアクセス制御)という手法があります。本記事ではその手法を使って行フィルターと列マスクを実装してみます。
補足
データガバナンス
「データを正しく活用できる状態を作る仕組み」
データの状態として以下の項目を満たすことを目指す。
もし、このような状態でない(ガバナンスが効いていない)とき
使われないデータ基盤が生まれる。
- 発見性:必要なデータが「どこに、どのような形で存在するのか」を、誰でもすぐに探せる状態。
- 信頼性:そのデータが「本当に正しく、最新で、処理プロセスが透明である」と信じられる状態。
- 完全性:必要なデータが欠落(Null)することなく、100%揃っている状態。
- 一貫性:異なるシステムや場所にあっても、データの定義やフォーマットが一致している状態。
- セキュリティ:適切な人だけが、適切なデータにアクセスできるよう制御されている状態。
- コンプライアンス:各種の法律(個人情報保護法、GDPRなど)や業界の規制、社内ポリシーを遵守した状態でデータが扱われている状態。
Unity Catalog
「Databricks上のデータやAI資産に対して、一元的なガバナンスを提供する仕組み」
データ基盤(データレイクハウス)における「データのサイロ化」や「複雑すぎる権限管理」を解消し、先述したデータガバナンスの6つの要件をテクノロジーで強制・自動化するために導入する。
アクセス制御の実装
Databricksの公式チュートリアルをもとに進めていきます。
※ Databricks Free Editionで実行しています。
データ準備
1. 管理タグの作成
管理タグの作成はCREATE権限が必要です。
今回はFree版を登録したアカウントで行うため、権限は自動で与えられています。
- カタログ > 管理 > 管理タグに移動し「管理タグを作成」ボタンをクリック
- タグキーに
pii、タグに使用する値にsnn,addressを設定
✅ タグを作成できる人が制限されていたり、許容値を設定できるのでタグがばらばら、無駄に増えるなどを防げます。
2. 顧客テーブル作成
新規のノートブックを作ってSQLで次のクエリを実行します。
-- Create catalog (if not already exists)
CREATE CATALOG IF NOT EXISTS abac;
USE CATALOG abac;
-- Create schema
CREATE SCHEMA IF NOT EXISTS customers;
USE SCHEMA customers;
-- Create table
CREATE TABLE IF NOT EXISTS profiles (
First_Name STRING,
Last_Name STRING,
Phone_Number STRING,
Address STRING,
SSN STRING
)
USING DELTA;
-- Insert data
INSERT INTO profiles (First_Name, Last_Name, Phone_Number, Address, SSN)
VALUES
('John', 'Doe', '123-456-7890', '123 Main St, NY', '123-45-6789'),
('Jane', 'Smith', '234-567-8901', '456 Oak St, CA', '234-56-7890'),
('Alice', 'Johnson', '345-678-9012', '789 Pine St, TX', '345-67-8901'),
('Bob', 'Brown', '456-789-0123', '321 Maple St, FL', '456-78-9012'),
('Charlie', 'Davis', '567-890-1234', '654 Cedar St, IL', '567-89-0123'),
('Emily', 'White', '678-901-2345', '987 Birch St, WA', '678-90-1234'),
('Frank', 'Miller', '789-012-3456', '741 Spruce St, WA', '789-01-2345'),
('Grace', 'Wilson', '890-123-4567', '852 Elm St, NV', '890-12-3456'),
('Hank', 'Moore', '901-234-5678', '963 Walnut St, CO', '901-23-4567'),
('Ivy', 'Taylor', '012-345-6789', '159 Aspen St, AZ', '012-34-5678'),
('Liam', 'Connor', '111-222-3333', '12 Abbey Street, Dublin, Ireland EU', '111-22-3333'),
('Sophie', 'Dubois', '222-333-4444', '45 Rue de Rivoli, Paris, France Europe', '222-33-4444'),
('Hans', 'Müller', '333-444-5555', '78 Berliner Str., Berlin, Germany E.U.', '333-44-5555'),
('Elena', 'Rossi', '444-555-6666', '23 Via Roma, Milan, Italy Europe', '444-55-6666'),
('Johan', 'Andersson', '555-666-7777', '56 Drottninggatan, Stockholm, Sweden EU', '555-66-7777');
全体のテーブルはこのようになります。
3. PII列に管理タグを追加
先ほど作成したタグを次のクエリでPII列に付与します。
(タグの付与はUIからも可能です。)
-- Add the governed tag to ssn column
ALTER TABLE abac.customers.profiles
ALTER COLUMN SSN
SET TAGS ('pii' = 'ssn');
-- Add governed tag to address column
ALTER TABLE abac.customers.profiles
ALTER COLUMN Address
SET TAGS ('pii' = 'address');
行フィルターを実装
1. フィルターをかけるためのUDFを作成
次のクエリを実行して、Functionを作ります。
addressがヨーロッパかどうかを判定しています。
-- Determine if an address is not in the EU
CREATE OR REPLACE FUNCTION is_not_eu_address(address STRING)
RETURNS BOOLEAN -- 戻り値の型を指定
RETURN (
SELECT CASE
WHEN LOWER(address) LIKE '%eu%'
OR LOWER(address) LIKE '%e.u.%'
OR LOWER(address) LIKE '%europe%'
THEN FALSE -- AddressがEUのレコードはFalseを返す
ELSE TRUE -- それ以外はTrueを返す(出力で見えるようになる)
END
);
2. 行フィルターを適用
- カタログ > abacカタログ > ポリシーに移動し、「新しいポリシー」をクリック
- 各項目を入力
- 名前:適用したいポリシー名を記載
- 説明:ポリシーの説明を記載
- ポリシーの種類:行フィルター
- 適用対象:すべてのアカウントユーザー
- 範囲:abacカタログ、すべてのスキーマ
- 条件:条件なし(スコープ内のすべてのテーブル)
- 行フィルタ関数:先ほど作った
is_not_eu_addressを指定 - 関数入力:これらのタグのいずれかに一致する列で
pii: addressを指定
✅ 適用対象や範囲、条件などは実際の要件に沿う形で指定します。
✅ UDFの動作を確認するためのテスト機能があるので、架空の値を入れて挙動を確認できます。
78 Berliner Str., Berlin, Germany E.U.を試しにテストすると
FALSE (Hide row)が返され、動きが問題ないことを確認できます。
実際の挙動
ポリシーを適用したテーブルは次のようになります。
本来は15行のテーブルですが、10行になっており、正しく適用されていることがわかります。
今回は対象をすべてのユーザーにしているため、
自分のアカウントでも適用されています。
実際に活用していくケースでは、
見せたくないグループを指定してアクセスを制限します。
列マスクを実装
1. 列マスクをかけるためのUDFを作成
次のクエリを実行して、Functionを作ります。
SSN文字列をマスクした状態で返します。
-- Masks any SSN input by returning a fully masked value
CREATE FUNCTION mask_ssn(ssn STRING)
RETURNS STRING
RETURN '***-**-****' ;
2. 列マスクを適用
- カタログ > abacカタログ > ポリシーに移動し、「新しいポリシー」をクリック
- 各項目を入力
- 名前:適用したいポリシー名を記載
- 説明:ポリシーの説明を記載
- ポリシーの種類:列マスク
- 適用対象:すべてのアカウントユーザー
- 範囲:abacカタログ、すべてのスキーマ
- 条件:条件なし(スコープ内のすべてのテーブル)
- 列の条件:これらのタグのいずれかに一致する列で
pii: ssnを指定 - マスキング機能:先ほど作った
mask_ssnを指定
以下、行フィルターと同様です。
✅ 適用対象や範囲、条件などは実際の要件に沿う形で指定します。
✅ UDFの動作を確認するためのテスト機能があるので、架空の値を入れて挙動を確認できます。
901-234-5678を試しにテストすると
***-**-****が返され、動きが問題ないことを確認できます。
実際の挙動
ポリシーを適用したテーブルは次のようになります。
SSN列を見るとマスクされていることがわかります。
アクセス制御の応用
ここまでは、列や行の単位で一律で適用するシンプルな方法を見てきました。
しかし、実務上では「一般社員には隠したいが、管理者や特定のアカウントには生データを見せたい」「自分のデータだけを動的に表示させたい」というケースがあります。
ポリシー側で「対象列(タグ)」を一律に指定していても、呼び出すUDFの内部でIS_ACCOUNT_GROUP_MEMBERやCURRENT_USERを使うことで、アクセスしてきたユーザーに応じた動的な制御が可能になります。
実務でよく使う2パターンを紹介します。
1. 特定グループだけマスクを解除
個人情報(PII)のマスクは基本全員に適用しますが、「人事部(hr_team)」や「システム管理者(admin_team)」だけは業務上、生のSSN(社会保障番号)を見る必要がある、というケースです。
IS_ACCOUNT_GROUP_MEMBER()関数を活用した
次のクエリをノートブック上で実行してFunctionを更新します。
CREATE OR REPLACE FUNCTION mask_ssn(ssn STRING)
RETURNS STRING
RETURN (
SELECT CASE
-- admin_team または hr_team に所属していれば、生の値をそのまま返す
WHEN IS_ACCOUNT_GROUP_MEMBER('admin_team')
OR IS_ACCOUNT_GROUP_MEMBER('hr_team') THEN ssn
-- それ以外の一般ユーザーにはマスクした値を返す
ELSE '***-**-****'
END
);
カタログ内のmask_ssnを見ると、
定義が更新されていることが確認できます。
✅ Functionの定義を変えるだけで、それを適用しているポリシーにも自動的に反映されます。
2. 自分が担当するレコードのみを動的に表示
このパートは使ってきたデータと少しズレるのでご注意ください。
例えば、営業担当者が顧客リストを見る際、「自分が担当している(または所属している)地域の顧客データだけが表示されるようにしたい」というケースです。
ここでは、クエリを実行した本人のメールアドレスを取得できるCURRENT_USER()関数を活用します。
※ 今回は解説用に、profilesテーブルにassigned_agent(担当者メールアドレス)という列が仮にあるケースを想定したロジックで記述します。
CREATE OR REPLACE FUNCTION filter_by_viewer_policy(assigned_agent STRING)
RETURNS BOOLEAN
RETURN (
SELECT CASE
-- 管理者は無条件ですべての行を閲覧可能
WHEN IS_ACCOUNT_GROUP_MEMBER('admin_team') THEN TRUE
-- データの担当者が、現在クエリを実行しているユーザー自身であれば閲覧可能
WHEN assigned_agent = CURRENT_USER() THEN TRUE
-- それ以外は非表示
ELSE FALSE
END
);
タグベース(ABAC)と関数(システム関数)の組み合わせの重要性
タグベースの管理(ABAC)と動的アクセス制御のパターンは組み合わせて使うと便利です。
- どの列(データ)を保護対象にするか:管理タグ(Tags)で全社一元管理(スケールしやすい)
- 誰に、どう見せるか(ビジネスロジック):UDF内のシステム関数 で柔軟に制御(カスタマイズしやすい)
この設計にしておくと、ガバナンスのルールが変わっても
少し修正するだけで柔軟に適応できるようになるのでガバナンスを保つことが楽になります。









