Snowflake Apache Iceberg™ table における  Secure Data Sharing 機能を試してみた

## 概要

Snowflake での Apache Iceberg™ テーブルにおける Secure Data Sharing（データ共有）機能について検証し、その結果と検証コードを共有します。本記事では、同じ Snowflake リージョン内の 1 つ以上のアカウントへデータを直接共有する機能を対象としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/2a46f06d-b2be-4e32-91c0-326977d36203.png)

出所：[Secure Data Sharingについて | Snowflake Documentation](https://docs.snowflake.com/ja/user-guide/data-sharing-intro)

Iceberg テーブルに対して「FUTURE TABLE」で権限を付与しようとするとエラーとなるため、新規で作成したテーブルには、その都度権限を付与する必要があります。共有元アカウント（プロバイダー）で、共有にテーブルを追加する際の手順でこの挙動を確認できます。

> 003503: SQL compilation error: Future grant on objects of type TABLE to SHARE is restricted.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/3ae4c6fe-8ee1-4990-b859-c552eda93c8d.png)

本記事は「SnowflakeにおけるApache Iceberg機能の完全ガイド」シリーズの一部です。  
Apache Iceberg機能の全体像やSnowflake上での活用方法について詳しく知りたい方は、以下の記事をご覧ください。

- [SnowflakeにおけるApache Icebergの機能完全ガイド：Apache Iceberg on Snowflake 活用の第一歩 #Spark - Qiita](https://qiita.com/manabian/items/7ba563b614e8ae016cca)

## 環境準備

### Snowflake Catalog 環境の準備

以下の記事で紹介している環境構築手順を、事前に完了しておいてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/5a727271-1090-4694-bf8c-b2a493fd0e56.png)

出所：[Snowflake Catalog における Iceberg テーブルの基本的な操作手順 #Spark - Qiita](https://qiita.com/manabian/items/69761bde791d0f014246)

### Snowflake Open Catalog のアカウントを作成

まず、ORGADMIN ロールに切り替えます。

```sql
-- ORGADMIN にカレントロールを変更
USE ROLE ORGADMIN;
SELECT CURRENT_ROLE();
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/4375b4e5-b01c-4bd8-ac02-57987160fa47.png)

Snowflake Open Catalog が有効な Snowflake アカウントを新規で作成します。

```sql
-- データ共有先の Snowflake アカウントを作成
-- ToDo EMAIL と REEGION をかえる必要あり
CREATE ACCOUNT manabian_comsumer_01_account
   ADMIN_NAME = 'comsumer_admin'
   ADMIN_PASSWORD = 'MySecurePassword2025!'
   EMAIL = 'admin@example.com'
   MUST_CHANGE_PASSWORD = FALSE
   EDITION = ENTERPRISE
   REGION = 'AZURE_EASTUS2';
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/883211f2-e689-4faf-87ba-898cb52d0e2b.png)

次に、Snowflake Open Catalog が有効なアカウントの URL を取得します。

```sql
-- カウントの URL を取得
SHOW ACCOUNTS LIKE 'manabian_comsumer_01_account';
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/d639b85c-da0f-4d1e-9ba5-c57690b783ec.png)

上記で作成したアカウントにログインします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/9c5191bb-b019-4f80-ac51-7d1e84fe3145.png)

ワークスペースで以下のクエリを実行して、`Data Sharing Account Identifier` の値を取得します。必要に応じて、クラスタを作成してください。

```sql
SELECT
    CURRENT_ORGANIZATION_NAME() || '.' || CURRENT_ACCOUNT_NAME() AS "Data Sharing Account Identifier";
```

---

## データベースおよびテーブルの作成

### データベースを作成

```sql
CREATE OR REPLACE DATABASE data_sharing_db;
USE DATABASE data_sharing_db
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/9dd14360-b1b2-4418-9ae5-35cb547babc9.png)

### テーブルの作成

標準テーブルと Iceberg テーブルを作成します。

```sql
-- 標準テーブルの作成
CREATE OR REPLACE TABLE nation_standard 
    AS
    SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF10.NATION;
```

```sql
-- Iceberg テーブルの作成
CREATE OR REPLACE ICEBERG TABLE nation_iceberg 
    CATALOG = 'SNOWFLAKE'
    EXTERNAL_VOLUME = 'my_azure_sf_volume'
    BASE_LOCATION = 'nation_iceberg'
    AS
    SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF10.NATION;
```

```sql
SHOW TABLES IN DATABASE data_sharing_db;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/1542a23a-d957-4a0e-b81b-4914929158e8.png)

## 直接共有の実施

### 共有元アカウント（プロバイダー）で共有の作成と権限付与

まず、共有（SHARE）を作成します。

```sql
CREATE OR REPLACE SHARE iceberg_share;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/34a5d580-094b-43d6-89dd-7f232251cd45.png)

次に、共有に対してデータベースとスキーマの USAGE 権限を付与します。

```sql
GRANT USAGE ON DATABASE data_sharing_db TO SHARE iceberg_share;
GRANT USAGE ON SCHEMA data_sharing_db.public TO SHARE iceberg_share;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/a4781d00-2c67-4835-93ba-974cb92acdd3.png)

続けて、テーブルに対して SELECT 権限を付与します。標準テーブルと Iceberg テーブルでは権限付与方法が異なる点に注意してください。

```sql
-- 標準テーブルの権限を付与
GRANT SELECT ON ALL TABLES IN DATABASE data_sharing_db
    TO SHARE iceberg_share;
```

```sql
-- Iceberg テーブルの権限付与
GRANT SELECT ON ALL ICEBERG TABLES IN DATABASE data_sharing_db
    TO SHARE iceberg_share;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/c96c3612-b9f2-4caf-85c0-94a4ab7062b5.png)

FUTURE TABLE を用いた権限付与はエラーとなります。

```sql
-- 今後作成される標準テーブルの権限を付与
GRANT SELECT ON FUTURE  TABLES IN DATABASE data_sharing_db
    TO SHARE iceberg_share;
-- Iceberg テーブルの権限付与
GRANT SELECT ON FUTURE ICEBERG TABLES IN DATABASE data_sharing_db
    TO SHARE iceberg_share;
```

> 003503: SQL compilation error: Future grant on objects of type TABLE to SHARE is restricted.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/3ae4c6fe-8ee1-4990-b859-c552eda93c8d.png)

付与済みの権限を確認します。

```sql
SHOW GRANTS TO SHARE iceberg_share;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/2c804aaf-051a-4ba2-bb7a-bbba4535716a.png)

共有先アカウントを追加します。

```sql
-- 共有先アカウントで取得した Data Sharing Account Identifier の値をセット
SET data_sharing_account_identifier = 'MTIRXWM.MANABIAN_COMSUMER_01_ACCOUNT';
ALTER SHARE iceberg_share
    ADD ACCOUNTS = $data_sharing_account_identifier;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/4eb7a8bb-cf82-4c5e-b772-4e4603233366.png)

### 共有先アカウント（コンシューマー）にて共有を使ったデータベースの作成

まず、共有先アカウントで有効な共有を表示し、`iceberg_share` が存在することを確認します。

```sql
SHOW SHARES;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/4af19ca7-09c7-4123-8b86-1da9d426c0e7.png)

下記のクエリで `owner_account_and_name` 列の値を確認します。

```sql
SHOW SHARES;
SELECT
    CONCAT($3, '.', $4) AS owner_account_and_name
    ,$3 AS owner_account
    ,$4 AS name
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()));
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/269db25d-8272-4180-9b1e-7a65c3bccd20.png)

`iceberg_share` の `owner_account_and_name` 列の値をもとに共有の詳細を確認します。

```sql
DESC SHARE MTIRXWM.ZJA50722.ICEBERG_SHARE;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/15b65eea-a5a3-433e-940d-ebbd5fba3edd.png)

取得した `owner_account_and_name` を使用してデータベースを作成します。

```sql
CREATE OR REPLACE DATABASE ICEBERG_SHARE_01_DB
    FROM SHARE MTIRXWM.ZJA50722.ICEBERG_SHARE;
USE DATABASE ICEBERG_SHARE_01_DB;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/21c21d2a-35cc-4a45-ad9e-690a90452da2.png)

作成したデータベースにテーブルが含まれていることを確認します。

```sql
SHOW TABLES IN DATABASE ICEBERG_SHARE_01_DB;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/f2e5ae1f-8e30-4d2d-9cd5-0fa1ceaed6b9.png)

テーブルに対してクエリを発行できることを確認します。

```sql
SELECT
    *
    FROM
        NATION_STANDARD
    LIMIT
        3;
```

```sql
SELECT
    *
    FROM
        NATION_ICEBERG
    LIMIT
        3;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/120d494b-d14f-42c1-8a4c-596937e6c639.png)

## 共有元アカウント（プロバイダー）でのテーブル追加

### 新規テーブル作成後に共有へ権限付与

共有元アカウント（プロバイダー）で新しいテーブルを作成します。

```sql
-- Iceberg テーブルの作成
CREATE OR REPLACE ICEBERG TABLE customer_iceberg
    CATALOG = 'SNOWFLAKE'
    EXTERNAL_VOLUME = 'my_azure_sf_volume'
    BASE_LOCATION = 'custmer_iceberg'
    AS
    SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF10.CUSTOMER;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/6732e716-b8c0-4c49-83dd-03c4cd260125.png)

作成したテーブル `customer_iceberg` が、まだ共有に含まれていないことを確認します。

```sql
SHOW GRANTS TO SHARE iceberg_share;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/fcfe67de-a718-412f-ab6e-b68b87b3696a.png)

全ての Iceberg テーブルを共有に追加し、`customer_iceberg` が共有に追加されたことを確認します。

```sql
-- Iceberg テーブルの権限付与
GRANT SELECT ON ALL ICEBERG TABLES IN DATABASE data_sharing_db
    TO SHARE iceberg_share;
SHOW GRANTS TO SHARE iceberg_share;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/35f930a5-ddae-49d5-9d31-f991c4f9cf70.png)

### 共有先アカウント（コンシューマー）でのクエリ実行

最後に、共有先アカウント（コンシューマー）で新たに追加された `customer_iceberg` テーブルに対するクエリが可能であることを確認します。

```sql
SELECT
    *
    FROM
        CUSTOMER_ICEBERG
    LIMIT
        3;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/ce524936-5fa0-466c-96bc-27b1fac662ad.png)