背景・目的
BigQueryでは列レベルや行レベルでのアクセス制御が可能です。この記事では、Databricksでの同様のアクセス制御の実現方法とその検証結果を詳しく紹介します。
まとめ
- 列と行レベルのセキュリティを行うには、UnityCatalogで実現できる。
- Dynamic Viewでは関数が利用できる
- current_user
- is_account_group_member
- 下記は非推奨
- is_member。Hiveメタストア互換のため
- Viewで参照されているテーブルとビューを読み取る機能をユーザに付与しない
概要
DatabricksのDynamic viewを元に整理します。
Create a dynamic view
Unity Catalogでは、動的ビューを使用して、次のようなきめ細かなアクセス制御を構成できます。
- 列または行のレベルのセキュリティ。
- データマスキング
- Unity CatalogでDynamic Viewが使用できる。Dynamic Viewでは列と行のセキュリティが利用できる。
動的ビューを使用したきめ細かなアクセスコントロールは、 シングルユーザー access modeのクラスターでは使用できません。
- シングルユーザアクセスモードのクラスタでは使用できない。
Unity Catalog では、ビュー内の行、列、またはレコードにアクセスできるユーザーを動的に制限できる次の関数が導入されています。
- current_user(): 現在のユーザーの Eメール アドレスを返します。
- is_account_group_member(): 現在のユーザーが特定のアカウントレベルのグループのメンバーである場合に TRUE を返します。 Unity Catalog データに対する動的ビューでの使用をお勧めします。
- is_member(): 現在のユーザーが特定のワークスペース レベルのグループのメンバーである場合に TRUE を返します。 この関数は、既存の Hive metastoreとの互換性のために提供されています。 Unity Catalog データに対するビューでは、アカウントレベルのグループメンバーシップを評価しないため、使用しないでください。
Databricks では、ビューで参照されているテーブルとビューを読み取る機能をユーザーに付与しないことをお勧めします。
- is_memberはHive metastore互換性のため用意されている。Unity Catalogデータに対するViewでは使用しないこと。
- Databricksでは、Viewで参照されているテーブルとビューを読み取る機能をユーザに付与しない
列レベルの権限
動的ビューを使用すると、特定のユーザーまたはグループがアクセスできる列を制限できます。 次の例では、 auditors グループのメンバーのみが sales_raw テーブルから Eメール アドレスにアクセスできます。 クエリー分析中に、Apache Spark は CASE ステートメントをリテラル文字列 REDACTED または Eメール アドレス列の実際の内容に置き換えます。 他の列は通常どおり返されます。 この戦略は、クエリー のパフォーマンスに悪影響を与えません。
-- Alias the field 'email' to itself (as 'email') to prevent the
-- permission logic from showing up directly in the column name results.
CREATE VIEW sales_redacted AS
SELECT
user_id,
CASE WHEN
is_account_group_member('auditors') THEN email
ELSE 'REDACTED'
END AS email,
country,
product,
total
FROM sales_raw
- auditorsグループのときには、Eメールを返し、グループ外では、REDACTEDの文字列を返す。
行レベルの権限
動的ビューでは、行レベルまたはフィールド レベルまで権限を指定できます。 次の例では、 managers グループのメンバーのみが $1,000,000 を超えたときにトランザクション金額を表示できます。 一致する結果は、他のユーザーに対して除外されます。
CREATE VIEW sales_redacted AS
SELECT
user_id,
country,
product,
total
FROM sales_raw
WHERE
CASE
WHEN is_account_group_member('managers') THEN TRUE
ELSE total <= 1000000
END;
- managerグループであれば、レコードを表示することができ、グループ外ではtotal が100,000以下であれば表示可能
実践
前提
検証
下記のような顧客テーブルがある場合に、適切にアクセス権を付与し想定通りに制限(閲覧)できるかを確認します。
- 営業1部と営業2部の社員がアクセスできるのは、自身が担当している顧客になります。
- 全ての列にアクセスが可能ですが顧客は制限されます。
- 営業1部は、たろうさん、じろうさん、さぶろうさん
- 営業2部は、しろうさん、ごろうさん
- 全ての列にアクセスが可能ですが顧客は制限されます。
- 分析担当者は、すべての顧客にアクセスできますが、列は顧客タイプ(customer_type)、職業(job)、担当列(in_charge)に限定されます。
- 最後に、制限なしにアクセスできる管理者がいます。
シナリオは下記のとおりです。
- 営業部1と2の社員
- 担当顧客のみ閲覧が可能であること
- 担当顧客以外は閲覧ができないこと
- 分析担当
- 全てのレコードにアクセスできること
- アクセス可能な列の値を参照できること
- アクセス不可能な顧客氏名や住所が閲覧できないこと
- 管理者
- 全ての顧客のデータが参照できること
準備
グループを作成
下記のグループを作成します。
- 営業1部 : sales1
- 営業2部 : sales2
- 分析: analysis
※ 管理者はデフォルトのadminをそのまま利用します。
-
①.「Groups」タブをクリックすると、デフォルトでは、adminsとusersしかありません。②.「Add group」をクリックします。
-
グループ名「sales1」をクリックします。
-
①「Entitlements」をクリックし、②「Databricks SQL access」のEnabledをクリックします。
ユーザの作成
下記のユーザを作成します。
- 営業1部所属の社員 : sales1 employee1
- 営業2部所属の社員 : sales2 employee1
- 分析所属の社員: analysis employee1
-
Inviteメールが届くので、リンクをクリックします。
グループにユーザを追加
下記のように、グループにユーザを追加します。
グループ(論理名) | グループ | ユーザ |
---|---|---|
営業1部 | sales1 | sales1 employee1 |
営業2部 | sales2 | sales2 employee1 |
分析 | analysis | analysis1 employee1 |
テーブルとデータの作成
スキーマの作成
- 下記のDDLでスキーマを作成します。
create schema main.test
テーブルの作成
- 下記のDDLでテーブルを作成します。
CREATE TABLE test.customer ( id INTEGER ,full_name VARCHAR(90) ,address VARCHAR(300) ,customer_type VARCHAR(10) ,job VARCHAR(30) ,in_charge VARCHAR(100) )
データを作成
-
下記のDMLでデータを登録します。
INSERT INTO main.test.customer VALUES(1,'たろう','Tokyo','C1','Accountant','sales1'); INSERT INTO main.test.customer VALUES(2,'じろう','Osaka','C1','Lawyer','sales1'); INSERT INTO main.test.customer VALUES(3,'さぶろう','Fukuoka','C2','Journalist','sales1'); INSERT INTO main.test.customer VALUES(4,'しろう','Hokkaido','C2','Doctor','sales2'); INSERT INTO main.test.customer VALUES(5,'ごろう','Kyushu','C3','Engineer','sales2');
-
下記のクエリで登録されたデータを確認します。確認できました。
select * from `main`.`test`.`customer` limit 100;
検証
Dynamic View の作成
- 下記のDDLでViewを作成します。
CREATE VIEW `main`.`test`.`customer_v` AS SELECT CASE WHEN is_account_group_member('sales1') OR is_account_group_member('sales2') THEN id END AS id ,CASE WHEN is_account_group_member('sales1') OR is_account_group_member('sales2') THEN full_name END AS full_name ,CASE WHEN is_account_group_member('sales1') OR is_account_group_member('sales2') THEN address END AS address ,customer_type ,job ,in_charge FROM `main`.`test`.`customer` WHERE CASE WHEN is_account_group_member('sales1') AND in_charge = 'sales1' THEN TRUE WHEN is_account_group_member('sales2') AND in_charge = 'sales2' THEN TRUE WHEN is_account_group_member('analysis') THEN TRUE END;
権限の付与
-
下記のクエリでグループに権限を付与します。
GRANT USE SCHEMA ON SCHEMA `main`.`test` TO `sales1`; GRANT USE SCHEMA ON SCHEMA `main`.`test` TO `sales2`; GRANT USE SCHEMA ON SCHEMA `main`.`test` TO `analysis`; GRANT SELECT ON VIEW `main`.`test`.`customer_v` TO `sales1`; GRANT SELECT ON VIEW `main`.`test`.`customer_v` TO `sales2`; GRANT SELECT ON VIEW `main`.`test`.`customer_v` TO `analysis`; GRANT ALL PRIVILEGES ON VIEW `main`.`test`.`customer_v` TO `管理者ユーザ`;
-
下記のクエリで付与した権限を確認します。
SHOW GRANTS ON `main`.`test`.`customer_v`
確認
sales1ユーザで確認
-
sales1グループに所属するユーザでログインし、下記のクエリを実行し想定どおりか確認します。
SELECT is_account_group_member('sales1'),is_account_group_member('sales2'),is_account_group_member('analysis'), * FROM main.test.customer_v
sales2ユーザで確認
-
sales2グループに所属するユーザでログインし、下記のクエリを実行し想定どおりか確認します。
SELECT is_account_group_member('sales1'),is_account_group_member('sales2'),is_account_group_member('analysis'), * FROM main.test.customer_v
analysisユーザで確認
-
analysisグループに所属するユーザでログインし、下記のクエリを実行し想定どおりか確認します。
SELECT is_account_group_member('sales1'),is_account_group_member('sales2'),is_account_group_member('analysis'), * FROM main.test.customer_v
-
対象列、全行が表示されました。なお、対象外の列はNullで表示されることは意外でした。
管理者で確認
管理者は、テーブルを直接参照します。
考察
今回は、Dynamic Viewで所属するグループで行列アクセス制御を試してみました。今後は、2023/9/17現在、Public Previewの段階ですがFilter sensitive data with row filters and column masks を試してみようと思います。
参考