メインコンテンツへジャンプ

Databricks Unity Catalog による行レベルおよび列レベルのセキュリティの一般提供開始のお知らせ

行フィルターと列マスクを使用したテーブルのセキュリティの提供
Share this post

AWSAzureGCP上の Unity Catalog で行フィルターと列マスクが一般提供されることをお知らせします。テーブル内の行と列に対するきめ細かなアクセス制御を管理することは、データセキュリティを確保し、コンプライアンスを満たすために不可欠です。 Unity Catalog を使用すると、標準の SQL 関数を使用して行フィルターと列マスクを定義し、行と列に対するきめ細かいアクセス制御が可能になります。 行フィルターを使用すると、組織内のグループとユーザーの階層に表示されるテーブルの行のサブセットを制御できます。 列マスクを使用すると、同じディメンションに基づいてテーブルの値を編集できます。

「Unity Catalog のおかげで、データ資産の統一されたビューを作成できるようになり、BlackBerry 内のチーム間のコラボレーションが簡素化されました。 現在、アクセス権限を管理し、レイク内のファイルまたはテーブルを監査するための標準的なアプローチがあり、行と列に対するきめ細かなアクセス制御を定義することができます。 自動化されたデータリネージにより、データの出所を確認して潜在的な脅威の発生源を正確に特定し、どの研究プロジェクトやチームが脅威検出のためにデータを活用しているかを把握できるようになりました」
— Justin Lai 氏、Blackberry 社、ディスティングイッシュト データ アーキテクト

このブログでは、行フィルターと列マスクを使用してきめ細かいアクセス制御を有効にする方法について説明します。

大まかなオブジェクトレベルのセキュリティとは?

この発表の前に、Unity Catalog はすでにオブジェクト レベルのセキュリティをサポートしていました。 たとえば、テーブルや関数などのセキュリティ保護可能なオブジェクト に対して GRANT および REVOKE SQL コマンドを使用して、それらの検査、クエリ、または変更を許可するユーザーとグループを調整できます。

USE CATALOG main;
CREATE SCHEMA accounts;
CREATE TABLE accounts.purchase_history(
  amount_cents BIGINT,
  region STRING,
  payment_type STRING,
  purchase_date DATE DEFAULT CURRENT_DATE())
USING DELTA;

account_teamへの読み取りアクセスを許可できます。

GRANT SELECT ON TABLE accounts.purchase_history TO accounts_team;

これで、account_teampurchase_historyテーブルをクエリするアクセス権を持ちます (ただし、変更はできません)。

異なるグループ間でデータのサブセットを共有するための従来のアプローチ

しかし、リージョンごとに別々のアカウント チームがある場合はどうなるでしょうか?

戦略の一つは、動的ビューの使用です。 特定のユーザーまたはグループによる使用を目的としたビューを定義できます。

CREATE VIEW accounts.purchase_history_emea
AS SELECT amount_cents, payment_type, purchase_date
FROM accounts.purchase_history
WHERE IS_ACCOUNT_GROUP_MEMBER('EMEA');

GRANT SELECT ON VIEW accounts.purchase_history_emea
TO accounts_team_emea;

これにはデータのコピーは含まれませんが、ユーザーがEMEAリージョンの場合はaccounts.purchase_history_emeaに、APACリージョンの場合はaccounts.purchase_history_apacにクエリすることなどを覚えておく必要があります。

管理者の観点では、動的ビューには特定のケースに対して有効な提案価値があります。 ただし、この例では、いくつかの制約が適用されます。

  • クエリに制限されており、ビュー内でデータを挿入または更新できません
  • 各リージョンに対して多数のビューを作成および維持する必要があります
  • 共有SQLロジックは、異なるリージョンのチーム間で再利用するのが面倒です
  • カタログエクスプローラが煩雑になります

上記に加えて、動的ビューでは、参照されたテーブルからスキャンされ、ビュー内でフィルター処理または集計された行の値を検出するダウンストリーム ユーザーからの保護は提供されません。 たとえば、ユーザーは、クエリ オプティマイザーがビュー評価自体内でこれらの操作をプッシュダウンすることを意図して、特定の列値に応答してエラーをスローする WHERE 句を作成できます。

最後の手段として、データのサブセットを別のテーブルにコピーし、それに応じて権限を設定する日次ジョブを作成することもできます。

-- Create a table for data from the EMEA region and grant
-- read access to the corresponding accounts group.
CREATE TABLE accounts.purchase_history_emea(
  amount_cents INT,
  payment_type STRING,
  purchase_date DATE DEFAULT CURRENT_DATE())
USING DELTA;

GRANT SELECT ON TABLE accounts.purchase_history_emea TO accounts_team_emea;

-- Run this daily to update the custom table.
-- Use the previous day to make sure all the data is available before
-- copying it.
INSERT INTO accounts.purchase_history_emea
SELECT * EXCEPT (region) FROM accounts.purchase_history
WHERE region = 'EMEA' AND purchase_date = DATE_SUB(CURRENT_DATE(), 1);

このアプローチはクエリのニーズに効果的に対応しますが、欠点があります。 データを複製することで、ストレージとコンピュートの使用量が増加します。 また、重複したデータは元のデータよりも遅れるため、古くなってしまいます。 さらに、このソリューションは、ユーザー権限が制限されているため、プライマリ テーブルへの書き込みアクセスを制限し、クエリのみに対応します。

行フィルターの概要

行フィルタを使用すると、テーブルに述語を適用して、特定の条件を満たす行のみが後続のクエリで返されるようにすることができます。

各行フィルターは、SQL ユーザー定義関数 (UDF) として実装されます。 まず、アクセスを制御するターゲット テーブルの列と同じ型のブール結果を持つSQL UDFを記述します。

一貫性を保つために、この目的のためのテーブルとして、前のaccounts.purchase_historyregion列を引き続き使用しましょう。

CREATE FUNCTION accounts.purchase_history_row_filter(region STRING)
RETURN CASE
  WHEN IS_ACCOUNT_GROUP_MEMBER('emea') THEN region = 'EMEA'
  WHEN IS_ACCOUNT_GROUP_MEMBER('admin') THEN TRUE
  ELSE FALSE
END;

このロジックをテストするには、ターゲットテーブルに対していくつかのクエリを実行し、関数を直接適用します。 accounts_team_emeaグループのユーザーの場合、次のようなクエリになります。

SELECT amount_cents,
  region,
  accounts.purchase_history_row_filter(region) AS filtered 
FROM accounts.purchase_history;

+--------------+--------+----------+
| amount_cents | region | filtered |
+--------------+--------+----------+
| 42           | EMEA   | TRUE     |
| 1042         | EMEA   | TRUE     |
| 2042         | APAC   | FALSE    |
+--------------+--------+----------+

または、最初にアクセス制御ロジックを設定しているadminグループ内のユーザーの場合、テーブルのすべての行が返されることがわかります。

SELECT amount_cents, region, purchase_history_row_filter(region) AS filtered 
FROM accounts.purchase_history;

+--------------+--------+----------+
| amount_cents | region | filtered |
+--------------+--------+----------+
| 42           | EMEA   | TRUE     |
| 1042         | EMEA   | TRUE     |
| 2042         | APAC   | TRUE     |
+--------------+--------+----------+

これで、このロジックをポリシー関数としてターゲット テーブルに適用し、accounts_team_emeaグループへの読み取りアクセスを許可する準備が整いました。

ALTER TABLE accounts.purchase_history
SET ROW FILTER accounts.purchase_history_row_filter ON (region);

GRANT SELECT ON TABLE accounts.purchase_history TO accounts_team_emea;

または、作成時にこのポリシーをテーブルに直接割り当てて、テーブルが存在するがポリシーがまだ適用されていない期間がないようにすることもできます。

CREATE TABLE accounts.purchase_history_emea(
  amount_cents INT,
  payment_type STRING,
  purchase_date DATE DEFAULT CURRENT_DATE())
USING DELTA
WITH ROW FILTER purchase_history_row_filter ON (region);

GRANT SELECT ON TABLE accounts.purchase_history TO accounts_team_emea;

その後、テーブルからクエリを実行すると、上記のテストの結果に対応する行のサブセットが返されます。 たとえば、accounts_team_emeaメンバーは次の結果を受け取ります。

SELECT amount_cents, region FROM accounts.purchase_history;

+--------------+--------+
| amount_cents | region |
+--------------+--------+
| 42           | EMEA   |
| 1042         | EMEA   |
+--------------+--------+

しかし、テーブルに新しいデータを書き込む場合はどうでしょうか。 accounts.purchase_history動的ビューの場合、これは不可能です。 一方こちらは、行フィルターを持つテーブルなので、必要に応じて SQL を使用して新しい行を挿入できます。

INSERT INTO accounts.purchase_history(amount_cents, region)
VALUES (1043, 'EMEA');

SELECT amount_cents, region FROM accounts.purchase_history;

+--------------+--------+
| amount_cents | region |
+--------------+--------+
| 42           | EMEA   |
| 1042         | EMEA   |
| 1043         | EMEA   |
+--------------+--------+

同じaccounts.purchase_historyを共有できるようになりました データをコピーしたり、名前空間に多くの新しい名前を追加したりすることなく、異なるグループを持つテーブルを作成できます。

この情報はカタログ エクスプローラーで表示できます。 purchase_historyテーブルを見ると、行フィルターが適用されていることがわかります。

カタログエクスプローラー

行フィルターをクリックすると、ポリシー関数名が表示されます。

ポリシー機能

「表示」ボタンに従うと、機能の内容が表示されます。

機能内容

列マスクのご紹介

行フィルターを使用してテーブルにきめ細かなアクセス制御を作成して適用し、呼び出し元のユーザーがクエリ時に読み取りアクセス権を持たない行を選択的に除外する方法を示しました。 しかし、代わりに へのアクセスを制御し、一部の列の値を省略し、各行内の他の列の値をそのまま残す場合はどうでしょうか。

列マスク発表!

各列マスクは、SQL ユーザー定義関数 (UDF) として実装されます。 ただし、ブール値の結果を返す行フィルター関数とは異なり、各列マスク ポリシー関数は 1 つの引数を受け入れ、この入力引数と同じ型を返します。 たとえば、次のようにポリシーを使用して列マスクを作成し、電子メール アドレス内の PII を除外できます。

CREATE FUNCTION email_mask(email STRING)
RETURN CASE
  WHEN IS_ACCOUNT_GROUP_MEMBER('admin') THEN email
  ELSE SUBSTRING(
    SPLIT_PART(email, "@", 1), 1, 1) || "####" || "@" ||
    SPLIT_PART(email, "@", 2)
END;

ここで実行中のaccounts.purchase_historyテーブルについて、値が1000を超える場合に購入金額の列をマスクしてみましょう。

CREATE FUNCTION accounts.purchase_history_mask(amount_cents INT)
RETURN CASE
  WHEN IS_ACCOUNT_GROUP_MEMBER('admin') THEN amount_cents
  WHEN amount_cents < 1000 THEN amount_cents
  ELSE NULL
END;

現在、10 ドル以上の購入金額を確認する権限を持つのは管理者のみです。

では、ポリシー機能をテストしてみましょう。 管理者以外のユーザーには、次の情報が表示されます。

SELECT amount_cents,
  accounts.purchase_history_mask(amount_cents) AS masked,
  region
FROM accounts.purchase_history;

+--------------+--------+----------+
| amount_cents | masked | region   |
+--------------+--------+----------+
| 42           | 42     | EMEA     |
| 1042         | NULL   | EMEA     |
| 2042         | NULL   | APAC     |
+--------------+--------+----------+

ただし、管理者はすべてのデータを表示するためのアクセス権を持っています。

SELECT amount_cents,
  accounts.purchase_history_mask(amount_cents) AS masked,
  region
FROM accounts.purchase_history;

+--------------+--------+----------+
| amount_cents | masked | region   |
+--------------+--------+----------+
| 42           | 42     | EMEA     |
| 1042         | 1042   | EMEA     |
| 2042         | 2042   | APAC     |
+--------------+--------+----------+

素晴らしいですね! マスクをテーブルに適用してみましょう。

ALTER TABLE accounts.purchase_history
ALTER COLUMN amount_cents
SET MASK accounts.purchase_history_mask;

その後、テーブルからのクエリでは、上記のテストの結果に対応する特定の列の値を編集する必要があります。 たとえば、管理者以外のユーザーには、次の結果が表示されます。

SELECT amount_cents, region FROM accounts.purchase_history;

+--------------+--------+
| amount_cents | region |
+--------------+--------+
| 42           | EMEA   |
| NULL         | EMEA   |
| NULL         | APAC   |
+--------------+--------+

正しく動作します。

また、他の列の値を検査して、マスキングの決定を下すこともできます。 たとえば、購入金額の代わりに region 列を見るように関数を変更できます。

ALTER TABLE accounts.purchase_history ALTER COLUMN amount_cents DROP MASK;

CREATE FUNCTION accounts.purchase_history_region_mask(
  amount_cents INT,
  region STRING)
RETURN CASE
  WHEN IS_ACCOUNT_GROUP_MEMBER('admin') THEN amount_cents
  WHEN region = 'APAC' THEN amount_cents
  ELSE NULL
END;

ここで、 USING COLUMNS句を使用してマスクを適用し、ポリシー関数に渡す追加の列名を指定できます。

ALTER TABLE accounts.purchase_history
ALTER COLUMN amount_cents
SET MASK accounts.purchase_history_mask
USING COLUMNS (region);

その後、テーブルからのクエリでは、管理者以外の特定の列の値を異なる方法で編集する必要があります。

SELECT amount_cents, region FROM accounts.purchase_history;

+--------------+--------+
| amount_cents | region |
+--------------+--------+
| NULL         | EMEA   |
| NULL         | EMEA   |
| 2042         | APAC   |
+--------------+--------+

マスクは、カタログエクスプローラーのテーブル列で確認できます。

カタログエクスプローラー

以前と同様に、「表示」ボタンに従うと、関数の内容が表示されます。

機能内容

アクセス制御リストをマッピングテーブルに保存する

行フィルターおよび列マスク ポリシー関数は、ほとんどの場合、現在のユーザーを参照して、許可されたユーザーのリストと比較するか、許可されたグループの明示的なリストに対してそのグループのメンバーシップを確認する必要があります。 これらのユーザーおよびグループの許可リストをポリシー関数自体にリストすることは、適切なサイズのリストの場合に有効です。 リストが大きい場合や、ユーザーまたはグループ自体の ID がユーザーから見えないようにさらに確実にしたい場合には、代わりにマッピング テーブルを利用できます。

これらのマッピング テーブルはパーソナライズされたゲートキーパーのように機能し、元のテーブルでユーザーまたはグループがアクセスできるデータ行を決定します。 マッピングテーブルの優れた点は、ファクトテーブルとのシームレスな統合にあり、データセキュリティ戦略をより効果的にします。

このアプローチは、さまざまなカスタム要件に対するゲームチェンジャーです。

  • カスタマイズされたユーザー アクセス: ユーザー グループに特定のルールを適用しながら、個々のユーザー プロファイルに基づいて制限を課すことができます。 これにより、各ユーザーには必要な内容のみが表示されるようになります。
  • 複雑な階層の処理: 複雑な組織構造であろうと、多様なルールセットであろうと、マッピングテーブルは複雑さをナビゲートし、データアクセスが独自の階層に準拠していることを確認できます。
  • シームレスな外部モデルレプリケーション: 外部ソース システムからの複雑なセキュリティ モデルのレプリケーションが簡単になります。 マッピングテーブルは、これらの複雑なセットアップを手間なくミラーリングするのに役立ちます。

例をいくつかご紹介します。

CREATE TABLE accounts.purchase_history_groups
AS VALUES ('emea'), ('apac') t(group);

CREATE OR REPLACE FUNCTION accounts.purchase_history_row_filter(region STRING)
RETURN EXISTS(SELECT 1 FROM accounts.purchase_history_groups phg
WHERE IS_ACCOUNT_GROUP_MEMBER(phg.group));

これにより、ポリシー関数自体を複雑にすることなく、accounts.purchase_history_groupsテーブルを多数のグループに拡張でき、さらに、そのテーブルの行へのアクセスを、accounts.purchase_history_row_filter SQL UDFを作成した管理者のみに制限することができます。

レイクハウスフェデレーションでの行および列レベルのセキュリティの使用

レイクハウスフェデレーションにより、 Unity Catalogデータ管理の重要な課題を解決し、組織が異種データ システムを処理する方法を簡素化します。 これにより、構造化データと非構造化データの両方を含むデータ資産全体の統一されたビューを作成できるようになり、データソースに関係なくすべてのユーザーが安全にアクセスして探索できるようになります。 単一のエンジンで効率的なクエリとデータの組み合わせが可能になり、データ取り込みを必要とせずにさまざまなデータ分析とAIアプリケーションを高速化します。 さらに、データ セキュリティのための一貫した権限モデルを提供し、アクセス ルールを適用して、さまざまなプラットフォーム間でコンプライアンスを確保します。

ここで発表されたきめ細かいアクセス制御は、レイクハウスフェデレーション テーブルとシームレスに連携し、さまざまなグループに対するカスタムの行および列レベルのアクセス ポリシーを使用して、組織内のフェデレーション テーブルへのアクセスの共有をサポートします。 カタログにデータをコピーしたり、重複または類似のテーブル/ビュー名を多数作成したりする必要はありません。

たとえば、既存の MySQL データベースへのフェデレーション接続を作成できます。 次に、カタログ エクスプローラーを参照してフォーリンカタログを調べます。

フォーリンカタログ

カタログ内には、 mysql_demo_nyc_pizza_rating テーブルがあります。

mysql デモ

カタログ

そのテーブルに行フィルターを適用してみましょう。

ALTER TABLE mysql_catalog.qf_mysql_demo_database.mysql_demo_nyc_pizza_rating 
SET ROW FILTER main.accounts.purchase_history_row_filter ON (name);

後でテーブルの概要を見ると、変更が反映されています。

mysqlの

行フィルターをクリックすると、以前と同様に関数の名前が表示されます。

MySQL テーブル

これで、このフェデレーション MySQL テーブルに対するクエリは、各呼び出しユーザーの ID とグループ メンバーシップに応じて、異なる行のサブセットを返します。 私たちは、きめ細かいアクセス制御をレイクハウスフェデレーションと統合することに成功し、その結果、同じ組織内のDelta LakeとMySQLテーブルの使いやすさと統一されたガバナンスが実現しました。

行および列レベルのセキュリティの概要

行フィルターと列マスクを使用すると、データ管理を合理化し、過剰なETLパイプラインとデータ コピーを排除できるようになります。 これは、統合データ セキュリティの新しい世界への入り口であり、制御を維持し、機密情報が保護された状態を保ちながら、複数のユーザーやグループと自信を持ってデータを共有できます。

行フィルターと列マスクの使用を開始するには、 AWSAzureGCPに関するドキュメントをご覧ください。 行フィルターと列マスクを使用してテーブルをクエリするワークロードを、どの UC コンピュートでも実行できます: サーバレス、共有アクセス モード、シングルユーザー アクセス モード (DBR 15.4 以降)

Databricks 無料トライアル

関連記事

Unity Catalogのオープンソース化を発表します!

Translation Review by saki.kitaoka Unity Catalogのオープンソース化を発表できることを非常に嬉しく思います。 これは、クラウド、データ形式、データプラットフォーム全体でデータとAIのガバナンスを行う業界初のオープンソースカタログです。ここでは、Unity Catalogビジョンの最も重要な柱をご紹介します: オープンソースのAPIと実装: OpenAPI仕様に基づいて構築され、Apache 2.0ライセンスのもとでオープンソースのサーバー実装があります。Apache HiveのメタストアAPIやApache IcebergのRESTカタログAPIとも互換性があります。 マルチフォーマットサポート: 拡張性があり、Delta Lake、UniForm経由のApache Iceberg、Apache Parquet、CSVなど、すべての形式をサポートします。 マルチエンジンサポート: オープンAPIを使用して、Unityにカタログされたデータはほぼすべてのコンピュートエン

Data + AI Summit 2024:Databricks Unity Catalogの最新情報

Translation Review by saki.kitaoka 急速に進化する人工知能とデータやジェネレーティブAIツールの爆発的な増加が特徴の時代において、企業はデータとAIのガバナンスの断片化に直面しており、データとAIの民主化の努力が妨げられています。この時代に成功するためには、企業はデータとAIのガバナンスにおいてオープンで統一されたアプローチを採用する必要があります。これには次のことが含まれます: オープンな接続性: データの出所や形式に関係なく、すべてのデータの信頼できる単一の情報源を作成する。 統一されたガバナンス: すべてのデータ(ファイル、テーブル)およびAI資産(MLモデル、AIツール、ノートブック)が中央システムで発見され、安全に管理され、監視され、追跡されるように包括的な監督を実施する。 オープンなアクセシビリティ: データとAIリソースにどのツール、コンピュートエンジン、プラットフォームからでもアクセスできる柔軟性を提供し、ロックインを回避するためにオープンスタンダードとインターフ

Unity Catalogでの発見を加速!新しくなったカタログエクスプローラーの魅力

日々のやり取りを効率化するために改良された カタログエクスプローラー が、Unity Catalog 対応のワークスペース全体で利用できるようになりました。 カタログ エクスプローラーは、 Unity Catalog での検出とガバナンスのプロセスを一元的に管理するツールとして機能し、すべてのデータとAIアセットを検索して管理できます。 このブログでは、カタログ エクスプローラー エクスペリエンスの 5 つの主要な更新内容 (新しいクイック アクセス エクスペリエンス、合理化されたナビゲーション、更新された資産概要ページ、リネージ保持の向上、エンティティ リレーションシップ ダイアグラム) について説明します。 クイックアクセスエクスペリエンスの更新 新しいクイックアクセスセクションで簡単に作業に戻ることができます。...
プラットフォームブログ一覧へ