行フィルターと列マスクを使用して機密性の高いテーブル データをフィルター処理する
この記事では、行フィルター、列マスク、マッピング テーブルを使ってテーブル内の機密データをフィルター処理するためのガイダンスと例を示します。 これらの機能には 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) とは何か」、、「列マスク句」、および「ROW FILTER 句」を参照してください。
次の要件も満たす必要があります。
- 行フィルターや列マスクをテーブルに追加する関数を割り当てるには、関数に
EXECUTE
特権、スキーマにUSE SCHEMA
、親カタログにUSE CATALOG
が必要です。 - 新しい テーブルを作成する場合にフィルターやマスクを追加するには、スキーマの
CREATE TABLE
特権が必要です。 - 既存のテーブルにフィルターまたはマスクを追加する場合は、テーブルの所有者である必要があります。
行フィルターや列マスクがあるテーブルにアクセスするには、コンピューティング リソースが次の要件のいずれかを満たす必要があります。
- 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 の手順には、行フィルター関数を作成し、それをテーブルに適用する例が含まれています。
カタログ エクスプローラー
- Azure Databricks ワークスペースで、
[カタログ] をクリックします。
- フィルター処理するテーブルを参照または検索します。
- [概要] タブで、[行フィルター: フィルターの追加] をクリックします。
- [行フィルターの追加] ダイアログで、フィルター関数を含むカタログとスキーマを選択し、関数を選択します。
- 展開されたダイアログで、関数定義を表示し、関数ステートメントに含まれる列と一致するテーブル列を選択します。
- 追加をクリックします。
テーブルからフィルターを削除するには、[fx 行フィルター] をクリックし、[削除] をクリックします。
SQL
行フィルターを作成して既存のテーブルに追加するには、CREATE FUNCTION
を使って ALTER TABLE
を使う関数に適用します。 CREATE TABLE
を使用してテーブルを作成するときに、関数も適用できます。
行フィルターを作成します。
CREATE FUNCTION <function_name> (<parameter_name> <parameter_type>, ...) RETURN {filter clause whose output must be a boolean};
列名を使用するテーブルに行フィルターを適用します。
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 句」も参照してください。
行フィルターの例
この例では、admin
リージョン内のグループ US
のメンバーに適用される 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 の手順には、列マスク関数を作成し、それをテーブル列に適用する例が含まれています。
カタログ エクスプローラー
- Azure Databricks ワークスペースで、
[カタログ] をクリックします。
- テーブルを参照または検索します。
- [概要] タブで、列マスクを適用する行を見つけ、
[マスク] 編集アイコンをクリックします。
- [列マスクの追加] ダイアログで、フィルター関数を含むカタログとスキーマを選択し、関数を選択します。
- 展開されたダイアログで、関数定義を表示します。 関数に、マスクされる列の他にパラメーターが含まれている場合は、それらの追加関数パラメーターをキャストするテーブル列を選択します。
- 追加をクリックします。
テーブルから列マスクを削除するには、表の行で [fx 列マスク] をクリックし、[削除] をクリックします。
SQL
列マスクを作成して既存のテーブル列に追加するには、CREATE FUNCTION
を使用し、ALTER TABLE
を使用してマスク関数を適用します。 CREATE TABLE
を使用してテーブルを作成するときに、関数も適用できます。
マスク機能を適用するには SET MASK
を使用します。 MASK
句内では、Azure Databricks の任意の組み込みランタイム関数を使ったり、他のユーザー定義関数を呼び出したりできます。 一般的なユース ケースとしては、current_user( )
を使って関数を実行している呼び出し元ユーザーの ID を調べたり、is_account_group_member( )
を使って所属しているグループを調べたりする場合などがあります。 詳細については、「列マスク句」と「組み込み関数」を参照してください。
列マスクを作成します。
CREATE FUNCTION <function_name> (<parameter_name> <parameter_type>, ...) RETURN {expression with the same type as the first parameter};
既存のテーブルの列に列マスクを適用します。
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;
このテーブルに対するクエリは、クエリ元ユーザが ssn
グループのメンバーでない場合、マスクされた HumanResourceDept
列値を返すようになりました。
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 の具体化されたビューやストリーミング テーブルに行フィルターと列マスクを追加できます。 具体化されたビューまたはストリーミング テーブルが定義されている場合は、マスクの追加を宣言によって行う必要があります。 CREATE MATERIALIZED VIEW または CREATE STREAMING TABLE を参照してください。
- Databricks SQL 具体化されたビューまたはストリーミング テーブルは、行フィルターと列マスクを含むテーブルで定義できます。
Delta Live Tables で宣言されて公開された具体化されたビューとストリーミング テーブルでは、行フィルターや列マスク (パブリック プレビュー)がサポートされます。
- Delta Live Tables の具体化されたビューやストリーミング テーブルに行フィルターと列マスクを追加できます。
- 行フィルターや列マスクが設定されたテーブルに Delta Live Tables の具体化されたビューやストリーミング テーブルを定義できます。
「行フィルターと列マスクを使用してテーブルを公開する」を参照してください。
パフォーマンスに関する推奨事項
行フィルターと列マスクは、フィルター処理とマスク操作が実行されるまでユーザーがベース テーブルの値の内容を表示できないようにすることで、データの可視性を制御します。 これらは、一般的なユース ケースでのクエリに対して適切に動作します。 クエリ エンジンがクエリ パフォーマンスを最適化することと、フィルター処理/マスクされた値から情報が漏洩するのを防ぐことのどちらかを選択する必要がある、頻度の低いアプリケーションでは、クエリ パフォーマンスに何らかの影響を与えることと引き換えに、常に安全性を重視した決定を行います。 このパフォーマンスへの影響を最小限に抑えるには、次の推奨事項を適用します。
- 単純なポリシー関数を使用する: 多くの場合、式の数が少ないポリシー関数のほうが、より複雑な式よりも優れたパフォーマンスを発揮します。 単純な 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 以降 シングル ユーザー アクセス モードを使用できます。 詳細については、「 シングル ユーザー コンピューティングでの詳細なアクセス制御を参照してください。