動的アクセス制御にマッピング テーブルを使用する

このチュートリアルでは、多数のグループを管理せずに、マッピング テーブルを使用して行レベルと列レベルのアクセスを制御する方法について説明します。 1 つの参照テーブルによって、行のフィルター処理と列マスクの両方が実行されます。 アクセスの変更には、行の更新のみが必要です。 新しいグループを作成したり、ポリシーを書き換えたりする必要はありません。

このチュートリアルでは、条件付きマスクについても説明します。PII 列は、同じ行の別の列の値に応じて異なる方法でマスクされます。 confidentialマークされた注文の PII は、ユーザーのクリアランス レベルに関係なく完全に修正されます。

マッピング テーブルの設計に関する一般的なガイダンスについては、「 マッピング テーブルを使用してアクセス制御リストを作成する」を参照してください

前提条件

  • Databricks Runtime 16.4 以降、またはサーバーレス コンピューティング。
  • アカウント管理者またはワークスペース管理者のアクセス許可 (管理タグを作成するため)。
  • MANAGE ターゲット カタログまたはスキーマに対するアクセス許可。
  • EXECUTE UDF に対して
  • SQL ノートブックまたはクエリ エディター。

シナリオ

組織には、4 つのリージョン (米国東部、米国西部、EU、APAC) と 4 つの部門の従業員がいます。 各ユーザーには、地域と部署に一致する行のみが表示されます。PII 列は、マッピング テーブルに格納されているユーザーのクリアランス レベル (fullmasked、または none) と注文の order_priorityの 2 つの要因に基づいてマスクする必要があります。

グループベースのアプローチでは、リージョンと部門の組み合わせごとにグループが必要です。 たとえば、4 つのリージョンと 4 つの部門に対して 16 のグループが必要です。 PII承認レベルを追加すると、カウントが3倍になります。 新しいリージョンまたは部門ごとに、新しいグループとポリシーの更新が必要です。

マッピング テーブルアプローチでは、これを 1 つの参照テーブル (ユーザーごとに 1 行、アクセス ディメンションごとに 1 列) に置き換えます。 ユーザーのアクセス権を変更するには、行を更新します。

手順 1: 管理タグを作成する

SQL を実行する前に、カタログ エクスプローラー UI (Catalog>Govern>ガバナンスタグ>) で次のガバナンスタグを作成します。

タグ キー 許可された値
region (キーのみのタグ)
department (キーのみのタグ)
pii nameemail
priority (キーのみのタグ)

regionタグとdepartment タグは、フィルター UDF に渡す列を行フィルター ポリシーに指示します。 pii タグは、マスクする列とその PII の種類を列マスク ポリシーに指示します。 priority タグを使用すると、列マスク ポリシーは、条件付きマスクのためにorder_priority値をマスク UDF に渡すことができます。

Warnung

タグ データはプレーン テキストとして格納され、グローバルにレプリケートされる場合があります。 リソースのセキュリティを損なう可能性のあるタグ名、値、または記述子は使用しないでください。 たとえば、個人または機密情報を含むタグ名、値、記述子は使用しないでください。

手順 2: サンプル データをビルドする

カタログ、スキーマ、および注文テーブルを作成します。 order_priority列は条件付きマスクを推進します。高いクリアランスを持つユーザーの場合でも、confidentialマークされた注文の PII が完全に編集されます。

CREATE CATALOG IF NOT EXISTS abac_tutorial;
USE CATALOG abac_tutorial;

CREATE SCHEMA IF NOT EXISTS mapping_demo;
USE SCHEMA mapping_demo;
CREATE OR REPLACE TABLE orders (
  order_id INT,
  customer_name STRING,
  customer_email STRING,
  sales_region STRING,
  dept STRING,
  amount DOUBLE,
  order_date DATE,
  order_priority STRING
);

INSERT INTO orders VALUES
  (1,  'Acme Corp',     'orders@acme.com',    'us_east', 'engineering', 50000,  '2025-01-15', 'standard'),
  (2,  'Beta Inc',      'sales@beta.com',     'us_east', 'sales',       75000,  '2025-02-01', 'confidential'),
  (3,  'Gamma LLC',     'info@gamma.com',     'us_west', 'engineering', 30000,  '2025-01-20', 'standard'),
  (4,  'Delta Co',      'deals@delta.com',    'us_west', 'sales',       95000,  '2025-03-01', 'confidential'),
  (5,  'Epsilon GmbH',  'kontakt@epsilon.de', 'eu',      'engineering', 45000,  '2025-02-15', 'standard'),
  (6,  'Zeta SA',       'contact@zeta.fr',    'eu',      'sales',       62000,  '2025-01-30', 'standard'),
  (7,  'Eta Ltd',       'hello@eta.sg',       'apac',    'marketing',   28000,  '2025-03-10', 'confidential'),
  (8,  'Theta Corp',    'biz@theta.com',      'us_east', 'marketing',   55000,  '2025-02-20', 'standard'),
  (9,  'Iota KK',       'info@iota.jp',       'apac',    'engineering', 41000,  '2025-01-25', 'standard'),
  (10, 'Kappa Inc',     'sales@kappa.com',    'us_west', 'marketing',   33000,  '2025-03-05', 'standard');

手順 3: 管理タグを適用する

ABAC ポリシーが列を自動的に検出できるように、列にタグを付ける。 order_priority列には、priorityを介して列マスク ポリシーが一致し、その値をマスク UDF に渡すことができるように、キーのみのMATCH COLUMNS タグが付けられます。

ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN sales_region SET TAGS ('region' = '');
ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN dept SET TAGS ('department' = '');
ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN customer_name SET TAGS ('pii' = 'name');
ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN customer_email SET TAGS ('pii' = 'email');
ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN order_priority SET TAGS ('priority' = '');

手順 4: マッピング テーブルを作成する

すべてのリージョン、部門、およびクリアランスの組み合わせに対してグループを作成する代わりに、ユーザーごとに 1 行のテーブルを保持します。 pii_access列は、PII 列の表示方法を制御します。

  • full — 実際の値を参照してください (標準優先注文の場合)
  • maskedA***o***@acme.com などの部分的な値を確認してください
  • none — を参照 ***REDACTED***

expires_on列は、各アクセス エントリの有効期限を設定します。 この日付を過ぎると、行フィルター UDF はエントリの照合を停止し、ユーザーは手動による失効を必要とせずにアクセスを自動的に失います。 これは、請負業者、一時的なデータ共有契約、または時間制限付きプロジェクトに役立ちます。

ユーザーが複数のリージョンと部門の組み合わせにアクセスする必要がある場合は、追加の行を追加します。

Note

マッピング テーブルを小さくシンプルに保ちます。 保護されたテーブルに対する各クエリでは、行フィルターと列マスク UDF が実行され、その結果、マッピング テーブルに対してクエリが実行されます。 大規模なマッピング テーブルと複雑な UDF ロジックは、クエリのパフォーマンスに影響を与える可能性があります。 狭いスキーマを使用し、可能な場合は UDF ロジックを 1 回の参照に保持します。

CREATE OR REPLACE TABLE abac_tutorial.mapping_demo.user_access (
  user_email STRING,
  region STRING,
  department STRING,
  pii_access STRING,
  expires_on DATE
);

INSERT INTO abac_tutorial.mapping_demo.user_access VALUES
  (current_user(),      'us_east', 'engineering', 'masked', '2099-12-31'),
  ('bob@example.com',   'us_west', 'sales',       'full',   '2099-12-31'),
  ('carol@example.com', 'eu',      'engineering', 'none',   '2099-12-31'),
  ('david@example.com', 'apac',    'marketing',   'masked', '2099-12-31');

手順 5: 行フィルター UDF を作成する

この UDF は、行の sales_regiondept 値 (タグ照合を使用してポリシーによって渡されます) を受け取り、マッピング テーブルで現在のユーザーを検索し、一致するエントリが存在し、有効期限が切れていない場合にのみ TRUE を返します。 マッピング テーブルに含まれていないユーザー、またはアクセスの有効期限が切れているユーザーには、行が表示されません (フェールクローズ 設計)。

CREATE OR REPLACE FUNCTION abac_tutorial.mapping_demo.access_filter(
  region_val STRING,
  dept_val STRING
)
RETURNS BOOLEAN
RETURN EXISTS (
  SELECT 1 FROM abac_tutorial.mapping_demo.user_access
  WHERE user_email = current_user()
    AND region = region_val
    AND department = dept_val
    AND expires_on >= current_date()
);

手順 6: 列マスク UDF を作成する

この UDF は、PII 列の表示方法を制御します。 列の値、PII 型 ('name' または 'email')、行の order_priorityの 3 つの引数を受け取ります。 マスク ロジックには、次の 2 つのレイヤーがあります。

  • レイヤー 1 (条件付きマスク):order_priorityconfidentialされている場合、PII はユーザーのクリアランス レベルに関係なく常に完全に編集されます。
  • レイヤー 2 (ユーザーのクリアランス): 標準行の場合、UDF はユーザーの pii_access レベルのマッピング テーブルをチェックし、対応するマスクを適用します。 ユーザーが複数のマッピング テーブル エントリ (複数リージョン アクセス) を持っている場合、すべての行で最も高いクリアランスが適用されます。
CREATE OR REPLACE FUNCTION abac_tutorial.mapping_demo.pii_mask(
  val STRING,
  pii_type STRING,
  order_pri STRING
)
RETURNS STRING
RETURN CASE
  WHEN order_pri = 'confidential' THEN '***REDACTED***'
  WHEN EXISTS (
    SELECT 1 FROM abac_tutorial.mapping_demo.user_access
    WHERE user_email = current_user() AND pii_access = 'full'
  ) THEN val
  WHEN EXISTS (
    SELECT 1 FROM abac_tutorial.mapping_demo.user_access
    WHERE user_email = current_user() AND pii_access = 'masked'
  ) THEN
    CASE pii_type
      WHEN 'email' THEN CONCAT(LEFT(val, 1), '***@', SUBSTRING_INDEX(val, '@', -1))
      WHEN 'name'  THEN CONCAT(LEFT(val, 1), '***')
      ELSE CONCAT(LEFT(val, 1), '***')
    END
  ELSE '***REDACTED***'
END;

手順 7: ポリシーを作成する

3 つのポリシーを作成します。すべて同じマッピング テーブルによって駆動されます。 どちらの列マスク ポリシーも、同じ pii_mask 関数を使用します。 pii_type引数は、適用するマスク スタイルを関数に指示するため、列の種類ごとに個別の UDF は必要ありません。

priority管理タグは、MATCH COLUMNS列と一致し、その値をマスク UDF にorder_priorityとして渡すために、order_priで使用されます。 これが条件付きマスクの実装方法です。ポリシーは、クエリ時に行の優先度値を UDF に渡します。

CREATE POLICY user_access_filter
ON SCHEMA abac_tutorial.mapping_demo
ROW FILTER abac_tutorial.mapping_demo.access_filter
TO `account users`
FOR TABLES
MATCH COLUMNS has_tag('region') AS r, has_tag('department') AS d
USING COLUMNS (r, d);
CREATE POLICY pii_mask_name
ON SCHEMA abac_tutorial.mapping_demo
COLUMN MASK abac_tutorial.mapping_demo.pii_mask
TO `account users`
FOR TABLES
MATCH COLUMNS has_tag_value('pii', 'name') AS m,
  has_tag('priority') AS pri
ON COLUMN m
USING COLUMNS ('name', pri);

CREATE POLICY pii_mask_email
ON SCHEMA abac_tutorial.mapping_demo
COLUMN MASK abac_tutorial.mapping_demo.pii_mask
TO `account users`
FOR TABLES
MATCH COLUMNS has_tag_value('pii', 'email') AS m,
  has_tag('priority') AS pri
ON COLUMN m
USING COLUMNS ('email', pri);

手順 8: 結果を確認する

マッピング テーブルエントリを使用すると、us_east / engineeringクリアランスでmaskedにアクセスできます。 次のクエリを実行して、PII が部分的にマスクされた注文 #1 のみが表示されることを確認します。

SELECT * FROM abac_tutorial.mapping_demo.orders;

注文 1 には order_priority = 'standard'があるため、 masked のクリアランスが適用されます。

ユーザーに予想される結果:

注文ID 顧客名 カスタマー_メール 販売地域 金額 注文日 注文の優先順位
1 A*** o***@acme.com us_イースト 工学 50000 2025-01-15 標準

他のユーザーに表示される内容:

User 表示される注文 注文の優先度 PII の動作
bob@example.com (full クリアランス) #4 (us_west、販売) 機密 ***REDACTED*** — 機密はfull クリアランスを優先します
carol@example.com (none クリアランス) #5 (eu, エンジニアリング) 標準 ***REDACTED***none クリアランスは全面削除を意味します
david@example.com (masked クリアランス) #7 (アジア太平洋、マーケティング) 機密 ***REDACTED*** — 機密はクリアランスを優先します masked
(カタログ所有者) 全部で10 マスクなし: 所有者はポリシーを適用されません
(一覧に含てられていないユーザー) なし 行フィルターで行が返されない

bob にはfullクリアランスがありますが、注文 #4 が***REDACTED***であるため、confidentialが表示されます。 これは条件付きマスクです。行の優先度の値がユーザーのクリアランスをオーバーライドします。

手順 9: アクセスを動的に更新する

マッピング テーブルアプローチの主な利点は、テーブル内の行を更新することでアクセスを変更できることです。 ポリシー、UDF、またはグループ メンバーシップを更新する必要はありません。

別の部署に再割り当てする

部署を engineering から sales に変更します。 Order #2 (Beta Inc) は confidential 販売注文であるため、PII は masked クリアランスがあっても完全に伏せられています。

UPDATE abac_tutorial.mapping_demo.user_access
SET department = 'sales'
WHERE user_email = current_user();

次のクエリを実行して確認します。 注文番号 #2 と ***REDACTED*** PII が表示されるはずです。

SELECT * FROM abac_tutorial.mapping_demo.orders;

変更を元に戻します。

UPDATE abac_tutorial.mapping_demo.user_access
SET department = 'engineering'
WHERE user_email = current_user();

PII のクリアランスをアップグレードする

クリアランスを masked から fullに変更します。 標準優先行の場合、実際の PII 値が表示されます。

UPDATE abac_tutorial.mapping_demo.user_access
SET pii_access = 'full'
WHERE user_email = current_user();

次のクエリを実行して確認します。 注文 1 は standard 優先されるため、 full クリアランスを設定すると、 Acme Corporders@acme.comが表示されます。

SELECT * FROM abac_tutorial.mapping_demo.orders;

変更を取り消して元に戻します。

UPDATE abac_tutorial.mapping_demo.user_access
SET pii_access = 'masked'
WHERE user_email = current_user();

追加のリージョンへのアクセスを許可する

2 行目を挿入して、EU エンジニアリングへのアクセスを許可します。 新しいグループやポリシーは必要ありません。

INSERT INTO abac_tutorial.mapping_demo.user_access
VALUES (current_user(), 'eu', 'engineering', 'masked', '2099-12-31');

次のクエリを実行して確認します。 これで、注文 #1 (us_east、エンジニアリング) と注文 #5 (eu、エンジニアリング) の両方が表示され、PII は部分的にマスクされます。

SELECT * FROM abac_tutorial.mapping_demo.orders;

追加のアクセス権を削除します。

DELETE FROM abac_tutorial.mapping_demo.user_access
WHERE user_email = current_user() AND region = 'eu';

アクセスの有効期限が切れる

アクセス エントリを過去の日付に設定します。 行フィルター UDF は expires_on >= current_date()チェックするため、期限切れのエントリは自動的に無視され、アクセスは自動的に取り消されます。 これは、請負業者、一定の期間のデータ共有契約、または時間制限付きプロジェクトに役立ちます。

UPDATE abac_tutorial.mapping_demo.user_access
SET expires_on = current_date() - INTERVAL 1 DAY
WHERE user_email = current_user();

次のクエリを実行して、行が表示されていないことを確認します。

SELECT * FROM abac_tutorial.mapping_demo.orders;

将来の有効期限を使用してアクセスを復元する:

UPDATE abac_tutorial.mapping_demo.user_access
SET expires_on = '2099-12-31'
WHERE user_email = current_user();

次のクエリを実行して、アクセスが復元されたことを確認します。

SELECT * FROM abac_tutorial.mapping_demo.orders;

まとめ

このチュートリアルでは、次の 3 つのパターンを示しました。

  • マッピング テーブル パターン: 単一の参照テーブルは、行フィルター処理と列マスクの両方を制御します。 アクセスの変更は、ポリシーまたはグループの変更を必要とせず、行を更新することによって行われます。
  • 条件付きマスク: マスク UDF は各行の order_priority 列をチェックして、PII をマスクする方法を決定します。 機密行は、ユーザーのクリアランス レベルに関係なく常に完全に編集され、 order_priority にタグを付け、 MATCH COLUMNS経由で UDF に渡すことによって実装されます。
  • アクセスの有効期限: マッピング テーブルには expires_on 日付が含まれます。 行フィルター UDF は、 current_date()に対してこの日付をチェックするため、期限切れのエントリは自動的に無視され、手動による介入なしで自動取り消しにアクセスします。

クリーンアップ

このチュートリアルで作成したすべてのオブジェクトを削除するには、次のコマンドを実行します。

DROP POLICY user_access_filter ON SCHEMA abac_tutorial.mapping_demo;
DROP POLICY pii_mask_name ON SCHEMA abac_tutorial.mapping_demo;
DROP POLICY pii_mask_email ON SCHEMA abac_tutorial.mapping_demo;
DROP FUNCTION IF EXISTS abac_tutorial.mapping_demo.access_filter;
DROP FUNCTION IF EXISTS abac_tutorial.mapping_demo.pii_mask;
DROP TABLE IF EXISTS abac_tutorial.mapping_demo.orders;
DROP TABLE IF EXISTS abac_tutorial.mapping_demo.user_access;
DROP SCHEMA IF EXISTS abac_tutorial.mapping_demo CASCADE;

管理タグ、 regiondepartmentpii、および priority タグを削除するには、カタログ エクスプローラー UI を使用します。