ちょっとハマりました。
行フィルターと列マスクは行・列レベルでアクセス制御できる便利な機能です。個人的には、ロジックを柔軟に列に適用できる列マスクの方がお気に入りです。ただ、マスキングという処理を考えると、正規表現を比較的楽に活用できるPythonを使いたいと思うのが人情です。(SQLでも使えますが)
マニュアルには以下の記載があります。
行フィルターは SQL ユーザー定義関数 (UDF) として定義され、SQL UDF にラップされた場合は Python または Scala ロジックを組み込むこともできます。行フィルターは、テーブルごとに適用することも、管理タグを使用して ABAC ポリシーを通じて一元的に適用することもできます。
Python使えるじゃん!となって試してみました。
最初に以下のようなPythonの正規表現を使用する関数を定義します。
%sql
CREATE OR REPLACE FUNCTION email_mask(email STRING)
RETURNS STRING
LANGUAGE PYTHON
AS
$$
import re
return re.sub(r'^[^@]+', lambda m: '*' * len(m.group()), email)
$$;
マスキングのロジックを適用する方法は手動によるものと、属性ベースでの適用(ABAC)の2種類あります。
今回は手動で列マスクを適用してみました。しかし、以下のエラー。
Your request failed with status FAILED: [BAD_REQUEST] [ROUTINE_NOT_FOUND] The routine
abac
.dbdemos
.email_mask
cannot be found. Verify the spelling and correctness of the schema and catalog. If you did not qualify the name with a schema and catalog, verify the current_schema() output, or qualify the name with the correct schema and catalog. To tolerate the error on drop use DROP ... IF EXISTS. SQLSTATE: 42883
セレクターに表示される関数を選択したのに存在しないとは禅問答?
いろいろ調べてみたら、鍵は最初のマニュアルの記載にありました。
行フィルターは SQL ユーザー定義関数 (UDF) として定義され、SQL UDF にラップされた場合は Python または Scala ロジックを組み込むこともできます。行フィルターは、テーブルごとに適用することも、管理タグを使用して ABAC ポリシーを通じて一元的に適用することもできます。
SQL UDFにラップされている必要があります。上の関数はこちらにあるようにPython UDFでしかなかったのでした。
正解はこちらです。新たにSQL UDFを作成し、その中で上のPython UDFを呼び出す形となります。特定のユーザーのみにマスキングするようにsession_userを用いた条件を追加しています。
CREATE OR REPLACE FUNCTION abac.dbdemos.email_mask_sql(email STRING)
RETURN CASE
WHEN session_user() = "takaaki.yayoi@databricks.com" THEN abac.dbdemos.email_mask(email)
ELSE email
END;
このSQL UDFを選択することでPythonロジックをマスキングロジックとして適用することができます。
このように@
の前のみがマスキングされていることを確認できます。
まとめ
SQL UDFでラッピングするというのは、PythonのUDFを呼び出すSQL UDFを定義するということです。マニュアルチームにもわかりにくいことフィードバックしておきました。