🐑

[メモ] クローンとタグベースのマスキングポリシーの話

2024/04/09に公開

はじめに

これはドキュメントに書いてあることを確認するだけの小ネタです。

疑問

  • タグベースのマスキングポリシーで保護されたテーブルを、ほかのデータベースにクローンする。このとき、タグとタグベースのマスキングポリシーって、どういう扱いになるんだっけ🤔

解答

https://docs.snowflake.com/ja/user-guide/object-clone#cloning-and-governance-objects

タグ:

  • ソースオブジェクト(例: テーブル)にあるタグの関連付けは、クローンされたオブジェクトで維持されます。

うん、クローン先もタグが付けられた状態になるってことですね。

タグベースのマスキングポリシー:

  • タグがマスキングポリシーおよびテーブルとは異なるスキーマに格納されているタグベースのマスキングポリシーの場合は、マスキングポリシーおよびテーブルを含むスキーマをクローンすると、クローンされたスキーマ内ではなく、ソーススキーマ内のマスキングポリシーによって保護されるクローンされたテーブルが生成されます。 ... (1)
  • ただし、タグ、マスキングポリシー、およびテーブルがすべてスキーマに存在するタグベースのマスキングポリシーの場合は、スキーマをクローンすると、ソーススキーマ内ではなく、クローンされたスキーマ内のマスキングポリシーによってテーブルが保護されます。... (2)
  • テーブルが別のスキーマまたはデータベースにクローンまたは移動され、そのスキーマまたはデータベースで設定されたタグベースのマスキングポリシーによって元々保護されていた場合、そのテーブルはソーススキーマまたはデータベースで設定されたタグベースのマスキングポリシーによっては保護されません。ターゲットスキーマまたはデータベースにタグベースのマスキングポリシーが設定されている場合、テーブルはターゲットスキーマまたはデータベースに設定されたタグベースのマスキングポリシーによって保護されます。 ... (3) [1]

なるほど。クローン先オブジェクトも、元と同じマスキングポリシーで保護される、と書かれている気がするけど...自分の解釈は公式と一致しているのだろうか..。

というわけで、どのスキーマまたはデータベースにあるマスキングポリシーで保護されるのか、理解を確認するために、簡単に動作を確認してみます。

図解:こういうことみたい

確認

準備

クローン元・クローン先を作っていきます。また、マスキングでデータが見えなくなるロールとして MASKING_TEST_ROLE を用意します。

use role securityadmin;
create role MASKING_TEST_ROLE;
grant role MASKING_TEST_ROLE to role SYSADMIN;

-- クローン元
use role sysadmin;
create database m_kajiya_db1;
create schema m_kajiya_db1.data;
create schema m_kajiya_db1.tagpoli;
create or replace table m_kajiya_db1.data.tbl (
    id, name
) as
select
    *
from (
    values
        (1, 'ほげ'),
        (2, 'ぴよ'),
        (3, null)
);

select * from m_kajiya_db1.data.tbl;

マスクされる前のデータがこちら:

+----+------+
| ID | NAME |
+----+------+
| 1  | ほげ |
| 2  | ぴよ |
| 3  |      |
+----+------+

タグを設定していく。

use role sysadmin;
create or replace masking policy m_kajiya_db1.tagpoli.mask
as (val string) returns string ->
  case
    when current_role() = 'MASKING_TEST_ROLE' then 'DB1_MASKED'
    else val
  end
;

create tag if not exists m_kajiya_db1.tagpoli.tag;

use role accountadmin;
alter tag  m_kajiya_db1.tagpoli.tag set masking policy m_kajiya_db1.tagpoli.mask;
alter table m_kajiya_db1.data.tbl alter column name set tag m_kajiya_db1.tagpoli.tag = 'true';

さらに準備を続ける。MASKING_TEST_ROLE でクローン元を参照可能にする。

-- 参照可能にする
use role securityadmin;
grant usage on database m_kajiya_db1 to role MASKING_TEST_ROLE;
grant usage on schema m_kajiya_db1.data to role MASKING_TEST_ROLE;
grant select on table m_kajiya_db1.data.tbl to role MASKING_TEST_ROLE;
grant usage on warehouse m_kajiya_wh to role MASKING_TEST_ROLE;

-- 動作テスト
use role MASKING_TEST_ROLE;
select * from m_kajiya_db1.data.tbl;

MASKING_TEST_ROLE から name は見えない。

+----+------------+
| ID | NAME       |
+----+------------+
| 1  | DB1_MASKED |
| 2  | DB1_MASKED |
| 3  | DB1_MASKED |
+----+------------+

保護されているのを確認したので、準備OK。

確認1 クローン元データベースで、テーブルと別のスキーマにタグとポリシーがあるとき

クローン先データベースを作成し、スキーマをクローンする。

use role sysadmin;
create database m_kajiya_db2;

-- db2 に同名のポリシーを作る
create or replace schema m_kajiya_db2.tagpoli;
create or replace masking policy m_kajiya_db2.tagpoli.mask
as (val string) returns string ->
  case
    when current_role() = 'MASKING_TEST_ROLE' then 'DB2_MASKED'
    else val
  end
;

create tag if not exists m_kajiya_db2.tagpoli.tag;

-- clone する
create or replace schema m_kajiya_db2.data 
    clone m_kajiya_db1.data
;

-- マスキングが適用されるロールから参照可能にする
use role securityadmin;
grant usage on database m_kajiya_db2 to role MASKING_TEST_ROLE;
grant usage on schema m_kajiya_db2.data to role MASKING_TEST_ROLE;
grant select on table m_kajiya_db2.data.tbl to role MASKING_TEST_ROLE;

-- マスクされているか
use role MASKING_TEST_ROLE;
select * from m_kajiya_db2.data.tbl;

クローン元データベースにあるポリシーで保護されているのがわかる。

+----+------------+
| ID | NAME       |
+----+------------+
| 1  | DB1_MASKED |
| 2  | DB1_MASKED |
| 3  | DB1_MASKED |
+----+------------+
policy_references を確認してみる
-- ポリシー確認
use role sysadmin;
select
    -- *
    POLICY_DB, POLICY_SCHEMA, POLICY_NAME
    , REF_DATABASE_NAME, REF_SCHEMA_NAME, REF_ENTITY_NAME, REF_COLUMN_NAME
    , TAG_DATABASE, TAG_SCHEMA, TAG_NAME
from
    table(information_schema.policy_references(
        ref_entity_name => 'm_kajiya_db2.data.tbl',
        ref_entity_domain => 'table'
    ))
;

クローン元データベースにあるタグとポリシーが紐づいているのがわかる。

+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+ 
| POLICY_DB    | POLICY_SCHEMA | POLICY_NAME | REF_DATABASE_NAME | REF_SCHEMA_NAME | REF_ENTITY_NAME | REF_COLUMN_NAME | TAG_DATABASE | TAG_SCHEMA | TAG_NAME |
+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+ 
| M_KAJIYA_DB1 | TAGPOLI       | MASK        | M_KAJIYA_DB2      | DATA            | TBL             | NAME            | M_KAJIYA_DB1 | TAGPOLI    | TAG      |
+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+

テーブルをクローンしたときも同じく、クローン元データベースにあるポリシーで保護される。

create or replace schema m_kajiya_db2.data;
-- create schema m_kajiya_db2.tagpoli;

-- replace schema によりテーブルがなくなったことを確認
show tables in schema m_kajiya_db2.data;
-- Query produced no results

-- タグベースのマスキングポリシーが設定されたテーブルをクローン
create or replace table m_kajiya_db2.data.tbl
    clone m_kajiya_db1.data.tbl
    copy grants
;

-- マスキングが適用されるロールから参照可能にする
use role securityadmin;
grant usage on database m_kajiya_db2 to role MASKING_TEST_ROLE;
grant usage on schema m_kajiya_db2.data to role MASKING_TEST_ROLE;
grant select on table m_kajiya_db2.data.tbl to role MASKING_TEST_ROLE;

-- マスクされているか
use role MASKING_TEST_ROLE;
select * from m_kajiya_db2.data.tbl;

クローン元データベースにあるポリシーで保護されていることがわかる。

+----+------------+
| ID | NAME       |
+----+------------+
| 1  | DB1_MASKED |
| 2  | DB1_MASKED |
| 3  | DB1_MASKED |
+----+------------+
policy_references を確認してみる(再)
-- ポリシー確認
use role sysadmin;
select
    -- *
    POLICY_DB, POLICY_SCHEMA, POLICY_NAME
    , REF_DATABASE_NAME, REF_SCHEMA_NAME, REF_ENTITY_NAME, REF_COLUMN_NAME
    , TAG_DATABASE, TAG_SCHEMA, TAG_NAME
from
    table(information_schema.policy_references(
        ref_entity_name => 'm_kajiya_db2.data.tbl',
        ref_entity_domain => 'table'
    ))
;

やはり、クローン元データベースにあるタグとポリシーが紐づいているのがわかる。

+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+ 
| POLICY_DB    | POLICY_SCHEMA | POLICY_NAME | REF_DATABASE_NAME | REF_SCHEMA_NAME | REF_ENTITY_NAME | REF_COLUMN_NAME | TAG_DATABASE | TAG_SCHEMA | TAG_NAME |
+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+ 
| M_KAJIYA_DB1 | TAGPOLI       | MASK        | M_KAJIYA_DB2      | DATA            | TBL             | NAME            | M_KAJIYA_DB1 | TAGPOLI    | TAG      |
+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+

確認2 クローン先データベースにタグとポリシーがあるとき

ターゲットスキーマまたはデータベースにタグベースのマスキングポリシーが設定されている場合、テーブルはターゲットスキーマまたはデータベースに設定されたタグベースのマスキングポリシーによって保護されます。

… とあるので、クローン先にあるタグとマスキングポリシーが使われるのだろうと思いつつ、確認してみる。

-- 一旦消し飛ばす
drop table m_kajiya_db2.data.tbl;

-- タグベースのマスキングポリシー付け替え
use role accountadmin;
alter tag  m_kajiya_db2.tagpoli.tag set masking policy m_kajiya_db2.tagpoli.mask;
alter table m_kajiya_db1.data.tbl alter column name unset tag m_kajiya_db1.tagpoli.tag;
alter table m_kajiya_db1.data.tbl alter column name set tag m_kajiya_db2.tagpoli.tag = 'true';

-- ふたたびクローン
use role sysadmin;
create or replace table m_kajiya_db2.data.tbl
    clone m_kajiya_db1.data.tbl
    copy grants
;
select * from m_kajiya_db2.data.tbl;

-- マスクされているか
use role MASKING_TEST_ROLE;
select * from m_kajiya_db2.data.tbl;

クローン先にあるタグとマスキングポリシーで保護されていることがわかる。つまり、クローン元テーブルと同じタグとマスキングポリシーで保護されているってこと。

+----+------------+
| ID | NAME       |
+----+------------+
| 1  | DB2_MASKED |
| 2  | DB2_MASKED |
| 3  | DB2_MASKED |
+----+------------+
policy_references を確認してみる(再々)
-- ポリシー確認
use role sysadmin;
select
    -- *
    POLICY_DB, POLICY_SCHEMA, POLICY_NAME
    , REF_DATABASE_NAME, REF_SCHEMA_NAME, REF_ENTITY_NAME, REF_COLUMN_NAME
    , TAG_DATABASE, TAG_SCHEMA, TAG_NAME
from
    table(information_schema.policy_references(
        ref_entity_name => 'm_kajiya_db2.data.tbl',
        ref_entity_domain => 'table'
    ))
;

やはり、クローン先データベースにあるタグとポリシーが紐づいている。

+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+ 
| POLICY_DB    | POLICY_SCHEMA | POLICY_NAME | REF_DATABASE_NAME | REF_SCHEMA_NAME | REF_ENTITY_NAME | REF_COLUMN_NAME | TAG_DATABASE | TAG_SCHEMA | TAG_NAME |
+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+ 
| M_KAJIYA_DB2 | TAGPOLI       | MASK        | M_KAJIYA_DB2      | DATA            | TBL             | NAME            | M_KAJIYA_DB2 | TAGPOLI    | TAG      |
+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+

確認3 クローン元でもクローン先でもないデータベース・スキーマにタグとポリシーがあるとき [4]

クローン元・クローン先のどちらでもない、まったく関係ないデータベースにある場合はどうなるんですかね?

-- クローンにかかわらないデータベース
use role sysadmin;
create database m_kajiya_db3;
create schema m_kajiya_db3.data;
create schema m_kajiya_db3.tagpoli;
create or replace masking policy m_kajiya_db3.tagpoli.mask
as (val string) returns string ->
  case
    when current_role() = 'MASKING_TEST_ROLE' then 'DB3_MASKED'
    else val
  end
;
create tag if not exists m_kajiya_db3.tagpoli.tag;

-- DB1 にあるテーブルを保護する
use role accountadmin;
alter tag  m_kajiya_db3.tagpoli.tag set masking policy m_kajiya_db3.tagpoli.mask;
alter table m_kajiya_db1.data.tbl alter column name unset tag m_kajiya_db2.tagpoli.tag;
alter table m_kajiya_db1.data.tbl alter column name set tag m_kajiya_db3.tagpoli.tag = 'true';

-- ふたたびクローン
use role sysadmin;
create or replace table m_kajiya_db2.data.tbl
    clone m_kajiya_db1.data.tbl
    copy grants
;
select * from m_kajiya_db2.data.tbl;

-- 動作テスト
use role MASKING_TEST_ROLE;
select * from m_kajiya_db2.data.tbl;

やはり、そのままクローン元と同じタグがついて、同じマスキングポリシーで保護されている。

+----+------------+
| ID | NAME       |
+----+------------+
| 1  | DB3_MASKED |
| 2  | DB3_MASKED |
| 3  | DB3_MASKED |
+----+------------+
policy_references を確認してみる(再再々)
-- ポリシー確認
use role sysadmin;
select
    -- *
    POLICY_DB, POLICY_SCHEMA, POLICY_NAME
    , REF_DATABASE_NAME, REF_SCHEMA_NAME, REF_ENTITY_NAME, REF_COLUMN_NAME
    , TAG_DATABASE, TAG_SCHEMA, TAG_NAME
from
    table(information_schema.policy_references(
        ref_entity_name => 'm_kajiya_db2.data.tbl',
        ref_entity_domain => 'table'
    ))
;

このとおり。

+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+ 
| POLICY_DB    | POLICY_SCHEMA | POLICY_NAME | REF_DATABASE_NAME | REF_SCHEMA_NAME | REF_ENTITY_NAME | REF_COLUMN_NAME | TAG_DATABASE | TAG_SCHEMA | TAG_NAME |
+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+ 
| M_KAJIYA_DB3 | TAGPOLI       | MASK        | M_KAJIYA_DB2      | DATA            | TBL             | NAME            | M_KAJIYA_DB3 | TAGPOLI    | TAG      |
+--------------+---------------+-------------+-------------------+-----------------+-----------------+-----------------+--------------+------------+----------+

おわりに

クローンおよびタグベースのマスキングポリシーと仲良くなることができました。これで安心して眠れます。

脚注
  1. 説明のために 箇条書きと (1)~(3) の番号を追加しています ↩︎

  2. テーブルをクローンする場合も、クローン先テーブルには、クローン元のデータベースにあるタグが付き、クローン元にあるポリシーで保護される ↩︎

  3. テーブルをクローンする場合も、クローン先テーブルには、クローン元テーブルと同様にクローン先のデータベースにあるタグが付き、クローン先にあるポリシーで保護される。また、クローン先データベースにタグがある状態の図を掲載していますが、クローン先でもクローン元でもないデータベースでも同じ ↩︎

  4. 環境分離等々の都合上、実際にはあまりしないと思いつつ ↩︎

Discussion