はじめに
私はデータ基盤の運用保守に携わっており、主にバッチ処理まわりの保守や追加開発を担っています。
結論から言うと、組織内の別アカウントへデータを共有する構成は、SQL だけでも作れます。ポイントは、共有には Share オブジェクト(共有する中身) と Listing オブジェクト(届け方の宣言) という 2 層があり、CREATE SHARE で中身を、CREATE ORGANIZATION LISTING で届け方を宣言する、という順番で組み立てることです。
この記事は、以前書いた「Snowflake Private Listing × Dynamic Table でアカウントをまたぐデータ共有を自動化する」で共有し返す部分を Snowsight(画面操作)で行った箇所を、SQL で書くとどうなるかをまとめたものです。「画面手順は将来 UI が変わって陳腐化しやすいので、いずれコード(IaC)で残したい」という動機の続きにあたります。
ひとつ大事な分岐があります。共有相手が 同じ組織(organization)内のアカウントか、別組織のアカウントか で、使うコマンドが変わります。本記事は 組織内(同一組織) のケースに絞り、CREATE ORGANIZATION LISTING を使う手順を扱います。組織外(別組織) のケースは CREATE EXTERNAL LISTING を使う別の手順になるため、別記事「Snowflakeの組織外データ共有をSQLで作る」にまとめています。まずは「自分のケースがどちらか」を見分けるところから始めます。
実案件では共有の作成自体は Snowsight(Provider Studio)で行いました。本記事の SQL は、同じことを SQL で行う場合の手順を公式ドキュメントで裏取りして整理したものです。実際に流すときは、お使いの環境・権限・組織設定に合わせてご確認ください。
前提・環境
- 共有元と共有先が、同じ組織内の別アカウントであること(相手を限定して非公開共有するケースのうち、組織内なら Organization Listing が該当します。組織外の場合は分岐して別記事の手順になります。判断方法は後述)。
- 共有する対象は Secure View(後述のとおり、Share に載せられるのは既定でセキュアオブジェクトのみ。非セキュアビューを載せるには Share 側の設定が要ります)。
- 実行するロール・権限:後述のとおり、Share と Listing を作るためのグローバル権限が必要です(オーナーロールの節で解説)。
-
組織側の事前設定:組織内リスティングを扱うには、
ORGADMINロールでプロバイダー規約に同意するなどの組織側の準備が前提です。これが済んでいないと、後段のCREATE ORGANIZATION LISTINGは通りません。手順に入る前に、組織管理者側で整っているか確認しておきます。 - SQL の実行場所:Snowsight の SQL ワークシートや
snowCLI など、通常のクエリ実行環境。
先に「オーナーロール」を決めておく
手順に入る前に、Share と Listing を「どのロールで作るか(=オーナーロール)」を先に決めておくことをおすすめします。オーナーを決めておくと、そのロールに何の権限を足せばよいかを逆算でき、手順の途中で権限不足に当たって止まる、ということが減ります。
というのも、共有・リスティング系の権限は既定で ACCOUNTADMIN にしか付いていません。データエンジニアリングで普段使う SYSADMIN などのロールには、これらの権限はありません。たとえば「SYSADMIN をオーナーにしよう」と考えても、そのままではリスティングを作成する権限がなく、CREATE ORGANIZATION LISTING が通りません。
そこで、オーナーにするロールへ、必要なグローバル権限を明示的に付与します。
-- ACCOUNTADMIN などの管理ロールで実行
GRANT CREATE SHARE ON ACCOUNT TO ROLE my_share_role;
GRANT CREATE ORGANIZATION LISTING ON ACCOUNT TO ROLE my_share_role; -- CREATE LISTING でも可
加えて、Share にオブジェクトを載せられるのは、そのオブジェクトを所有(または相応の権限を持つ)ロールです。Share の作成 → オブジェクトの付与 → Listing の作成 → 公開までを同じオーナーロールで通すと、所有関係がシンプルになり、権限まわりで迷いにくくなります。
CREATE SHARE をあるロールに渡すと、そのロールが所有するオブジェクトを共有に載せられるようになります。付与先のロールは必要な範囲に絞ってください。
用語整理:Share と Listing、そして「Private」と「Organization」
先に言葉を整理しておきます。ここがあいまいだと、SQL のどのコマンドを使うか迷います。
| オブジェクト | 役割 |
|---|---|
| Share(共有オブジェクト) | 「どのデータベース/スキーマ/ビューを共有するか」という中身。CREATE SHARE で作り、GRANT ... TO SHARE で対象を足す。 |
| Listing(リスティングオブジェクト) | その Share を「誰に・どう届けるか」という届け方の宣言。タイトルや対象アカウントなどのメタデータを持つ。Listing は Share をラップする。 |
つまり Listing は Share を包んで配る仕組みで、中身(Share)と届け方(Listing)は別レイヤです。
そのうえで、届け方(Listing)にはいくつか種類があります。
-
Direct Share:Listing を介さず、Share を直接アカウントへ渡す方式(
ALTER SHARE ... ADD ACCOUNTS)。同一リージョン限定でシンプルですが、利用状況の可視化などはありません。 -
Organization Listing:同じ組織内の特定アカウントへ、非公開で配る Listing。本記事で扱うのはこれです。SQL コマンドは
CREATE ORGANIZATION LISTING。 - Private Listing / Marketplace Listing:組織をまたいで特定の相手(Private)や広く一般(Marketplace)へ配る Listing。
「Private Listing」という言葉は、Snowsight の画面では「Specified Consumers(相手を限定)」として組織内・組織外の両方の文脈で登場します。ただし SQL で組織内に閉じて共有する場合の正確なコマンドは CREATE ORGANIZATION LISTING です。前の記事では通しで「Private Listing」と呼んでいましたが、SQL で書く段になると、組織内は Organization Listing が対応する、と押さえておくと迷いません。
最初に確認:共有相手は「組織内」か「組織外」か
ここが今回いちばん大事な分岐です。同じ Snowflake 組織(organization)内のアカウントどうしか、別組織のアカウントかで、使うコマンドが変わります。
-
組織内(同一組織) →
CREATE ORGANIZATION LISTING(本記事の手順) -
組織外(別組織) →
CREATE EXTERNAL LISTING(相手を限定した Private Listing)。手順が変わるため、別記事「Snowflakeの組織外データ共有をSQLで作る」で扱います。
「同じ会社なら組織内」とは限りません。 同一企業でも、部署ごとに別の Snowflake 組織として運用されていれば、アカウント間の共有は「組織外」になります。まず組織の境界を確認してから、どちらのコマンドを使うか決めます。
判断はシンプルで、両方のアカウントで組織名を出して、一致するかを見ます。
-- 共有元・共有先それぞれのアカウントで実行する
SELECT CURRENT_ORGANIZATION_NAME();
- 返ってきた組織名が一致すれば組織内 →
CREATE ORGANIZATION LISTING(このまま本記事を進める)。 -
異なれば組織外 →
CREATE EXTERNAL LISTING(別記事の手順)。
CURRENT_ORGANIZATION_NAME() はどのロールでも実行できます。組織全体を管理できる ORGADMIN ロールがあれば、組織内のアカウント一覧から相手が含まれるかを確認する方法もあります。
-- 組織のアカウント一覧を確認する(ORGADMIN ロール)
SHOW ACCOUNTS;
-- もしくは組織利用状況ビューから
SELECT account_name, region FROM SNOWFLAKE.ORGANIZATION_USAGE.ACCOUNTS;
以降は、組織内(同一組織)だった場合の手順を進めます。
手順①:Share を作り、共有するオブジェクトを付与する
まず「中身」である Share を作り、共有したいオブジェクトを付与します。共有するのは、前の記事で作った結合結果を主キーだけに絞った Secure View だとします。
-- 1. 空の Share を作る
CREATE SHARE my_share;
-- 2. 共有に必要なオブジェクトを、上位から順に付与する
GRANT USAGE ON DATABASE my_db TO SHARE my_share;
GRANT USAGE ON SCHEMA my_db.my_schema TO SHARE my_share;
GRANT SELECT ON VIEW my_db.my_schema.my_secure_view TO SHARE my_share;
ポイントは次のとおりです。
-
共有に載せられるのは、既定ではセキュアオブジェクト(Secure View / Secure UDF)だけです。Share は
SECURE_OBJECTS_ONLYプロパティが既定でTRUEのため、通常のビューをGRANT ... TO SHAREしようとするとエラーになります(Share data in non-secured views)。どうしても非セキュアビューを共有したい場合は、Share 作成時にSECURE_OBJECTS_ONLY = FALSEを指定します。ただし機微データの露出を避けるため、Snowflake は Secure View の共有を強く推奨しています(Use secure objects to control data access)。前の記事で結合結果を Secure View にして絞り込んだのは、この推奨とも噛み合います。 -
完全修飾名(
my_db.my_schema.my_secure_view)で指定します。 - 定義に
CURRENT_ROLEやCURRENT_USERを含む secure object は Share に含めるべきではない、と公式に注意があります。共有先で意図しない評価になり得るためです。
手順②:Organization Listing を作って公開する
次に「届け方」である Listing を作ります。CREATE ORGANIZATION LISTING は、対象アカウントなどを YAML の manifest で宣言し、その中で手順①の Share を参照します。
CREATE ORGANIZATION LISTING my_org_listing
SHARE my_share AS $$
title: "会員クロス集計(主キーのみ)"
description: "属性Aと属性B両方を持つ会員の主キー一覧。結合結果を Secure View で提供。"
organization_profile: "INTERNAL"
organization_targets:
access:
- account: "<共有先のアカウント名>"
roles:
- "<共有先で利用するロール>"
support_contact: "support@example.com"
$$;
manifest の要点です。
-
SHARE my_share:手順①で作った Share を、この Listing に紐づけます。 -
organization_profile: "INTERNAL":組織内向けのリスティングであることを示します。 -
organization_targets.access:誰がアクセスできるかを、アカウント名(と任意でロール)で指定します。trueにすると組織内の全アカウント、falseにすると誰も対象にしない、配列で書くと特定アカウントだけ、という指定になります。 -
support_contactは必須です。加えて、発見用のdiscoveryターゲットを設ける場合はapprover_contactも必須になります。 - 公開の可否は
PUBLISHパラメータ(既定はTRUE)で制御できます。既定のままなら、作成と同時に公開されます。
権限とプロバイダー規約への同意など、実行前に必要な準備は「前提・環境」にまとめました。オーナーロールへの権限付与と ORGADMIN 側の事前設定が済んでいないと、この CREATE ORGANIZATION LISTING は通りません。
Snowsight 手順 → SQL 対応表
公式ドキュメントの Snowsight 手順(Data sharing » Internal sharing から作成)が、SQL / manifest のどこに対応するかです。画面で作った場合と SQL で作った場合を対応づけておくと、既存の手順書からの移行がしやすくなります。
| Snowsight の手順 | SQL / manifest での対応 |
|---|---|
| Data sharing » Internal sharing を開く | UI 固有。SQL では CREATE ORGANIZATION LISTING 権限を持つロールで実行 |
| Create Listing → 共有する data product(share) を選択 | ... SHARE <share_name> |
| リスティング名を入力(ULL を確認) |
CREATE ORGANIZATION LISTING <name>(ULL は <org>$INTERNAL$<name>) |
| Access Control:Grant access(対象アカウント/ロール) | manifest organization_targets.access:(account と任意で roles) |
| Access Control:Allow discovery(発見を許可) | manifest organization_targets.discovery:(設定時は approver_contact も必須) |
| Description などメタデータを入力 | manifest title / description(support_contact は必須) |
| Publish |
PUBLISH = TRUE(既定 TRUE) |
| (Internal sharing なので組織内向けが前提) | manifest organization_profile: "INTERNAL"
|
手順③:共有先(消費側)でデータベースとして参照する
公開された Organization Listing は、共有先のアカウントで データベースとしてマウントすると参照できます。SQL では CREATE DATABASE ... FROM LISTING を使います。
-- 消費側アカウントで実行
CREATE DATABASE my_shared_db
FROM LISTING '<listing_global_name>';
<listing_global_name> には、組織内リスティングを一意に指す Uniform Listing Locator(ULL) を指定します。ULL は「プロバイダーの組織名」「プロバイダープロファイル INTERNAL」「リスティング名」を $ で連結した形式(例:myorg$INTERNAL$my_org_listing)です。
- マウントには、消費側アカウントで
IMPORT ORGANIZATION LISTING権限(アカウントレベル)とCREATE DATABASE権限が必要です。 - マウントせずに、ULL を使ってクエリから直接参照する方法もあります(用途に応じて選べます)。
マウント後は、共有された Secure View を通常のテーブルのように参照できます。
SELECT * FROM my_shared_db.my_schema.my_secure_view;
作成したオブジェクトを確認する
手順の途中や最後に、作った Share と Listing が意図どおりにできているかを SHOW / DESCRIBE で確認できます。オブジェクトが2層(Share と Listing)に分かれているので、それぞれを見ておくと安心です。
Share を確認する(提供側)
-- 自アカウントの Share 一覧
SHOW SHARES;
-- 特定の Share に何のオブジェクトが載っているか
DESCRIBE SHARE my_share;
-
SHOW SHARESのkind列は、自分が作って外に出している共有がOUTBOUND、他アカウントから受け取っている共有がINBOUNDです。 -
listing_global_name列を見ると、その Share がどのリスティングに紐づいているかも分かります。 -
DESCRIBE SHAREで、Share に付与したデータベース・スキーマ・Secure View が並んでいるかを確認できます。
Listing を確認する(提供側)
-- USAGE / MODIFY / OWNERSHIP を持つリスティング一覧
SHOW LISTINGS;
-- 特定のリスティングの現在の設定(manifest を含む)
DESCRIBE LISTING my_org_listing;
届いているリスティングを確認する(消費側)
-- 自分に共有されている組織内リスティング
SHOW AVAILABLE LISTINGS IS_ORGANIZATION = TRUE;
つまずきやすいポイント
-
既定では通常ビューを共有できない。Share は既定(
SECURE_OBJECTS_ONLY = TRUE)でセキュアオブジェクトのみ。結合や絞り込みは Secure View 側で完結させておくのが素直です(非セキュアビューを載せるにはSECURE_OBJECTS_ONLY = FALSEが必要)。 -
CURRENT_ROLE/CURRENT_USERを含む secure object は共有に載せない。共有先での評価が意図とずれる恐れがあります。 -
権限・組織設定が前提。オーナーロールへの
CREATE SHAREとCREATE ORGANIZATION LISTING(またはCREATE LISTING)の付与、ORGADMIN側の事前設定がないと、そもそも Share や Listing の作成が通りません。SYSADMINなどの普段のロールには既定で付いていない点に注意します。 -
manifest の必須項目。
support_contactは必須、discoveryを使うならapprover_contactも必須です。
まとめ・学び
- 組織内アカウント間のデータ共有は、Share(中身)+ Listing(届け方)の2層で捉えると SQL に落とし込みやすくなります。オーナーロールを決めて権限を付与 →
CREATE SHARE→GRANT ... TO SHARE→CREATE ORGANIZATION LISTING→ 消費側でCREATE DATABASE ... FROM LISTING、という流れです。途中はSHOW SHARES/SHOW LISTINGSなどで確認できます。 - 「Private Listing」と呼んでいた共有も、SQL で組織内に閉じて書くなら
CREATE ORGANIZATION LISTINGが対応します。UI の呼び名と SQL のコマンド名がずれる点は、最初に押さえておくと迷いません。 -
権限は最初の関門。共有・リスティング系は既定で
ACCOUNTADMINだけが持ち、SYSADMINなどにはありません。オーナーロールを先に決めて必要な権限を付与しておくと、手順の途中で止まらずに済みます。 - 画面手順は UI 変更で陳腐化しやすい一方、SQL は再現性・レビュー・IaC 化に効きます。共有構成もコードで残しておく価値は大きいと感じます。
参考リンク(公式ドキュメント)
- About managing listings using SQL(リスティングを SQL で管理する概要)
- CREATE ORGANIZATION LISTING
- Organization listing manifest reference(manifest の項目)
- Create an organizational listing(作成・消費の流れ)
- Reference organizational listings in queries(ULL でのクエリ参照)
- Create and configure shares(CREATE SHARE と Secure View 共有の制約)
- Use secure objects to control data access(セキュアオブジェクト共有の推奨)
- Share data in non-secured views(SECURE_OBJECTS_ONLY の指定)
- CREATE SHARE
- Enable non-ACCOUNTADMIN roles to perform data sharing tasks(権限の委譲)
- SHOW SHARES
- SHOW LISTINGS
- Introduction to organizations(組織の概念)
- CURRENT_ORGANIZATION_NAME