
Snowflake データシェアリングでプロバイダー側のデータ保護ポリシー6種がコンシューマー側でどのように作用するか確認してみた
かわばたです。
本記事では、プロバイダー側で定義したデータ保護系ポリシー6種(マスキング・行アクセス・プロジェクション・集約・結合・Data Movement Policy)が、コンシューマー側でどう挙動するかをまとめて検証します。
結論
2026年8月31日時点、AWS東京リージョンにある同一組織の Enterprise Edition アカウント2つをダイレクトシェアで接続して実測した結果です。
| ポリシー | コンシューマー側で作用するか | 補足 |
|---|---|---|
| マスキングポリシー | 〇 | タグベース・ポリシー本体が非共有DBにある場合も作用する |
| 行アクセスポリシー | 〇 | マッピングテーブルが非共有DBでも所有者権限で評価される |
| プロジェクションポリシー | 〇 | コンパイル時エラー。INVOKER_SHARE() でシェア別の出し分け可 |
| 集約ポリシー | 〇 | 最小グループ未満は残余グループへ集約 |
| 結合ポリシー | 〇 | コンシューマー所有テーブルとの結合で要件を満たせる |
| Data Movement Policy | タグ経由は効く / アカウントレベルは効かない | フェッチ・アンロードを制限。ただし CTAS は素通し |
重要なポイントが2つありました。
- 「特定ロールのときだけマスクする」書き方のポリシーは、シェア越しだと全コンシューマーに素値が見える(ポリシー内で
CURRENT_ROLE()が NULL になり、マスク条件に一致しなくなるため)
-- 安全側に倒れる書き方(fail-closed): 許可ロールのときだけ素値を見せる
CASE WHEN CURRENT_ROLE() IN ('ANALYST_ROLE') THEN val
ELSE '***MASKED***' END -- ← 判定できないときもマスクされる
-- 危険側に倒れる書き方(fail-open): 特定ロールのときだけマスクする
CASE WHEN CURRENT_ROLE() IN ('UNTRUSTED_ROLE') THEN '***MASKED***'
ELSE val END -- ← 判定できないときは素値が見える
- ポリシーはクエリ結果や特定のデータ移動を制御するが、取得できたデータの CTAS・再共有までは止められない
前提条件
- 両アカウントとも Enterprise Edition 以上
- 同一リージョンのアカウント
- 検証日: 2026年8月31日、Snowflake Enterprise Edition 、AWS東京リージョン
- 本記事のアカウント識別子はサンプル値(
myorg.provider_acct/myorg.consumer_acct)に置き換えています
検証の観点
ポリシー種別ごとに、次の観点で測定しました。
| 観点 | 確認内容 |
|---|---|
| 適用有無 | コンシューマーのクエリで強制されるか、エラーはコンパイル時か実行時か |
| コンテキスト関数 | ポリシー本文内の CURRENT_ROLE() 等がコンシューマー側でどう評価されるか |
| 定義の可視性 | コンシューマーからポリシー本文・タグが見えるか |
| 受け側からの適用 | コンシューマーが共有オブジェクトへポリシーを追加できるか |
| 変更反映 | プロバイダーのポリシー変更・解除がいつ反映されるか |
| 持ち出し後の保護 | CTAS・再共有・アンロードで保護が残るか |
事前準備
プロバイダー側に検証用DBとシェア2本を作ります。シェアを2本にするのは、後述の INVOKER_SHARE() によるシェア別分岐を1コンシューマーで実証するためです。
-- プロバイダー側
CREATE DATABASE POLSHARE_DB; -- 共有対象
CREATE DATABASE POLSHARE_LIB_DB; -- 共有しない(ポリシー集中管理用)
CREATE SHARE POLSHARE_SHARE_A;
GRANT USAGE ON DATABASE POLSHARE_DB TO SHARE POLSHARE_SHARE_A;
-- (スキーマUSAGE・テーブルSELECTの付与は省略)
ALTER SHARE POLSHARE_SHARE_A ADD ACCOUNTS = myorg.consumer_acct;
CREATE SHARE POLSHARE_SHARE_B; -- 同一テーブルを別シェアでも共有
GRANT USAGE ON DATABASE POLSHARE_DB TO SHARE POLSHARE_SHARE_B;
-- (SHARE_A と同様に対象スキーマのUSAGE・テーブルSELECTを付与)
ALTER SHARE POLSHARE_SHARE_B ADD ACCOUNTS = myorg.consumer_acct;
コンシューマー側でシェアをマウントします。
-- コンシューマー側
CREATE DATABASE POLSHARE_A_DB FROM SHARE myorg.provider_acct.POLSHARE_SHARE_A;
CREATE DATABASE POLSHARE_B_DB FROM SHARE myorg.provider_acct.POLSHARE_SHARE_B;
GRANT IMPORTED PRIVILEGES ON DATABASE POLSHARE_A_DB TO ROLE POLSHARE_CONSUMER_ADMIN;
GRANT IMPORTED PRIVILEGES ON DATABASE POLSHARE_B_DB TO ROLE POLSHARE_CONSUMER_ADMIN;
注意: コンシューマー側の検証ではセッションごとに
ALTER SESSION SET USE_CACHED_RESULT = FALSE;とUSE SECONDARY ROLES NONE;を実行しています。前者は変更反映検証の誤判定防止、後者は保有ロールによる権限迂回の遮断のためです。
試してみた
マスキングポリシー
ポリシーの書き方による違いを見るため、1つのテーブルに書き方の異なるポリシーを列ごとに適用しました。
マスキングポリシー
-- 許可ロール列挙型: 許可ロールだけ素値を見せる
CREATE MASKING POLICY MP_ALLOWLIST AS (val STRING) RETURNS STRING ->
CASE WHEN CURRENT_ROLE() IN ('POLSHARE_PROV_ADMIN') THEN val
ELSE '***MASKED***' END;
-- 禁止ロール列挙型: 特定ロールだけマスクする(判定できないときは素値が見える = fail-open)
CREATE MASKING POLICY MP_BLOCKLIST AS (val STRING) RETURNS STRING ->
CASE WHEN CURRENT_ROLE() IN ('UNTRUSTED_ROLE') THEN '***MASKED***'
ELSE val END;
-- コンテキスト関数の評価値をそのまま返すデバッグ用
CREATE MASKING POLICY MP_DEBUG AS (val STRING) RETURNS STRING ->
'ROLE=' || NVL(CURRENT_ROLE(), '<NULL>')
|| '|USER=' || NVL(CURRENT_USER(), '<NULL>')
|| '|ACCTNAME=' || NVL(CURRENT_ACCOUNT_NAME(), '<NULL>')
|| '|SHARE=' || NVL(INVOKER_SHARE(), '<NULL>');
コンシューマー側で SELECT した結果です。
| 列(書き方) | プロバイダー | コンシューマー |
|---|---|---|
| 常時マスキング | ***ALWAYS*** |
***ALWAYS*** |
| 常時マスキング(ポリシー本体が非共有DB) | ***ALWAYS_LIB*** |
***ALWAYS_LIB*** |
| 許可ロール列挙(MP_ALLOWLIST) | 素値 | ***MASKED*** |
| 禁止ロール列挙(MP_BLOCKLIST) | 素値 | 素値(漏れる) |
| デバッグ列(MP_DEBUG) | ROLE=POLSHARE_PROV_ADMIN|... |
ROLE=<NULL>|USER=<NULL>|ACCTNAME=CONSUMER_ACCT|SHARE=POLSHARE_SHARE_A |

デバッグ列が示す通り、共有オブジェクト上のポリシー内では CURRENT_ROLE() / CURRENT_USER() が NULL になります。このため CASE の条件が UNKNOWN となり ELSE 節に落ちます。

- 許可ロール列挙型: ELSE がマスク → 安全側に倒れる
- 禁止ロール列挙型: ELSE が素値 → 全コンシューマーに素値が漏れる
「特定ロールだけマスクする」書き方は同一アカウント内では成立しますが、シェアに載せるとロールを判定できなくなり、素値を見せる側(fail-open)に倒れます。既存のポリシー設計を大きく変えずに安全側へ倒すには、NULL を明示的に検知する書き方が使えます。
CREATE MASKING POLICY MP_NULLSAFE AS (val STRING) RETURNS STRING ->
CASE WHEN CURRENT_ROLE() IS NULL THEN '***SHARE_CTX***' -- シェア越しアクセス
WHEN CURRENT_ROLE() IN ('POLSHARE_PROV_ADMIN') THEN val
ELSE '***MASKED***' END;
一方、CURRENT_ACCOUNT() / CURRENT_ACCOUNT_NAME() / CURRENT_ORGANIZATION_NAME() / INVOKER_SHARE() コンシューマー側の値で正しく評価されます。シェア対応ポリシーの分岐にはこちらを使います。
-- プロバイダーだけ素値、共有先はマスク
CREATE MASKING POLICY MP_ACCT AS (val STRING) RETURNS STRING ->
CASE WHEN CURRENT_ACCOUNT_NAME() = 'PROVIDER_ACCT' THEN val
ELSE '***CONSUMER***' END;
注意:
CURRENT_ACCOUNT()(ロケータ)はアカウント移行で変わる可能性があるため、CURRENT_ACCOUNT_NAME()とCURRENT_ORGANIZATION_NAME()の組み合わせを推奨します。
タグベースマスキングも同様に強制されました。また、ポリシー本体を共有していない別DBに置いても、シェア越しの強制に影響はありませんでした。
行アクセスポリシー
行アクセスポリシーは TRUE と評価された行だけを返すため、判定式が NULL(UNKNOWN)になった行は返されません。マスキングポリシーと異なり、安全側に倒れます。
行アクセスポリシー
-- ロール依存 RAP: シェア越しは CURRENT_ROLE()=NULL → 全行除外(0行)になる
CREATE OR REPLACE ROW ACCESS POLICY POLSHARE_DB.S_RAP.RAP_ROLE
AS (region STRING) RETURNS BOOLEAN ->
CURRENT_ROLE() IN ('POLSHARE_PROV_ADMIN', 'ACCOUNTADMIN');
-- アカウント分岐 RAP: コンシューマーには APAC だけ見せる(マルチテナント配信パターン)
CREATE OR REPLACE ROW ACCESS POLICY POLSHARE_DB.S_RAP.RAP_ACCT
AS (region STRING) RETURNS BOOLEAN ->
CURRENT_ACCOUNT_NAME() = 'PROVIDER_ACCT' OR region = 'APAC';
-- マッピングテーブル参照 RAP(マッピングは共有に含める)
CREATE OR REPLACE ROW ACCESS POLICY POLSHARE_DB.S_RAP.RAP_MAP_S
AS (region STRING) RETURNS BOOLEAN ->
EXISTS (SELECT 1 FROM POLSHARE_DB.S_RAP.REGION_MAP m
WHERE m.region = region AND m.account_name = CURRENT_ACCOUNT_NAME());
-- マッピングテーブル参照 RAP(マッピングは非共有 LIB DB。所有者権限で評価されるため動く)
CREATE OR REPLACE ROW ACCESS POLICY POLSHARE_DB.S_RAP.RAP_MAP_L
AS (region STRING) RETURNS BOOLEAN ->
EXISTS (SELECT 1 FROM POLSHARE_LIB_DB.MAPS.REGION_MAP_LIB m
WHERE m.region = region AND m.account_name = CURRENT_ACCOUNT_NAME());
| ポリシー条件 | プロバイダー | コンシューマー |
|---|---|---|
CURRENT_ROLE() IN (...) |
6行 | 0行(NULL → 全行除外) |
CURRENT_ACCOUNT_NAME() = '...' OR region = 'APAC' |
6行 | 2行(APAC のみ) |
| マッピングテーブル参照(テーブルは共有) | 6行 | 2行 |
| マッピングテーブル参照(テーブルは非共有DB) | 6行 | 2行 |

マッピングテーブルを共有に含めなくても、ポリシーは所有者権限で評価されるためエラーになりません。テナント別マッピングをコンシューマーから隠したまま行を出し分けられます。
プロジェクションポリシー
公式ドキュメントのサンプルにある INVOKER_SHARE() 分岐を実測しました。
プロジェクションポリシー
-- シェア別分岐(公式サンプルの形): SHARE_A 経由だけ投影不可、
-- SHARE_B 経由とプロバイダー自身は投影可
CREATE OR REPLACE PROJECTION POLICY POLSHARE_DB.S_PROJ.PP_BY_SHARE
AS () RETURNS PROJECTION_CONSTRAINT ->
CASE WHEN INVOKER_SHARE() = 'POLSHARE_SHARE_A' THEN PROJECTION_CONSTRAINT(ALLOW => false)
ELSE PROJECTION_CONSTRAINT(ALLOW => true) END;
同一テーブル・同一コンシューマーでも、経由したシェアによって結果が分かれました。
SELECT email FROM POLSHARE_A_DB.S_PROJ.CONTACTS; -- SHARE_A 経由

SELECT email FROM POLSHARE_B_DB.S_PROJ.CONTACTS; -- SHARE_B 経由 → 素値で取得できる

EXPLAIN でも同じエラーになるため、強制はコンパイル時です。なお WHERE email = '...' のような射影しない参照は許可されるため、値の存在推定は可能です。
集約ポリシー
集約ポリシー
-- プロバイダーは無制限、それ以外は最小グループサイズ5(未満は残余グループへ)
CREATE OR REPLACE AGGREGATION POLICY POLSHARE_DB.S_AGG.AP_COND
AS () RETURNS AGGREGATION_CONSTRAINT ->
CASE WHEN CURRENT_ACCOUNT_NAME() = 'PROVIDER_ACCT' THEN NO_AGGREGATION_CONSTRAINT()
ELSE AGGREGATION_CONSTRAINT(MIN_GROUP_SIZE => 5) END;
通常の SELECT * はエラーになります。

MIN_GROUP_SIZE => 5 を設定したテーブル(APAC 12行 / EMEA 5行 / US 3行)をコンシューマーから集計した結果です。
SELECT region, COUNT(*) AS cnt FROM POLSHARE_A_DB.S_AGG.SALES GROUP BY region;

結合ポリシー
結合ポリシー
-- コンシューマー側: 自DBのテーブルと結合すれば成功
SELECT p.diagnosis, COUNT(*) AS cnt
FROM POLSHARE_A_DB.S_JOIN.PATIENTS p
JOIN POLSHARE_LOCAL_DB.WORK.LOCAL_PATIENTS l ON p.patient_id = l.patient_id
GROUP BY p.diagnosis;
JOIN_CONSTRAINT(JOIN_REQUIRED => TRUE) を設定したテーブルは、SELECT *がエラーでブロックされます。コンシューマーが自分のテーブルと結合すると取得できました。


WHERE ... IN (サブクエリ) は結合要件を満たさず、同じエラーになります。

Data Movement Policy
Data Movement Policy(DMP)は 2026年8月に GA したデータ持ち出し制御機能で、タグ経由の適用も GA に含まれます。
以前検証した記事は下記になります。
公式ドキュメントには「Cross-region share protection is not supported」という一文があるだけで、同一リージョンのシェアでの挙動は書かれていません。実測した結果、タグ経由の DMP はシェア越しに機能しました。
Data Movement Policy
-- CLI/ドライバ経由のフェッチを100行までに制限(検証ロール本人は無制限)
CREATE OR REPLACE DATA MOVEMENT RULE POLSHARE_DB.S_DMP.R_PSH_FETCH_100
TYPE = 'PROGRAMMATIC_FETCH'
MAX_ROWS AS () RETURNS INTEGER
-> (CASE WHEN SYS_CONTEXT('SNOWFLAKE$SESSION', 'ROLE') = 'POLSHARE_PROV_ADMIN' THEN NULL ELSE 100 END)
COMMENT = 'Fetch limited to 100 rows except provider admin';
-- Snowsight の結果表示も100行までに制限(Snowsight でスクショを撮るための追加ルール。
-- ブログ本文の実測エラー 100168 は PROGRAMMATIC_FETCH 側)
CREATE OR REPLACE DATA MOVEMENT RULE POLSHARE_DB.S_DMP.R_PSH_SNOWSIGHT_100
TYPE = 'SNOWSIGHT_UI'
MAX_ROWS AS () RETURNS INTEGER
-> (CASE WHEN SYS_CONTEXT('SNOWFLAKE$SESSION', 'ROLE') = 'POLSHARE_PROV_ADMIN' THEN NULL ELSE 100 END)
COMMENT = 'Screenshot only: Snowsight display limited to 100 rows';
-- 内部/外部ステージへのアンロードを全ブロック(COPY INTO の検証用)
CREATE OR REPLACE DATA MOVEMENT RULE POLSHARE_DB.S_DMP.R_PSH_COPY_INT_BLOCK
TYPE = 'COPY_INTO_INTERNAL_STAGE'
MAX_ROWS AS () RETURNS INTEGER
-> (CASE WHEN SYS_CONTEXT('SNOWFLAKE$SESSION', 'ROLE') = 'POLSHARE_PROV_ADMIN' THEN NULL ELSE 0 END)
COMMENT = 'Block unload to internal stage except provider admin';
CREATE OR REPLACE DATA MOVEMENT RULE POLSHARE_DB.S_DMP.R_PSH_COPY_EXT_BLOCK
TYPE = 'COPY_INTO_EXTERNAL_STAGE'
MAX_ROWS AS () RETURNS INTEGER
-> (CASE WHEN SYS_CONTEXT('SNOWFLAKE$SESSION', 'ROLE') = 'POLSHARE_PROV_ADMIN' THEN NULL ELSE 0 END)
COMMENT = 'Block unload to external stage except provider admin';
-- Rule を ENFORCE(超過でブロック)として束ねるポリシー
CREATE OR REPLACE DATA MOVEMENT POLICY POLSHARE_DB.S_DMP.DMP_SHARE_GUARD
ENFORCE_RULES = (R_PSH_FETCH_100, R_PSH_SNOWSIGHT_100, R_PSH_COPY_INT_BLOCK, R_PSH_COPY_EXT_BLOCK)
COMMENT = 'Share guard: fetch/display <= 100 rows, block unload';
-- DMP はタグ経由で適用(PROPAGATE = NONE のタグには設定できない)
CREATE OR REPLACE TAG POLSHARE_DB.S_DMP.DMP_TAG
PROPAGATE = ON_DEPENDENCY_AND_DATA_MOVEMENT;
ALTER TAG POLSHARE_DB.S_DMP.DMP_TAG SET DATA MOVEMENT POLICY POLSHARE_DB.S_DMP.DMP_SHARE_GUARD;
ALTER TABLE POLSHARE_DB.S_DMP.PAYROLL SET TAG POLSHARE_DB.S_DMP.DMP_TAG = 'guarded';
-- アカウントレベル検証用ポリシー(ここでは定義のみ。ALTER ACCOUNT SET/UNSET で適用・解除して確認した)
CREATE OR REPLACE DATA MOVEMENT RULE POLSHARE_DB.S_DMP.R_PSH_BASELINE_FETCH_BLOCK
TYPE = 'PROGRAMMATIC_FETCH'
MAX_ROWS AS () RETURNS INTEGER
-> (CASE WHEN SYS_CONTEXT('SNOWFLAKE$SESSION', 'ROLE') IN ('POLSHARE_PROV_ADMIN', 'ACCOUNTADMIN') THEN NULL ELSE 0 END)
COMMENT = 'Baseline test: block fetch except provider roles';
CREATE OR REPLACE DATA MOVEMENT POLICY POLSHARE_DB.S_DMP.DMP_TEST_BASELINE
ENFORCE_RULES = (R_PSH_BASELINE_FETCH_BLOCK)
COMMENT = 'Temporary account baseline for share verification';
プロバイダー側でフェッチ100行制限・アンロード禁止のポリシーをタグ経由で適用し、コンシューマーから操作した結果です。
| コンシューマーの操作 | 結果 |
|---|---|
SELECT COUNT(*)(結果1行) |
成功 |
SELECT * ... LIMIT 50 |
成功 |
SELECT *(500行フェッチ) |
実行時エラー |
COPY INTO @自分のステージ |
コンパイル時エラー |
CREATE TABLE ... AS SELECT *(500行) |
成功(素通し) |


100行以上なのでエラー

自分のステージへのアンロードなのでエラー

CTAS は movement type 外のため素通しで成功

重要なのは最後の行です。
CTAS は DMP の制御対象(movement type)に含まれないため、クエリで取得できる範囲の全行を自分のテーブルへコピーできます。コピーされるのはあくまでクエリ結果で、マスキングや行アクセスポリシーの適用結果が素値に戻るわけではありません。ただしコピー先にはタグも DMP も伝播しないため(PROPAGATE 設定はアカウント境界を越えません)、コピー先へのフェッチ・アンロードは制限されません。
一方、タグを付けずアカウントレベル(ベースライン)で適用した DMP は、コンシューマーの操作をブロックしませんでした。シェアに機能するのはタグ経由の DMP だけとなります。
セキュアビュー経由
実運用で多い「元テーブルは共有せず、それを参照するセキュアビューだけを共有する」構成も確認しました。
セキュアビュー経由
CREATE OR REPLACE TABLE POLSHARE_LIB_DB.BASE.CUSTOMERS_BASE (
id NUMBER, region STRING, ssn STRING, email STRING
);
INSERT INTO POLSHARE_LIB_DB.BASE.CUSTOMERS_BASE VALUES
(1, 'APAC', 'SSN-0001', 'base1@example.com'),
(2, 'EMEA', 'SSN-0002', 'base2@example.com');
CREATE OR REPLACE MASKING POLICY POLSHARE_LIB_DB.POLICIES.MP_BASE_ALWAYS
AS (val STRING) RETURNS STRING -> '***BASE_ALWAYS***';
-- 「特定ロールだけマスクする」型(シェア越しに素値が見えることをビュー経由でも確認する)
CREATE OR REPLACE MASKING POLICY POLSHARE_LIB_DB.POLICIES.MP_BASE_BLOCKLIST
AS (val STRING) RETURNS STRING ->
CASE WHEN CURRENT_ROLE() IN ('UNTRUSTED_ROLE') THEN '***MASKED***' ELSE val END;
CREATE OR REPLACE ROW ACCESS POLICY POLSHARE_LIB_DB.POLICIES.RAP_BASE_ACCT
AS (region STRING) RETURNS BOOLEAN ->
CURRENT_ACCOUNT_NAME() = 'PROVIDER_ACCT' OR region = 'APAC';
ALTER TABLE POLSHARE_LIB_DB.BASE.CUSTOMERS_BASE ALTER COLUMN ssn SET MASKING POLICY POLSHARE_LIB_DB.POLICIES.MP_BASE_ALWAYS;
ALTER TABLE POLSHARE_LIB_DB.BASE.CUSTOMERS_BASE ALTER COLUMN email SET MASKING POLICY POLSHARE_LIB_DB.POLICIES.MP_BASE_BLOCKLIST;
ALTER TABLE POLSHARE_LIB_DB.BASE.CUSTOMERS_BASE ADD ROW ACCESS POLICY POLSHARE_LIB_DB.POLICIES.RAP_BASE_ACCT ON (region);
-- ケース1: ポリシー付きの元テーブルを参照するセキュアビュー(ビュー自体にはポリシーなし)
CREATE OR REPLACE SECURE VIEW POLSHARE_DB.S_VIEW.V_BASEPOL AS
SELECT id, region, ssn, email FROM POLSHARE_LIB_DB.BASE.CUSTOMERS_BASE;
-- ケース2: ビュー列に直接ポリシー(元テーブルはポリシーなし)
CREATE OR REPLACE TABLE POLSHARE_LIB_DB.BASE.CUSTOMERS_PLAIN (id NUMBER, email STRING);
INSERT INTO POLSHARE_LIB_DB.BASE.CUSTOMERS_PLAIN VALUES
(1, 'plain1@example.com'), (2, 'plain2@example.com');
CREATE OR REPLACE SECURE VIEW POLSHARE_DB.S_VIEW.V_VIEWPOL AS
SELECT id, email FROM POLSHARE_LIB_DB.BASE.CUSTOMERS_PLAIN;
CREATE OR REPLACE MASKING POLICY POLSHARE_DB.S_VIEW.MP_VIEWCOL_ALWAYS
AS (val STRING) RETURNS STRING -> '***VIEWCOL***';
ALTER VIEW POLSHARE_DB.S_VIEW.V_VIEWPOL ALTER COLUMN email SET MASKING POLICY POLSHARE_DB.S_VIEW.MP_VIEWCOL_ALWAYS;
| 保護の適用箇所 | ビュー越しの結果 |
|---|---|
| 元テーブルの常時マスキング | 強制される(***BASE_ALWAYS***) |
| 元テーブルの行アクセスポリシー(アカウント分岐) | 強制される(対象行のみ) |
| 元テーブルの「特定ロールだけマスクする」型(fail-open) | 素値が漏れる |
| ビュー列に直接設定したマスキングポリシー | 強制される(***VIEWCOL***) |

元テーブルを共有していなくても、ポリシー評価のコンテキストはシェア越し(CURRENT_ROLE() = NULL)のままです。
横断検証
定義の可視性: コンシューマーからポリシーの定義本文や実際の名前は確認できません(DMP の SHOW コマンドは未確認)。
SHOW MASKING POLICIES/SHOW ROW ACCESS POLICIES/SHOW AGGREGATION POLICIES/SHOW PROJECTION POLICIES/SHOW JOIN POLICIES(いずれもIN DATABASE指定): すべて0件DESCRIBE TABLEの policy name 列:Unknown Policy!(存在だけ見える)GET_DDL('TABLE', ...): 共有DBでは操作自体が非サポート(エラー001131)

受け側からの適用: 共有テーブルへのタグ・ポリシー適用は 003001: Provider share does not have sufficient privileges. でブロックされます。

制限事項・注意点
- 本検証は同一組織・同一リージョン・ダイレクトシェアの構成です。クロス組織・クロスリージョン・リスティング経由・リーダーアカウントは未検証です
- Dynamic Tables・マテリアライズドビュー・外部テーブルの共有は対象外です
- データベースロール分岐が「シェア単位の判定」になる挙動は、公式ドキュメントの説明(コンシューマー側でロールに付与して有効化する)と乖離があります。設計に組み込む前に再確認を推奨します
- プロジェクション・集約・結合ポリシーは信頼関係のあるパートナー向けの機能です。試行を重ねた推定攻撃を完全には防げないと公式ドキュメントに明記されています
- タグベースの行アクセス・プロジェクション・集約・結合ポリシー適用は 2026年8月時点でパブリックプレビューのため、これらは直接適用で確認しています(タグベースマスキングと DMP のタグ経由適用は GA)
- DMP の違反記録は最大2時間遅延します。監査に使う場合は遅延を織り込んでください
最後に
マスキング・行アクセス・プロジェクション・集約・結合の各ポリシーはシェア越しにも強制され、DMP はタグ経由の適用のみ機能しました。
機密データはそもそも共有しなくても良いものは共有しないが前提ですが、必要に応じてデータ保護ポリシーが利用できるのは利点だと思います。
この記事が何かの参考になれば幸いです!





