行フィルターと列マスクを使用して機密性の高いテーブル データをフィルター処理する

この記事では、行フィルター、列マスク、マッピング テーブルを使ってテーブル内の機密データをフィルター処理するためのガイダンスと例を示します。 これらの機能には Unity Catalog が必要です。

行フィルターとは

行フィルターを使用すると、テーブルにフィルターを適用して、クエリがフィルター条件を満たす行のみを返すようにすることができます。 SQL ユーザー定義関数 (UDF) として行フィルターを実装します。 Python UDF および Scala UDF もサポートされていますが、SQL UDF でラップされている場合に限られます。

列マスクとは

列マスクを使うと、テーブル列にマスキング関数を適用できます。 マスキング関数はクエリ実行時に評価され、ターゲット列の各参照がマスキング関数の結果に置き換えられます。 ほとんどのユース ケースでは、列マスクを使って、元の列の値を返すか、呼び出し元ユーザーの ID に基づいて値を編集するかを決定します。 列マスクは SQL UDF として記述された式、または SQL UDF でラップされた Python UDF および Scala UDF として記述された式です。

各テーブル列に 1 つのみマスキング関数を適用できます。 マスキング関数は、マスクされていない列の値を入力として受け取り、マスクされた値を結果として返します。 マスキング関数の戻り値は、マスク対象の列と同じ型である必要があります。 マスキング関数は、追加の列を入力パラメーターとして受け取ってマスキングのロジックで使うこともできます。

これらのフィルターと動的ビューの違いは何か

動的ビュー、行フィルター、列マスクのどれを使っても、複雑なロジックをテーブルに適用し、クエリ実行時にそのフィルター処理の決定を処理できます。

動的ビューは、1 つ以上のソース テーブルの、抽象化された読み取り専用ビューです。 ユーザーは、ソース テーブルに直接アクセスできなくても、動的ビューにアクセスできます。 動的ビューを作成すると、新しいテーブル名が定義されます。それは、ソース テーブルやその他のテーブルの名前、および同じスキーマに存在するビューの名前と一致してはなりません。

一方、行フィルターまたは列マスクをターゲット テーブルに関連付ける場合は、対応するロジックがテーブル自体に直接適用され、新しいテーブル名が導入されることはありません。 後続のクエリでは、ターゲット テーブルをその元の名前を使って直接参照し続けることができます。

フィルターやマスクなどの変換ロジックを読み取り専用テーブルに適用する必要があり、ユーザーが別の名前を使って動的ビューを参照してもよい場合は、動的ビューを使います。 Delta Sharing を使用してデータを共有する場合に、データをフィルター処理する場合は、動的ビューを使用する必要があります。 特定のデータに対してフィルター処理や式の計算を実行しつつ、ユーザーが元の名前を使ってテーブルにアクセスできるようにしたい場合は、行フィルターと列マスクを使います。

開始する前に

テーブルに行フィルターと列マスクを追加するには、次が必要です。

  • Unity Catalog に対して有効になっているワークスペース。
  • Unity Catalog に登録された関数。 これは、SQL UDF、または Unity Catalog に登録され、SQL UDF でラップされた Python UDF または Scala UDF の可能性があります。 詳細については、「ユーザー定義関数 (UDF) とは」、「列マスク句」、「列フィルター句」を参照してください。

次の要件も満たす必要があります。

  • 行フィルターや列マスクをテーブルに追加する関数を割り当てるには、関数に EXECUTE 特権、スキーマに USE SCHEMA、親カタログに USE CATALOG が必要です。
  • 新しいテーブルを作成する場合にフィルターやマスクを追加するには、スキーマの CREATE TABLE 特権も必要です。
  • 既存のテーブルを変更してフィルターやマスクを追加するには、テーブル所有者であるか、テーブルの MODIFY 特権がある必要があります。

行フィルターや列マスクがあるテーブルにアクセスするには、コンピューティング リソースが次の要件のいずれかを満たす必要があります。

  • SQL ウェアハウス

  • Databricks Runtime 12.2 LTS 以降の場合は共有アクセス モード

  • Databricks Runtime 15.4 LTS 以降の場合はシングル ユーザー アクセス モード (パブリック プレビュー)

    Databricks Runtime 15.3 以前では、シングル ユーザー コンピューティングを使用して行フィルターまたは列マスクを読み取ることはできません。

    Databricks Runtime 15.4 LTS 以降で提供されるデータ フィルター処理を利用するには、行フィルターと列マスクをサポートするデータ フィルター処理機能はサーバーレス コンピューティングで実行されるため、"ワークスペースでサーバーレス コンピューティングが有効になっている" ことも確認する必要があります。 そのため、シングル ユーザー コンピューティングを使用して、行フィルターまたは列マスクを読み取ると、サーバーレス コンピューティング リソースに対して課金される場合があります。 「シングル ユーザー コンピューティングに対するきめ細かなアクセス制御」を参照してください。

行フィルターの適用

行フィルターを作成するには、まず関数 (UDF) を記述してフィルター ポリシーを定義してから、それを適用してテーブルに適用します。 各テーブルに設定できる行フィルターは 1 つだけです。 行フィルターは 0 個以上の入力パラメーターを受け取り、各入力パラメーターは対応するテーブルの 1 つの列にバインドされます。

カタログ エクスプローラーまたは SQL コマンドを使用して行フィルターを適用できます。 カタログ エクスプローラーの手順は、既に関数を作成し、それが Unity Catalog に登録されていることを前提としています。 SQL の手順には、行フィルター関数を作成し、それをテーブルに適用する例が含まれています。

カタログ エクスプローラー

  1. Azure Databricks ワークスペースで、カタログ アイコン [カタログ] をクリックします。
  2. フィルター処理するテーブルを参照または検索します。
  3. [概要] タブで、[行フィルター: フィルターの追加] をクリックします。
  4. [行フィルターの追加] ダイアログで、フィルター関数を含むカタログとスキーマを選択し、関数を選択します。
  5. 展開されたダイアログで、関数定義を表示し、関数ステートメントに含まれる列と一致するテーブル列を選択します。
  6. 追加をクリックします。

テーブルからフィルターを削除するには、[fx 行フィルター] をクリックし、[削除] をクリックします。

SQL

行フィルターを作成して既存のテーブルに追加するには、CREATE FUNCTION を使用して ALTER TABLE を使用する関数に適用します。 CREATE TABLE を使用してテーブルを作成するときに、関数も適用できます。

  1. 行フィルターを作成します。

    CREATE FUNCTION <function_name> (<parameter_name> <parameter_type>, ...)
    RETURN {filter clause whose output must be a boolean};
    
  2. 列名を使用するテーブルに行フィルターを適用します。

    ALTER TABLE <table_name> SET ROW FILTER <function_name> ON (<column_name>, ...);
    

その他の構文例:

  • 関数パラメーターと一致する定数リテラルを使用して、行フィルターをテーブルに適用します。

    ALTER TABLE <table_name> SET ROW FILTER <function_name> ON (<constant_literal>, ...);
    
  • テーブルから行フィルターを削除します。

    ALTER TABLE <table_name> DROP ROW FILTER;
    
  • 行フィルターを変更します。

    Run a DROP FUNCTION statement to drop the existing function, or use CREATE OR REPLACE FUNCTION to replace it.
    
  • 行フィルターを削除します。

    ALTER TABLE <table_name> DROP ROW FILTER;
    DROP FUNCTION <function_name>;
    

    Note

    関数をドロップする前に ALTER TABLE ... DROP ROW FILTER コマンドを実行する必要があります。 そうしないと、テーブルはアクセスできない状態になります。

    このようにテーブルにアクセスできなくなった場合は、ALTER TABLE <table_name> DROP ROW FILTER; を使ってテーブルを変更し、孤立した行フィルターの参照を削除します。

ROW FILTER 句も参照してください。

行フィルターの例

この例では、US リージョン内のグループ admin のメンバーに適用される SQL ユーザー定義関数を作成します。

このサンプル関数を sales テーブルに適用すると、admin グループのメンバーはテーブル内のすべてのレコードにアクセスできます。 管理者以外のユーザーがこの関数を呼び出すと、RETURN_IF 条件が失敗し、region='US' 式が評価され、US リージョン内のレコードのみを表示するようにテーブルがフィルター処理されます。

CREATE FUNCTION us_filter(region STRING)
RETURN IF(IS_ACCOUNT_GROUP_MEMBER('admin'), true, region='US');

この関数を、行フィルターとしてテーブルに適用します。 sales テーブルからの後続のクエリは、行のサブセットを返すようになります。

CREATE TABLE sales (region STRING, id INT);
ALTER TABLE sales SET ROW FILTER us_filter ON (region);

行フィルターを無効にします。 今後の sales テーブルからのユーザー クエリは、テーブル内のすべての行を返すようになります。

ALTER TABLE sales DROP ROW FILTER;

CREATE TABLE ステートメントの一部として、関数が行フィルターとして適用されたテーブルを作成します。 今後の sales テーブルからのクエリは、それぞれ行のサブセットを返すようになります。

CREATE TABLE sales (region STRING, id INT)
WITH ROW FILTER us_filter ON (region);

列マスクの適用

列マスクを適用するには、関数 (UDF) を作成し、それをテーブル列に適用します。

カタログ エクスプローラーまたは SQL コマンドを使用して列マスクを適用できます。 カタログ エクスプローラーの手順は、既に関数を作成し、それが Unity Catalog に登録されていることを前提としています。 SQL の手順には、列マスク関数を作成し、それをテーブル列に適用する例が含まれています。

カタログ エクスプローラー

  1. Azure Databricks ワークスペースで、カタログ アイコン [カタログ] をクリックします。
  2. テーブルを参照または検索します。
  3. [概要] タブで、列マスクを適用する行を見つけ、[編集] アイコン [マスク] 編集アイコンをクリックします。
  4. [列マスクの追加] ダイアログで、フィルター関数を含むカタログとスキーマを選択し、関数を選択します。
  5. 展開されたダイアログで、関数定義を表示します。 関数に、マスクされる列の他にパラメーターが含まれている場合は、それらの追加関数パラメーターをキャストするテーブル列を選択します。
  6. 追加をクリックします。

テーブルから列マスクを削除するには、表の行で [fx 列マスク] をクリックし、[削除] をクリックします。

SQL

列マスクを作成して既存のテーブル列に追加するには、CREATE FUNCTION を使用し、ALTER TABLE を使用してマスク関数を適用します。 CREATE TABLE を使用してテーブルを作成するときに、関数も適用できます。

マスク機能を適用するには SET MASK を使用します。 MASK 句内では、Azure Databricks の任意の組み込みランタイム関数を使ったり、他のユーザー定義関数を呼び出したりできます。 一般的なユース ケースとしては、current_user( ) を使って関数を実行している呼び出し元ユーザーの ID を調べたり、is_account_group_member( ) を使って所属しているグループを調べたりする場合などがあります。 詳細については、「列マスク句」と「組み込み関数」を参照してください。

  1. 列マスクを作成します。

    CREATE FUNCTION <function_name> (<parameter_name> <parameter_type>, ...)
    RETURN {expression with the same type as the first parameter};
    
  2. 既存のテーブルの列に列マスクを適用します。

    ALTER TABLE <table_name> ALTER COLUMN <col_name> SET MASK <mask_func_name> USING COLUMNS <additional_columns>;
    

その他の構文例:

  • 関数パラメーターと一致する定数リテラルを使用して、既存のテーブルの列に列マスクを適用します。

    ALTER TABLE <table_name> ALTER COLUMN <col_name> SET MASK <mask_func_name> USING COLUMNS (<constant_name>, ...);
    
  • テーブル内の列から列マスクを削除します。

    ALTER TABLE <table_name> ALTER COLUMN <column where mask is applied> DROP MASK;
    
  • 列マスクの変更: 既存の関数を DROP するか、CREATE OR REPLACE TABLE を使います。

  • 列マスクを削除します。

    ALTER TABLE <table_name> ALTER COLUMN <column where mask is applied> DROP MASK;
    DROP FUNCTION <function_name>;
    

    Note

    関数を削除する前に、ALTER TABLE コマンドを実行する必要があります。そうしないと、テーブルにアクセスできない状態になります。

    このようにテーブルにアクセスできなくなった場合は、ALTER TABLE <table_name> ALTER COLUMN <column where mask is applied> DROP MASK; を使ってテーブルを変更し、孤立したマスク参照の参照を削除します。

列マスクの例

この例では、ssn 列をマスクするユーザー定義関数を作成し、HumanResourceDept グループのメンバーであるユーザーのみがその列の値を表示できるようにします。

CREATE FUNCTION ssn_mask(ssn STRING)
  RETURN CASE WHEN is_member('HumanResourceDept') THEN ssn ELSE '***-**-****' END;

新しい関数を列マスクとしてテーブルに適用します。 列マスクは、テーブルの作成時に追加することも、作成後に追加することもできます。

--Create the `users` table and apply the column mask in a single step:

CREATE TABLE users (
  name STRING,
  ssn STRING MASK ssn_mask);
--Create the `users` table and apply the column mask after:

CREATE TABLE users
  (name STRING, ssn STRING);

ALTER TABLE users ALTER COLUMN ssn SET MASK ssn_mask;

このテーブルに対するクエリは、クエリ元ユーザが HumanResourceDept グループのメンバーでない場合、マスクされた ssn 列値を返すようになりました。

SELECT * FROM users;
  James  ***-**-****

クエリが ssn 列の元の値を返すように列マスクを無効にするには、次のようにします。

ALTER TABLE users ALTER COLUMN ssn DROP MASK;

マッピング テーブルを使ってアクセス制御リストを作成する

行レベルのセキュリティを実現する場合は、マッピング テーブル (またはアクセス制御リスト) を定義することを検討してください。 各マッピング テーブルは、元のテーブルのどのデータ行に特定のユーザーまたはグループがアクセスできるかをエンコードした包括的なマッピング テーブルです。 マッピング テーブルは、直接の結合によってファクト テーブルと簡単に統合できるため便利です。

この手法は、カスタム要件のある多くのユース ケースに対処する場合に役立ちます。 以下に例を示します。

  • ログインしているユーザーに基づいて制限を課しながら、特定のユーザー グループに対するさまざまなルールに対応する。
  • さまざまなルールのセットを必要とする複雑な階層を作成する (組織構造など)。
  • 外部ソース システムから複雑なセキュリティ モデルを再現する。

この方法でマッピング テーブルを採用することで、これらの困難なシナリオに効果的に取り組み、堅牢な行レベルと列レベルのセキュリティの実装を確保できます。

マッピング テーブルの例

マッピング テーブルを使って、現在のユーザーがリストに含まれているかどうかを確認します。

USE CATALOG main;

新しいマッピング テーブルを作成します。

DROP TABLE IF EXISTS valid_users;

CREATE TABLE valid_users(username string);
INSERT INTO valid_users
VALUES
  ('fred@databricks.com'),
  ('barney@databricks.com');

新しいフィルターを作成します。

Note

すべてのフィルターは定義者の権限で実行されます。ただし、ユーザー コンテキストをチェックする関数 (CURRENT_USER 関数や IS_MEMBER 関数など) は呼び出し元として実行されます。

この例では、関数は現在のユーザーが valid_users テーブルに存在するかどうかを確認します。 ユーザーが見つかった場合、関数は true を返します。

DROP FUNCTION IF EXISTS row_filter;

CREATE FUNCTION row_filter()
  RETURN EXISTS(
    SELECT 1 FROM valid_users v
    WHERE v.username = CURRENT_USER()
);

次の例では、テーブルの作成時に行フィルターを適用しています。 後で ALTER TABLE ステートメントを使ってフィルターを追加することもできます。 テーブル全体に適用する場合は、ON () 構文を使います。 特定の行の場合は、ON (row); を使います。

DROP TABLE IF EXISTS data_table;

CREATE TABLE data_table
  (x INT, y INT, z INT)
  WITH ROW FILTER row_filter ON ();

INSERT INTO data_table VALUES
  (1, 2, 3),
  (4, 5, 6),
  (7, 8, 9);

テーブルからデータを選択します。 ユーザーが valid_users テーブルに存在する場合にのみ、データが返されるはずです。

SELECT * FROM data_table;

列の値に関係なく、テーブル内のすべての行を表示するアクセス権を常に持つアカウントで構成されるマッピング テーブルを作成します。

CREATE TABLE valid_accounts(account string);
INSERT INTO valid_accounts
VALUES
  ('admin'),
  ('cstaff');

次に、行内のすべての列の値が 5 未満の場合、または呼び出し元のユーザーが上記のマッピング テーブルのメンバーである場合に true を返す SQL UDF を作成します。

CREATE FUNCTION row_filter_small_values (x INT, y INT, z INT)
  RETURN (x < 5 AND y < 5 AND z < 5)
  OR EXISTS(
    SELECT 1 FROM valid_accounts v
    WHERE IS_ACCOUNT_GROUP_MEMBER(v.account));

最後に、この SQL UDF を行フィルターとしてテーブルに適用します。

ALTER TABLE data_table SET ROW FILTER row_filter_small_values ON (x, y, z);

サポートと制限事項

行フィルターと列マスクは、一部の Azure Databricks の機能やコンピューティング リソースではサポートされていません。 このセクションにサポートされている機能と制限事項の一覧を示します。

サポートされている機能と形式

このサポートされている機能の一覧は、すべてを網羅しているわけではありません。 一部の項目は、パブリック プレビュー中はサポートされていなかったため掲載されています。

  • SQL ワークロード用の Databricks SQL と Databricks ノートブックがサポートされています。

  • MODIFY 特権を持つユーザーによる DML コマンドがサポートされています。 フィルターとマスクは、UPDATE ステートメントと DELETE ステートメントによって読み取られるデータに適用され、書き込まれるデータ (INSERT を含む) には適用されません。

  • サポートされるデータ形式:

    • マネージド テーブルと外部テーブル用の Delta と Parquet。
    • Lakehouse フェデレーションを使用して Unity Catalog に登録された外部テーブルの他の複数のデータ形式。
  • ポリシー パラメーターには定数式 (文字列、数値、間隔、ブール値、null) を指定できます。

  • SQL UDF、Python UDF、Scala UDF は、Unity Catalog に登録されている限り、行フィルター関数または列マスク関数としてサポートされます。 Python UDF と Scala UDF は SQL UDF でラップする必要があります。

  • 列マスクや行フィルターを参照するビューをテーブルに作成することはできますが、列マスクや行フィルターをビューに追加することはできません。

  • Delta Lake の変更データ フィードは、スキーマがターゲット テーブルに適用される場合のある行フィルターと列マスクと互換性がある限り、サポートされます。

  • 外部テーブルがサポートされています。

  • テーブル サンプリングがサポートされています。

  • MERGE ステートメントは、ソース テーブル、ターゲット テーブル、またはその両方で行フィルターと列マスクを使用している場合にサポートされます。 これには、単純なサブクエリを含む行フィルター関数を持つテーブルも含まれますが、次のセクションで説明する制限事項があります。

  • Databricks SQL の具体化されたビューと Databricks SQL のストリーミング テーブルでは、行フィルターと列マスク (パブリック プレビュー) がサポートされます。

    • Databricks SQL の具体化されたビューやストリーミング テーブルに行フィルターと列マスクを追加できます。
    • Databricks SQL 具体化されたビューまたはストリーミング テーブルは、行フィルターと列マスクを含むテーブルで定義できます。

パフォーマンスに関する考慮事項

行フィルターと列マスクは、フィルター操作とマスキング操作の前にユーザーがベース テーブルの値の内容を表示できなくすることで、データの可視性を保証します。 これらは、最も一般的なユース ケースでのクエリに対して適切に動作するように設計されています。 クエリ エンジンがクエリ パフォーマンスを最適化することと、フィルター処理/マスクされた値から情報が漏洩するのを防ぐことのどちらかを選択する必要がある頻度の低いアプリケーションでは、クエリ パフォーマンスに何らかの影響を与えることと引き換えに、常に安全性を重視した決定を行います。 このパフォーマンスへの影響を最小限に抑えるには、次の原則を適用します。

  • 単純なポリシー関数を使用する: 一般的に、式の数が少ないポリシー関数のほうが、より複雑な式よりも優れたパフォーマンスを発揮します。 単純な CASE 関数を優先し、マッピング テーブルや式サブクエリを使用することは避けてください。
  • 関数の引数の数を減らす: Azure Databricks では、ポリシー関数の引数に起因するソース テーブルへの列がクエリで使用されていなくても、そのような列参照を最適化できません。 引数の数が少ないポリシー関数を使用します。そのようなテーブルからのクエリのほうが、一般的に優れたパフォーマンスを発揮するためです。
  • AND 結合が多すぎる行フィルターの追加を避ける: 各テーブルで追加できる行フィルターは 1 つのみであるため、AND を使用して必要とする複数のポリシー関数を組み合わせる方法が一般的です。 ただし、各結合に関して、このテーブルの他の場所で言及されている、パフォーマンス (マッピング テーブルの使用など) に影響を与える可能性があるコンポーネントが結合に含まれる可能性が高くなります。 パフォーマンスを向上させるには、使用する結合の数を減らしてください。
  • テーブル ポリシーやそのようなテーブルからのクエリにエラーをスローできない決定論的な式を使用する: ANSI 除算などの一部の式では、指定された入力が無効な場合にエラーがスローされることがあります。 このような場合、SQL コンパイラでは、フィルター操作やマスキング操作の前に値に関する情報を明らかにする "ゼロ除算" のようなエラーが発生する可能性を回避するために、クエリ プランでそのような式を使用する操作 (フィルターなど) をプッシュ ダウンしすぎないようにする必要があります。 決定論的でエラーを絶対にスローしない式 (この例の try_divide など) を使用してください。
  • テーブルに対してテスト クエリを実行してパフォーマンスを測定する: 行フィルターや列マスクが適用されたテーブルで予期されるワークロードを表す現実的なクエリを構築し、そのパフォーマンスを測定します。 ポリシー関数に小さな変更を加え、フィルター処理とマスク ロジックのパフォーマンスと表現力のバランスが取れるまで、その効果を観察します。

制限事項

  • バージョン 12.2 LTS より前の Databricks Runtime では、行フィルターや列マスクはサポートされていません。 これらのランタイムは安全に失敗します。つまり、これらのランタイムのサポートされていないバージョンからテーブルにアクセスしようとすると、データは返されません。
  • Delta Sharing は、行レベルのセキュリティや列マスクでは機能しません。
  • 行レベル セキュリティや列マスクをビューに適用することはできません。
  • タイム トラベルは、行レベルのセキュリティや列マスクでは機能しません。
  • ポリシーを含むテーブル内のファイルへのパスベースのアクセスは、サポートされていません。
  • 元のポリシーに戻る循環依存関係がある行フィルターまたは列マスクのポリシーは、サポートされていません。
  • ディープ クローンとシャロー クローンはサポートされていません。
  • MERGE ステートメントは、関数の入れ子化、集計関数、ウィンドウ関数、制限関数、または非決定性関数を含む行フィルター ポリシーを持つテーブルをサポートしていません。
  • Delta Lake API はサポートされていません。

シングルユーザーのコンピューティングの制限

Databricks Runtime 15.3 以前のシングル ユーザー コンピューティング リソースから、行フィルターまたは列マスクを含むテーブルにアクセスすることはできません。 Databricks Runtime 15.4 LTS 以降では、"ワークスペースでサーバーレス コンピューティングが有効になっている" 場合、シングル ユーザー アクセス モードを使用できます。 詳細については、「シングル ユーザー コンピューティングに対するきめ細かなアクセス制御」を参照してください。