Unity Catalogにおけるデータのアクセス権

[Data permissions \| Databricks on AWS](https://docs.databricks.com/data-governance/unity-catalog/data-permissions.html) [2022/3/10時点]の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

本書では、Unity Catalogにおけるデータとオブジェクトに対するアクセスを制御するために、どのようにデータのアクセス権が動作するのかを説明します。

Unity Catalogのデータとオブジェクトに対するアクセスを許可・剥奪するために、Databricks SQLのData Explorer、あるいはノートブック上のSQL文、Databricks SQLのクエリー、Unity CatalogのREST APIを用いてデータアクセスコントロールポリシーを適用します。

最初は、ユーザーはメタストアのデータにアクセスできません。[メタストア管理者](https://qiita.com/taka_yayoi/items/065706136dcd2ad9df33#%E3%83%A1%E3%82%BF%E3%82%B9%E3%83%88%E3%82%A2%E7%AE%A1%E7%90%86%E8%80%85)のみがスキーマ、テーブル、ビュー、その他のUnity Catalogオブジェクトを作成することができ、それらに対する[アカウントレベルのユーザー、グループ](https://qiita.com/taka_yayoi/items/065706136dcd2ad9df33#%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%83%AC%E3%83%99%E3%83%ABid)のアクセスを許可、拒否することができます。アクセスコントロールのポリシーは継承されません。メタストアを作成したアカウントレベルの管理者がオーナーとなり、メタストア管理者となります。

お使いのクラウドテナントに対してデータを読み書きできるようになる前に、Unity Catalogによってアクセスコントロールポリシーが適用されます。

# オーナーシップ

Unity Cataloにおけるそれぞれの[セキュリティ保護可能オブジェクト](https://qiita.com/taka_yayoi/items/065706136dcd2ad9df33#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%A2%E3%83%87%E3%83%AB)には、オーナーが存在します。プリンシパルと呼ばれる任意のアカウントレベルのユーザー、グループがオーナーになることができます。オブジェクトを作成したプリンシパルが最初のオーナーになります。オブジェクトのオーナーは、テーブルに対する`SELECT`、`MODIFY`、他のプリンシパルに対するアクセス権を許可する権限など、オブジェクトに対する全ての権限を持ちます。

オブジェクトオーナーは、別のユーザー、グループにオーナーシップを移譲することができます。メタストア管理者は、メタストアのいかなるオブジェクトのオーナーシップを別のユーザー、グループに移譲することができます。

セキュリティ保護可能オブジェクトのオーナーを参照するには、以下の文法を使用します。プレースホルダーの値を置き換えてください。

- `<SECURABLE_TYPE>`: `CATALOG`や`TABLE`のようなセキュリティ保護可能オブジェクトのタイプ
- `<catalog>`: テーブルやビューに対する親のカタログ
- `<schema>`: テーブルやビューに対する親のスキーマ
- `<securable_name>`: テーブルやビューなどのセキュリティ保護可能オブジェクトの名前

```sql:SQL
DESCRIBE <SECURABLE_TYPE> EXTENDED <catalog>.<schema>.<securable_name>;
```

オブジェクトのオーナーシップを移譲するには、以下の文法のSQLコマンドを使用します。プレースホルダーの値を置き換えてください。

- `<SECURABLE_TYPE>`: `CATALOG`や`TABLE`のようなセキュリティ保護可能オブジェクトのタイプ
- `<SECURABLE_NAME>`: テーブルやビューなどのセキュリティ保護可能オブジェクトの名前
- `<PRINCIPAL>`: アカウントレベルのユーザーのメールアドレス、あるいはアカウントレーベルのグループの名前

```sql:SQL
ALTER <SECURABLE_TYPE> <SECURABLE_NAME> OWNER TO <PRINCIPAL>;
```

例えば、`accounting`グループにテーブルのオーナーシップを移譲するには以下を実行します。

```sql:SQL
ALTER TABLE orders OWNER TO `accounting`;
```

## メタストアのオーナーシップ

メタストアを作成したアカウントレベルの管理者がオーナーとなります。メタストアのオーナーシップを、異なるアカウントレベルのユーザー、グループに移譲するには、[(推奨)メタストアのオーナーシップをグループに転送する](https://qiita.com/taka_yayoi/items/3f2df6ddea81521ee786#%E6%8E%A8%E5%A5%A8%E3%83%A1%E3%82%BF%E3%82%B9%E3%83%88%E3%82%A2%E3%81%AE%E3%82%AA%E3%83%BC%E3%83%8A%E3%83%BC%E3%82%B7%E3%83%83%E3%83%97%E3%82%92%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AB%E8%BB%A2%E9%80%81%E3%81%99%E3%82%8B)を参照ください。セキュリティ強化のため、このコマンドはSQL文法では使用できません。

# 権限

Unity Catalogでは、[セキュリティ保護可能オブジェクト](https://qiita.com/taka_yayoi/items/065706136dcd2ad9df33#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%A2%E3%83%87%E3%83%AB)に対して以下の権限を許可することができます。

- `USAGE`: このアクセス権はセキュリティ保護可能なオブジェクト自身へのアクセスを許可しませんが、子供のオブジェクトにアクセスするためにセキュリティ保護可能オブジェクトを通過することを許可します。例えば、テーブルからデータを取得するためには、ユーザーは当該テーブルに対する`USAGE`権限と、親のスキーマ、親のカタログに対する`USAGE`権限を必要とします。特定のグループに対してデータの名前空間のセクションへのアクセスを制限するために、この権限を使用することができます。
- `SELECT`: テーブル、ビューからデータを読み込むことを許可します。ユーザーは親のカタログ、スキーマに対する`USAGE`権限が必要です。
- `MODIFY`: テーブルへの行追加、更新、データの削除を許可します。ユーザーは親のカタログ、スキーマに対する`USAGE`権限が必要です。
- `CREATE`: ユーザーが親のカタログに対して`USAGE`と`CREATE`権限を有しているのであれば、スキーマの作成を許可します。ユーザーが親のカタログとスキーマに対して`USAGE`権限、親のスキーマに対して`CREATE`権限を有しているのであれば、テーブル、ビューの作成を許可します。

さらに、ストレージ認証情報と外部ロケーションに対して以下のアクセス権を許可することができます。

- `CREATE TABLE`: ストレージ認証情報を用いて指定された外部ロケーションに外部テーブルを作成することを許可します。
- `READ FILES`: 外部ロケーションに関連づけられたストレージ認証情報を用いて、指定された外部ロケーションからデータファイルを読み込むことを許可します。

    ストレージ認証情報に対して直接許可をすると、ストレージ認証情報を用いてお使いのクラウドテナントから直接ファイルを読み込むことを許可します。

- `WRITE FILES`: 外部ロケーションに関連づけられたストレージ認証情報を用いて、指定された外部ロケーションにデータファイルを書き込むことを許可します。

    ストレージ認証情報に対して直接許可をすると、ストレージ認証情報を用いてお使いのクラウドテナントから直接ファイルを書き込むことを許可します。

:::note info
**注意**
ストレージ認証情報に対して`READ FILES`と`WRITE FILES`権限を許可することができますが、そうするのではなく、外部ロケーションに対してこれらのアクセス権を許可することをお勧めします。これによって、よりきめ細かいレベルでのアクセス権管理を可能とし、エンドユーザーに対してよりシンプルな体験を提供します。
:::

Unity Catalogでは、権限は子供のセキュリティ保護可能なオブジェクトには継承されません。例えば、ユーザーに対してカタログの`CREATE`権限を許可しても、ユーザーは自動ではカタログの全データベースに対する`CREATE`権限を持ちません。

以下の表では、それぞれのセキュリティ保護可能オブジェクトに許可される権限をまとめています。

| セキュリティ保護可能オブジェクト | 権限 |
|:--|:--|
|カタログ   | `CREATE`, `USAGE`  |
|スキーマ   |  `CREATE`, `USAGE` |
|テーブル   | `SELECT`, `MODIFY`  |
|ビュー   |  `SELECT` |
|外部ロケーション   | `USAGE`, `CREATE TABLE`, `READ FILES`, `WRITE FILES`  |
|ストレージ認証情報   |`USAGE`, `CREATE TABLE`, `READ FILES`, `WRITE FILES`   |

## 権限の管理

Databricks SQLのData Explorerか、Databricks SQLのSQLエディタ、Data Science & Engineeringノートブックでメタストアの権限を管理することができます。

権限を管理するには、`GRANT`と`REVOKE`文を使用します。オブジェクトのオーナーあるいはメタストア管理者のみが、オブジェクトとその子供のオブジェクトに対する権限を許可することができます。ビルトインの`account users`というアカウントレベルのグループには全てのアカウントレベルのユーザーが含まれています。

このセクションには、権限を管理するためのSQLコマンドの使用例が含まれています。Databricks SQLのData Exprolerを用いた権限管理については、[Manage access to data](https://docs.databricks.com/data-governance/unity-catalog/manage-access-to-data.html)を参照ください。

### セキュリティ保護可能オブジェクトの権限の表示

SQLを用いてオブジェクトに許可されている権限を表示するには、以下のようなコマンドを使用します。Databricks SQLのData Explorerの使い方については、[Use the Databricks SQL Data Explorer](https://docs.databricks.com/data-governance/unity-catalog/manage-access-to-data.html#show-grants-data-explorer)をご覧ください。

以下の文法を使用します。プレースホルダーの値を置き換えてください。

- `<securable_type>`: カタログやテーブルのようなセキュリティ保護可能オブジェクトのタイプ
- `<securable_name>`: セキュリティ保護可能オブジェクトの名前

```sql:SQL
SHOW GRANTS ON <securable_type> <securable_name>;
```

オブジェクトに対する特定のプリンシパルに許可された全ての権限を表示するには、以下の文法を使用します。プレースホルダーの値を置き換えてください。

- `<principal>`: アカウントレベルユーザーのメールアドレスか、アカウントレベルグループの名前
- `<securable_type>`: カタログやテーブルのようなセキュリティ保護可能オブジェクトのタイプ
- `<securable_name>`: セキュリティ保護可能オブジェクトの名前

```sql:SQL
SHOW GRANTS <principal> ON <securable_type> <securable_name>;
```

### 権限の許可

SQLを用いて権限を許可するには、以下のようなコマンドを使用します。Databricks SQLのData Explorerの使い方については、[Use the Databricks SQL Data Explorer](https://docs.databricks.com/data-governance/unity-catalog/manage-access-to-data.html#show-grants-data-explorer)をご覧ください。

以下の文法を使用します。プレースホルダーの値を置き換えてください。

- `<privilege>`: `SELECT`や`USAGE`のような許可する権限
- `<securable_type>`: カタログやテーブルのようなセキュリティ保護可能オブジェクトのタイプ
- `<securable_name>`: セキュリティ保護可能オブジェクトの名前
- `<principal>`: アカウントレベルユーザーのメールアドレスか、アカウントレベルグループの名前

```sql:SQL
GRANT <privilege> ON <securable_type> <securable_name> TO <principal>
```

### 権限の剥奪

SQLを用いて権限を剥奪するには、以下のようなコマンドを使用します。Databricks SQLのData Explorerの使い方については、[Use the Databricks SQL Data Explorer](https://docs.databricks.com/data-governance/unity-catalog/manage-access-to-data.html#show-grants-data-explorer)をご覧ください。

以下の文法を使用します。プレースホルダーの値を置き換えてください。

- `<privilege>`: `SELECT`や`USAGE`のような許可する権限
- `<securable_type>`: カタログやテーブルのようなセキュリティ保護可能オブジェクトのタイプ
- `<securable_name>`: セキュリティ保護可能オブジェクトの名前
- `<principal>`: アカウントレベルユーザーのメールアドレスか、アカウントレベルグループの名前

```sql:SQL
REVOKE <privilege> ON <securable_type> <securable_name> FROM <principal>
```

# ダイナミックビュー

Unity Catalogでは、以下を含むきめ細かいアクセスコントロールを設定するためのダイナミックビューを使用することができます。

- 行・列レベルでのセキュリティ
- データマスキング

:::note info
**注意**
ダイナミックビューを用いたきめ細かいアクセスコントロールは**Single User**[セキュリティモード](https://qiita.com/taka_yayoi/items/065706136dcd2ad9df33#%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%A2%E3%83%BC%E3%83%89)では利用できません。
:::

Unity Catalogでは、ユーザーがアクセスできる行、カラム、ビューのレコードを動的に制限するために、以下の関数を導入しています。

- `current_user()`: 現在のユーザーのメールアドレスを返却。
- `is_account_group_member()`: 現在のユーザーが特定のアカウントレベルグループのメンバーであれば`TRUE`を返却。Unity Catalogのデータに対するダイナミックビューでの利用を推奨。
- `is_member()`: 現在のユーザーが特定のワークスペースレベルのグループのメンバーであれば`TRUE`を返却。この関数は既存のHiveメタストアとの互換性のために提供されています。これは、アカウントレベルのグループメンバーシップを評価しないので、Unity Catalogのデータに使用するのは避けてください。

以下の例では、Unity Catalogのダイナミックビューの作成方法を説明します。

## カラムレベルのアクセス権

ダイナミックビューを用いることで、特定のユーザー、グループがアクセスできるカラムを制限することができます。以下の例では、`auditors`グループメンバーのみが`sales_raw`テーブルのメールアドレスにアクセスすることができます。クエリー分析においては、Apache Sparkは`CASE`文を`REDACTED`という文字列リテラルや実際のメールアドレスのカラムの中身で置換します。他のカラムは通常通りに返却されます。この戦略はクエリー性能にはネガティブなインパクトを及ぼしません。

```sql:SQL
-- 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
```

## 行レベルのアクセス権

ダイナミックビューをを用いることで、行やフィールドレベルでアクセス権を指定することがでできます。以下の例では、`managers`グループのメンバーのみが総額が$1,000,000を超えたトランザクションを参照することができます。この条件にマッチしたトランザクションは他のユーザーには表示されません。

```sql:SQL
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;
```

## データマスキング

Unity CatalogのビューはSpark SQLを使用しているので、より複雑なSQL表現や正規表現を用いた高度なデータマスキングを実装することができます。以下の例では、全てのユーザーはメールアドレスのドメインを分析することができますが、`auditors`グループのメンバーはメールアドレス全体を参照することができます。

```sql:SQL
-- The regexp_extract function takes an email address such as
-- user.x.lastname@example.com and extracts 'example', allowing
-- analysts to query the domain name

CREATE VIEW sales_redacted AS
SELECT
  user_id,
  region,
  CASE
    WHEN is_account_group_member('auditors') THEN email
    ELSE regexp_extract(email, '^.*@(.*)$', 1)
  END
  FROM sales_raw
```

# Unity CatalogとレガシーなHiveメタストアを一緒に使用する

Unity Catalogは加法的(additive)なものであり、Databricksのワークスペース単位のHiveメタストアと一緒に使用できることを意味します。Hiveメタストアは、3レベルの名前空間では`hive_metastore`と呼ばれるトップレベルのカタログとして表示されます。例えば、レガシーのHiveメタストアの`sales`スキーマの`sales_raw`というテーブルは、以下の記述で参照することができます。

```sql:SQL
SELECT * from hive_metastore.sales.sales_raw;
```

`USE`文を用いてカタログとスキーマを指定することができます。

```sql:SQL
USE hive_metastore.sales;
SELECT * from sales_raw;
```

## Unity CatalogとHiveメタストアにおけるアクセスコントロール

Hiveメタストアの[テーブルアクセスコントロール](https://qiita.com/taka_yayoi/items/f0b999e69b9fef5065d8)を設定しているのであれば、**User Isolation**[セキュリティモード](https://qiita.com/taka_yayoi/items/065706136dcd2ad9df33#%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%A2%E3%83%BC%E3%83%89)で稼働しているクラスターにおいては、`hive_metastore`カタログのデータに対するアクセスコントロールの強制を継続します。Unity Catalogにおけるアクセスコントロールモデルは、レガシーのアクセスコントロールと若干の差異(`DENY`文など)があります。Hiveメタストアはワークスペースレベルのオブジェクトであるため、`hive_metastore`カタログ内で定義されたアクセス権は常にワークスペースローカルのユーザー、グループを参照します。[テーブルアクセスコントロールとの違い](#テーブルアクセスコントロールとの違い)をご覧下さい。

テーブルアクセスコントロールがHiveメタストアで有効化されている場合、ワークロードでは**User Isolation**が有効化されたクラスターを使用する必要があります。SQLエンドポイントは常にこのセキュリティモードを使用します。

## テーブルアクセスコントロールとの違い

Unity Catalogはワークスペース単位のレガシー[テーブルアクセスコントロール](https://qiita.com/taka_yayoi/items/f0b999e69b9fef5065d8)とは、以下の違いがあります。

Unity Catalogのアクセスコントロールモデルは、テーブルアクセスコントロールと以下の違いがあります。

- **アカウントレベルのID**: Unity Catalogにおけるアクセスコントロールポリシーは、アカウントレベルのユーザー、グループに適用されますが、Hiveメタストアのアクセスコントロールポリシーはワークスペースレベルのユーザー、グループに適用されます。
- **簡素化されたアクセス権**: Unity Catalogには、カタログ、スキーマ、テーブルとビューに対する4つの権限(`SELECT`, `MODIFY`, `CREATE`, `USAGE`)、外部ロケーション、ストレージ認証情報固有の3つの権限(`READ_FILES`, `WRITE_FILES`, `CREATE TABLE`)しかありません。しかし、明示的にアクセス権が許可されるまでアクセスを常に拒否する`DENY`文はUnity Catalogにはありません。`READ_METADATA`や`MODIFY_CLASSPATH`といったレガシーな権限はサポートされていません。
- **権限が継承されません**: Unity Catalogでは、親のオブジェクトに対する権限は子供のオブジェクトに継承されません。
- **カタログ内のオブジェクトに対する全てのオペレーションには`USAGE`権限が必要です**: テーブルやデータベースに対するプリンシパルの権限に関係なく、プリンシパルはテーブルやデータベースにアクセスするために、親のカタログに対する`USAGE`権限を必要とします。ワークスペースレベルのアクセスコントロールでは、ルートカタログに対する`USAGE`の許可によって自動ですべてのデータベースの`USAGE`を許可しますが、ルートカタログに対する`USAGE`は必要ではありません。
- **ビュー**: Unity Catalogでは、ビューのオーナーは、ビューが参照するテーブルやビューのオーナーである必要はありません。親のスキーマとカタログに対する`USAGE`権限と`SELECT`権限を持っているだけで十分です。ワークスペースレベルのテーブルアクセスコントロールでは、ビューのオーナーは、参照するテーブルやビューのオーナーである必要があります。
- **`ALL FILES`や`ANONYMOUS FUNCTION`の未サポート**: Unity Catalogでは`ALL FILES`や`ANONYMOUS FUNCTION`権限の概念がありません。これらの権限は、許可されないユーザーがコードを実行しないようにするアクセス制限を回避する手段となり得ます。

## Join

3レベルの名前空間記述を用いることで、Unity CatalgのメタストアのデータとレガシーHiveメタストアのデータをJoinすることができます。

:::note info
**注意**
レガシーHiveメタストアのデータとのJoinはデータが格納されているワークスペースでのみ動作します。別のワークスペースでそのようなJoinを実行しようとするとエラーとなります。レガシーなテーブル、ビューをUnity Catalogに[アップグレード](https://docs.databricks.com/data-governance/unity-catalog/migrate.html)することをお勧めします。
:::

以下のサンプルでは、レガシーHiveメタストアの`sales_current`テーブルと、Unity Catalogメタストアの`sales_historical`テーブルとを`order_id`フィールドでJoinします。

```sql:SQL
SELECT * FROM hive_metastore.sales.sales_current
JOIN main.shared_sales.sales_historical
ON hive_metastore.sales.sales_current.order_id = main.shared_sales.sales_historical.order_id;
```

以下の例では、より複雑なJoinを行なっています。それぞれのテーブルには共通する顧客のレコードを少なくとも1行含むことを前提として、顧客ごとの現在と過去の売り上げの合計を返却します。

```sql:SQL
SELECT current.customer_id, current.customer_name, COALESCE(current.total, 0) + COALESCE(historical.total, 0) AS total
  FROM hive_metastore.sales.sales_current AS current
  FULL OUTER JOIN main.shared_sales.sales_historical AS historical
    ON current.customer_id = historical.customer_id;
```

## デフォルトのカタログ

トップレベルのカタログ名を省略し、`USE CATALOG`文を使用していない場合、デフォルトのカタログが選択されます。ワークスペースにおけるデフォルトカタログを設定するには`spark.databricks.sql.initial.catalog.name`の値を設定します。

既存コードの変更なしに現在のHiveメタストアで動作するように、デフォルトのカタログを`hive_metastore`に設定することをお勧めします。

## クラスターのインスタンスプロファイル

Unity CatalogとHiveメタストアを同居させる際、Hiveメタストアのデータにアクセスするためにインスタンスプロファイルが使用されますが、Unity Catalogのデータへのアクセスには使用されません。Unity Catalogはクラスターに設定されたインスタンスプロファイルには依存しません。

## レガシーテーブルのUnity Catalogへのアップデート

Hiveメタストアのテーブルは、ビルトインの監査、アクセスコントロールのように、Unity Catalogが導入するフルセットのセキュリティ、ガバナンス機能の恩恵を受けることができません。Unity Catalogに[レガシーテーブルをアップグレード](https://docs.databricks.com/data-governance/unity-catalog/migrate.html)することをお勧めします。

# 次のステップ

- [Unity Catalogを使い始める](https://qiita.com/taka_yayoi/items/3f2df6ddea81521ee786)
- [Unity Catalogのキーコンセプト](https://qiita.com/taka_yayoi/items/065706136dcd2ad9df33)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)