0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Databricksにおける属性ベースアクセスコントロール(ABAC)

0
Posted at

先ほどこちらの記事を翻訳しました。中ではデモ用のリポジトリが紹介されていました。

こちらのデモリポジトリをウォークスルーしてみます。

00 - Setup

ワークスペースファイルからデータを読み込んでテーブルを作成するので、サーバレスコンピュートではなくクラシックコンピュートを使います。

事前準備

ABACベータ版を有効にするには、以下の手順を実施してください:

  • ワークスペース管理者として、Databricksワークスペースの上部バーでユーザー名をクリックします。
  • メニューから「プレビュー」を選択します。
  • 「属性ベースアクセス制御(ABAC)」のトグルをオンにします。

制限事項

ABACプレビュー段階では、以下の制限があります:

  • テーブルのMODIFY権限を持つユーザーが、ASSIGNタグポリシー権限を持たなくても、管理タグが付与されたカラムを削除できます。これによりテーブル構造が変更され、該当カラムに紐づくABACポリシーが無効になる可能性があります。
  • ABACベータはワークスペース単位で有効化されます。ベータが有効化されていないワークスペースからカタログにアクセスした場合、ABACポリシーは強制されません。
  • 必要なDelta Sharing権限を持つユーザーは、ABACポリシーで保護されたテーブルをDelta共有できます。ポリシーは受信者のアクセスを制御しません。
  • ビューはサポートされていません。
  • 外部カタログはサポートされていません。
  • マテリアライズドビューとストリーミングテーブルはサポートされていません。
  • オブジェクト階層内の特定のカラムや行に対して、複数のカラムマスクや行フィルターを同時に適用することはできません。複数適用するとテーブルにアクセスできなくなる場合があります。
  • ABACはAWS GovCloudやFedRAMP moderate準拠コントロールが有効なワークスペースではサポートされていません。
dbutils.widgets.removeAll()
dbutils.widgets.text("catalog", "takaakiyayoi_catalog")
dbutils.widgets.text("database", "abac")
dbutils.widgets.text("volume", "input")
## 必要に応じてこれらの変数を変更してください

catalog = dbutils.widgets.get("catalog")
database = dbutils.widgets.get("database")
volume = dbutils.widgets.get("volume")

print(f"{catalog}.{database}")
# 現在のノートブックパスを取得
current_path = dbutils.notebook.entry_point.getDbutils().notebook().getContext().notebookPath().get()

# 現在のパスを表示
display(current_path)
'/Users/takaaki.yayoi@databricks.com/abac-demo/notebooks/00 - Setup'

PII(個人情報)を含むデータセットの読み込み

# データセットのファイルパスを作成
file_path = f"file:/Workspace/{current_path}/../../data/pii_dataset.csv"

# データを読み込み、表示
df = spark.read.csv(f"{file_path}", header=True, inferSchema=True)
df.display()
# テーブルとして保存
df.write.saveAsTable(f"{catalog}.{database}.students")

Screenshot 2025-09-05 at 13.40.06.png

電話番号の列があること、.govで終わるアドレスがあることを覚えておいてください。

データ分類の有効化(オプション)

データ分類機能は、カタログ内のテーブルを自動的に分類・タグ付けします。分類結果は、下流のポリシーで行レベル・カラムレベルのセキュリティ(ABAC)を強制するためのタグとして利用できます。

data-classification-details-tab.png

手順:

  • この機能はUIから有効化できます
  • 現時点ではプログラムから有効化できません

制限事項:

  • ビューはサポートされていません
  • Delta Sharingカタログはサポートされていません
  • サポートされる分類クラスは限定的ですが、今後拡張予定(カスタムも含む)

出典: https://learn.microsoft.com/ja-jp/azure/databricks/lakehouse-monitoring/data-classification

classes.png

今回は次のノートブックで手動で付与するのでこの手順はスキップしています。

01 - Apply tags and policies

%python
dbutils.widgets.removeAll()
%python
dbutils.widgets.text("catalog", "takaakiyayoi_catalog")
dbutils.widgets.text("database", "abac")
dbutils.widgets.text("warehouse_id", "23ed98665852ebad")
dbutils.widgets.text("client_id", "1234")
%python
## 必要に応じてこれらの変数を変更してください

catalog = dbutils.widgets.get("catalog")
database = dbutils.widgets.get("database")
warehouse_id = dbutils.widgets.get("warehouse_id")
client_id = dbutils.widgets.get("client_id")

print(f"{catalog}.{database}")

タグの作成と適用(任意)

データ分類を有効にしている場合は、このステップをスキップして「ポリシー(ABAC)の作成」に進んでください。

SET TAG ON COLUMN ${catalog}.${database}.students.name `class.name`;
SET TAG ON COLUMN ${catalog}.${database}.students.username `class.name`;
SET TAG ON COLUMN ${catalog}.${database}.students.address `class.location`;
SET TAG ON COLUMN ${catalog}.${database}.students.phone `class.phone_number`;
SET TAG ON COLUMN ${catalog}.${database}.students.email `class.email_address`;

SQLクエリーには$パラメーターが含まれています。パラメーターマーカー構文に移行と言ったメッセージが出てきますが、現状は問題なく動きますのでこのままにします。:param構文への移行が推奨されていますが、この構文ではこの後の関数定義に対応できません。

カタログエクスプローラでテーブルにアクセスするとタグを確認できます。
Screenshot 2025-09-05 at 13.10.24.png

マスキング関数の作成

-- 入力値を完全にマスクした値で返す関数
CREATE FUNCTION ${catalog}.${database}.mask_phone(value STRING)
RETURN '***-**-****' ;
-- pubsec(公共部門)職員の行を非表示にする関数
CREATE OR REPLACE FUNCTION ${catalog}.${database}.pubsec_email(email STRING)
RETURNS BOOLEAN
RETURN NOT LOWER(email) like '%.gov'

動作確認します。

SELECT ${catalog}.${database}.pubsec_email('roger@pubsec.gov')

.govで終わるメールアドレスの場合はfalseになります。

Screenshot 2025-09-05 at 13.46.37.png

SELECT ${catalog}.${database}.mask_phone('123-45-6789')

Screenshot 2025-09-05 at 13.47.47.png

ポリシーの作成

ABACルールのテスト用サービスプリンシパル(SP)の作成

%python
import time

from databricks.sdk import WorkspaceClient, AccountClient
from databricks.sdk.service import iam

w = WorkspaceClient()
a = AccountClient()

spn = w.service_principals.create(
    display_name=f"sp-abac-demo-{catalog}",
    groups=[],
)

spn
%python
spn_id = spn.application_id
spn_id
'737b8711-bd51-4bc2-8ecb-06152123efcc'

SPのIDをウィジェットにコピー&ペースト

SELECT :spn_id

これでSQLからSPを操作できるようになります。

Screenshot 2025-09-05 at 13.47.47.png

GRANT SELECT ON SCHEMA ${catalog}.${database} TO `${spn_id}`;
GRANT USAGE ON SCHEMA ${catalog}.${database} TO `${spn_id}`;
CREATE POLICY hide_pii_rows
ON TABLE ${catalog}.${database}.students
COMMENT 'Hide rows from pubsec employees'
ROW FILTER ${catalog}.${database}.pubsec_email
TO `${spn_id}`
FOR TABLES
MATCH COLUMNS
  hasTag('class.email_address') AS email_address
USING COLUMNS (email_address);
CREATE POLICY mask_information
ON TABLE ${catalog}.${database}.students
COMMENT 'Mask phone numbers'
COLUMN MASK ${catalog}.${database}.mask_phone
TO `${spn_id}`
FOR TABLES
MATCH COLUMNS
  hasTag('class.phone_number') as phone_number
ON COLUMN phone_number;

hasTagでタグclass.email_addressclass.phone_numberが付与されているカラムをターゲットにしているところが肝です。これによって、タグとユーザーの組み合わせでアクセスコントロールを適用することができます。

これでテーブルに対するタグポリシーが定義されます。

Screenshot 2025-09-05 at 13.24.39.png

SHOW POLICIES ON TABLE ${catalog}.${database}.students;
Policy Name Policy Type Catalog Schema Table Comment
hide_pii_rows ROW_FILTER takaakiyayoi_catalog abac students Hide rows from pubsec employees
mask_information COLUMN_MASK takaakiyayoi_catalog abac students Mask phone numbers

現在のユーザーでデータを選択

カラム・行フィルターは適用されません。

SELECT * FROM ${catalog}.${database}.students

政府関係者のレコードと電話番号がそのまま表示されています。
Screenshot 2025-09-05 at 13.51.34.png

テスト

サービスプリンシパルでテストします。

サービスプリンシパル用のクライアントシークレット作成

サービスプリンシパル用のクライアントシークレットを作成してください。

  • 設定 → Identity and access → Service principals → Secrets
  • クライアントIDをウィジェットにコピー&ペースト
  • クライアントシークレットは値入力時にコピー&ペースト

Screenshot 2025-09-05 at 13.25.28.png
Screenshot 2025-09-05 at 13.26.13.png

%python
client_id = dbutils.widgets.get("client_id")
client_id
'737b8711-bd51-4bc2-8ecb-06152123efcc'

SPでの認証に使用するクライアントシークレットを入力します。

%python
import getpass

client_secret = getpass.getpass("Enter service principal oauth secret: ")
print("Secret received.")

元のソースですとクエリー結果を取得できるまで待っていなかったので修正しています。あと、サービスプリンシパルがSQLウェアハウスにアクセスできるように使用可能の権限を付与する必要があります。

%python
import pandas as pd
from databricks.sdk import WorkspaceClient
import time

# 実際のサービスプリンシパルの詳細に置き換えてください
workspace_url = dbutils.notebook.entry_point.getDbutils().notebook().getContext().apiUrl().get()

# サービスプリンシパル認証でWorkspaceClientを初期化
w = WorkspaceClient(
    host=workspace_url,
    client_id=client_id,
    client_secret=client_secret
)

# 実行するクエリを定義
query = f"SELECT * FROM {catalog}.{database}.students"

# execute_statementを使用してクエリを実行
# ウェアハウスID
statement_response = w.statement_execution.execute_statement(query, warehouse_id)
#print(statement_response)

# クエリの実行が完了するまで待機
while statement_response.status.state == 'PENDING':
    time.sleep(5)  # 5秒待機
    statement_response = w.statement_execution.get_statement(statement_response.statement_id)

if statement_response.result:
    # ステートメントレスポンスからデータ配列を抽出
    data_array = statement_response.result.data_array or []

    if data_array:
        # データ配列をpandas DataFrameに変換
        df = pd.DataFrame(data_array)

        # DataFrameを表示
        display(df)
    else:
        print("クエリは空のデータセットを返しました。")
else:
    print("クエリの実行に失敗しました。")

govを含むメールアドレスの行が表示されていないこと、phone_numberの列がマスキングされていることがわかります。
Screenshot 2025-09-05 at 13.58.02.png

はじめてのDatabricks

はじめてのDatabricks

Databricks無料トライアル

Databricks無料トライアル

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?