行フィルターと列マスクを使用した機密テーブルデータのフィルター処理
この記事では、行フィルター、列マスク、マッピングテーブルを使用してテーブル内の機密データをフィルターするためのガイダンスと例を紹介します。これらの機能を利用するには、Unity Catalogが必要です。
行フィルターとは
行フィルターを使用すると、テーブルにフィルターを適用して、クエリーがフィルター条件を満たす行のみを返すようにすることができます。行フィルターは、SQL ユーザー定義関数 (UDF) として実装します。Python および Scala UDF もサポートされていますが、SQL UDF にラップされている場合に限ります。
列マスクとは
列マスクを使用すると、テーブル列にマスキング機能を適用できます。 マスキング関数は、クエリの実行時に評価され、ターゲットカラムの各参照をマスキング関数の結果で置き換えます。 ほとんどのユースケースでは、列マスクは、呼び出し元のユーザーの ID に基づいて、元の列値を返すか、編集するかを決定します。 列マスクは、SQL UDFs、またはSQL UDFsにラップされたPythonまたはScala UDFsとして記述された式です。
各テーブル列には、マスキング関数を 1 つだけ適用できます。 マスキング関数は、列のマスクされていない値を入力として受け取り、マスクされた値を結果として返します。 マスキング関数の戻り値は、マスキングされる列と同じ型である必要があります。 マスキング関数は、追加の列を入力パラメーターとして受け取り、それらをマスキング ロジックで使用することもできます。
これらのフィルターとダイナミックビューの違い
ダイナミックビュー、行フィルター、列マスクを使用すると、複雑なロジックをテーブルに適用し、クエリーのランタイムにフィルタリングの決定を処理できます。
動的ビューは、1 つ以上のソーステーブルの抽象化された読み取り専用ビューです。ユーザーは、ソース・テーブルに直接アクセスしなくても、動的ビューにアクセスできます。 動的ビューの作成では、新しいテーブル名を定義しますが、この名前は、同じスキーマに存在するソース・テーブルや他のテーブルおよびビューの名前と一致してはなりません。
一方、行フィルターまたは列マスクをターゲット テーブルに関連付けると、新しいテーブル名を導入することなく、対応するロジックがテーブル自体に直接適用されます。後続のクエリでも引き続き、元の名前を使用してターゲット テーブルを直接参照できます。
動的ビューは、フィルターやマスクなどの変換ロジックを読み取り専用テーブルに適用する必要がある場合、およびユーザーが異なる名前を使用して動的ビューを参照することが許容される場合に使用します。 Delta Sharing を使用してデータを共有するときにデータをフィルター処理する場合は、動的ビューを使用する必要があります。 特定のデータに対してフィルターまたはコンピュート式を行いながら、ユーザーが元の名前を使用してテーブルにアクセスできるようにする場合は、行フィルターと列マスクを使用します。
始める前に
テーブルに行フィルターと列マスクを追加するには、次のものが必要です。
Unity Catalog が有効になっているワークスペース。
Unity Catalogに登録されている関数。この関数は、SQL UDF、または Unity Catalog に登録され、SQL UDF にラップされた Python または Scala UDF にすることができます。 詳細については、 ユーザー定義関数 (UDF) とは、列 マスク句、および ROW FILTER 句を参照してください。
また、次の要件を満たす必要があります。
行フィルターまたは列マスクをテーブルに追加する関数を割り当てるには、関数の
EXECUTE
権限、スキーマのUSE SCHEMA
権限、親カタログのUSE CATALOG
権限が必要です。新しいテーブルを作成するときにフィルターまたはマスクを追加する場合は、スキーマに対する
CREATE TABLE
権限が必要です。既存のテーブルにフィルターまたはマスクを追加する場合は、テーブルの所有者である必要があります。
行フィルターや列マスクのあるテーブルにアクセスするには、コンピュートリソースが次の要件のいずれかを満たしている必要があります。
A SQLウェアハウス.
Databricks Runtime 12.2 LTS 以降の共有アクセス モード。
行フィルターを適用する
行フィルターを作成するには、フィルターポリシーを定義する関数 (UDF) を記述し、それをテーブルに適用します。各テーブルに設定できる行フィルターは1つだけです。行フィルターは0個以上の入力パラメーターを受け入れます。各入力パラメーターは対応する表の1つの列にバインドされます。
行フィルタは、カタログエクスプローラまたは SQL コマンドを使用して適用できます。 Catalog Explorer の手順では、関数を既に作成し、Unity Catalog に登録していることを前提としています。 SQL 命令には、行フィルタ関数を作成し、それをテーブルに適用する例が含まれています。
Databricksワークスペースで、[カタログ] をクリックします。
フィルタリングするテーブルを参照または検索します。
[概要] タブで、[行フィルター: フィルターを追加] をクリックします。
[行フィルターを追加] ダイアログで、フィルター機能を含むカタログとスキーマを選択し、関数を選択します。
展開されたダイアログで関数定義を表示して、関数ステートメントに含まれる列と一致するテーブル列を選択します。
[追加] をクリックします。
テーブルからフィルターを削除するには、[fx行フィルター] をクリックして [削除] をクリックします。
行フィルターを作成し、それを既存のテーブルに追加するには、 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>;
注:
関数を削除する前に、
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 コマンドを使用して適用できます。 Catalog Explorer の手順では、関数を既に作成し、Unity Catalog に登録していることを前提としています。 SQL 命令には、列マスク関数を作成し、それをテーブル列に適用する例が含まれています。
Databricksワークスペースで、[カタログ] をクリックします。
テーブルを参照または検索します。
[概要] タブで列マスクを適用する行を見つけて、[マスク] 編集アイコンをクリックします。
[列マスクを追加] ダイアログで、フィルター関数を含むカタログとスキーマを選択し、関数を選択します。
展開されたダイアログで、関数定義を表示します。 関数に、マスクされる列に加えてパラメーターが含まれている場合は、それらの追加の関数パラメーターをキャストするテーブル列を選択します。
[追加] をクリックします。
テーブルから列マスクを削除するには、テーブル行のfx列マスクをクリックし、[削除] をクリックします。
列マスクを作成して既存のテーブル列に追加するには、CREATE FUNCTION
を使用し、ALTER TABLE
を使用してマスキング関数を適用します。CREATE TABLE
を使用してテーブルを作成するときに関数を適用することもできます。
SET MASK
を使用してマスキング機能を適用します。MASK
句内では、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>;
注:
関数を削除する前に
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 UDFs は、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はサポートされていません。