行フィルターと列マスクを使用した機密テーブルデータのフィルター処理

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

行フィルターとは

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

列マスクとは

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

テーブルの各列には、マスキング機能を 1 つのみ適用できます。マスキング関数は、列のマスクされていない値を入力として受け取り、その結果としてマスクされた値を返します。マスキング関数の戻り値は、マスクされる列と同じタイプでなければなりません。マスキング関数は、入力パラメータとして追加の列を取り、それをマスキングロジックで使用することもできます。

これらのフィルターとダイナミックビューの違い

ダイナミックビュー、行フィルター、列マスクを使用すると、複雑なロジックをテーブルに適用し、クエリーのランタイムにフィルタリングの決定を処理できます。

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

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

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

始める前に

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

  • Unity Catalog が有効になっているワークスペース。

  • Unity Catalogに登録されている機能。これはSQL UDFでも、Unity Catalogに登録されていてSQL UDFでラップされているPythonまたはScala UDFでもかまいません。詳細については、「ユーザー定義関数 (UDF) とは」、「列マスク句」、「行フィルター句」を参照してください。

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

  • 行フィルターまたは列マスクをテーブルに追加する関数を割り当てるには、関数のEXECUTE権限、スキーマのUSE SCHEMA権限、親カタログのUSE CATALOG権限が必要です。

  • 新しいテーブルを作成するときにフィルターまたはマスクを追加する場合は、スキーマに対するCREATE TABLE権限が必要です。

  • 既存のテーブルにフィルタまたはマスクを追加する場合は、テーブルの所有者であるか、テーブルに対するMODIFY権限とSELECT権限の両方を持っている必要があります。

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

  • A SQLウェアハウス.

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

行フィルターを適用する

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

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

  1. Databricksワークスペースで、[カタログアイコンカタログ] をクリックします。

  2. フィルタリングするテーブルを参照または検索します。

  3. [概要] タブで、[行フィルター: フィルターを追加] をクリックします。

  4. [行フィルターを追加] ダイアログで、フィルター機能を含むカタログとスキーマを選択し、関数を選択します。

  5. 展開されたダイアログで関数定義を表示して、関数ステートメントに含まれる列と一致するテーブル列を選択します。

  6. [追加] をクリックします。

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

行フィルターを作成して既存のテーブルに追加するには、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>;
    

    注:

    関数を削除する前に、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. Databricksワークスペースで、[カタログアイコンカタログ] をクリックします。

  2. テーブルを参照または検索します。

  3. [概要] タブで列マスクを適用する行を見つけて、[編集アイコンマスク] 編集アイコンをクリックします。

  4. [列マスクを追加] ダイアログで、フィルター関数を含むカタログとスキーマを選択し、関数を選択します。

  5. 展開されたダイアログで、関数定義を表示します。関数にマスクされている列のほかにパラメーターが含まれている場合は、それらの追加の関数パラメーターをキャストしたいテーブルの列を選択してください。

  6. [追加] をクリックします。

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

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

SET MASKを使用してマスキング機能を適用します。MASK句内では、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>;
    

    注:

    関数を削除する前に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');

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

注:

すべてのフィルターは、呼び出し元として実行されるユーザーコンテキストをチェックする関数 (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);

サポートと制限事項

行フィルターと列マスクは、すべてのDatabricks機能、あるいはすべてのコンピュートリソースでサポートされているとは限りません。このセクションでは、サポートされている機能と制限事項を紹介します。

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

このサポートされている機能のリストは、すべてを網羅しているわけではありません。一部、パブリックプレビュー中にサポートされなかったためにリストされているアイテムもあります。

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

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

  • サポートされているデータ形式は以下の通りです。

    • マネージドテーブルと外部テーブルにはDeltaとParquetがあります。

    • レイクハウスフェデレーションを使用してUnity Catalogに登録されたフォーリンテーブルのその他の複数のデータ形式。

  • ポリシーパラメーターには、定数式(文字列、数値、区間、ブーリアン、ヌル)を含めることができます。

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

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

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

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

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

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

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

行フィルターと列マスクは、フィルタリングやマスキング操作の前にユーザーがベーステーブルの値の内容を見ることができないようにすることで、データの可視性を保証します。これらは、最も一般的な使用例でのクエリに適切に応答するように設計されています。使用例によっては稀に、クエリエンジンがクエリのパフォーマンスを最適化するか、フィルタリング/マスクされた値から情報が漏洩しないようにするかを選択する必要がありますが、クエリのパフォーマンスへの影響を犠牲にしてでも、エンジンは常に安全な決定を下します。このようなパフォーマンスへの影響を最小限に抑えるには、次の原則を適用してください。

  • シンプルなポリシー関数を使う:通常の場合、式の少ないポリシー関数の方が、複雑な式よりも優れたパフォーマンスを発揮します。マッピングテーブルや式サブクエリの使用は避け、シンプルなCASE関数を使用します。

  • 関数の引数の数を減らす:Databricksは、ポリシー関数の引数から生じる列参照をソーステーブルへ最適化することはできません。これは、当該の列がクエリで使用されていない場合でも同じです。これらのテーブルからのクエリの方が一般的にパフォーマンスに優れているため、引数の少ないポリシー関数を使用してください。

  • AND接続が多すぎる行フィルターを追加しない:各テーブルは最大1件の行フィルターの追加のみをサポートするため、複数の必要なポリシー関数を AND と組み合わせるのが一般的なアプローチです。ただし、接続詞ごとに、このテーブルの別の場所に記載されているコンポーネントでパフォーマンスに影響する可能性のあるもの(マッピングテーブルの使用など)が含まれている可能性が高くなります。パフォーマンスを向上させるには、接続詞を減らしてください。

  • テーブルポリシーおよびテーブルからのクエリでエラーをスローしない確定的な式を使用する:ANSI除算など、入力が無効な場合にエラーをスローする式もあります。このような場合、SQLコンパイラは、フィルタリングやマスキング操作の前に値に関する情報を明らかにする「ゼロ除算」などのエラーが発生する可能性を避けるために、これらの式を使った操作(フィルタリングなど)をクエリプランのかなり下の方に押し下げないようにしなければなりません。この例では、 try_divide のように、確定的でエラーをスローしない式を使用します。

  • テーブルに対してテストクエリを実行してパフォーマンスを測定する:行フィルタや列マスクを使用して、テーブルに期待される作業負荷を表す現実的なクエリを構築し、パフォーマンスを測定します。フィルタリングとマスキングロジックのパフォーマンスと表現力のバランスが取れるまでポリシー関数を少しずつ修正し、その効果を観察してください。

制限事項

  • 12.2 LTS以前のDatabricks Runtimeバージョンでは、行フィルターまたは列マスクはサポートされません。これらのランタイムは安全に失敗します。つまり、サポートされていないバージョンのランタイムのテーブルにアクセスしようとしても、データは返されません。

  • デルタ共有は、行レベルのセキュリティまたは列マスクでは機能しません。

  • ビューに行レベルのセキュリティまたは列マスクを適用することはできません。

  • タイムトラベルは、行レベルのセキュリティまたは列マスクでは機能しません。

  • ポリシーを持つテーブル内のファイルへの、パスベースのアクセスはサポートされていません。

  • 元のポリシーに戻る循環依存性を持つ行フィルターまたは列マスクポリシーはサポートされていません。

  • ディープクローン、シャロークローンはサポートされていません。

  • MERGE ステートメントは、ネスト、集計、ウィンドウ、制限、または非決定論的関数を含む行フィルターポリシーのあるテーブルをサポートしていません。

  • Delta Lake APIsはサポートされていません。

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

行フィルターまたは列マスクを持つテーブルには、単一ユーザーのコンピュート リソースからアクセスすることはできません。