Snowflakeの「Masking Policy」と「Row Access Policy」を試してみた #SnowflakeDB

2022.12.12

※本エントリは、Snowflakeをもっと使いこなそう! Advent Calendar 2022の12日目の記事となります。

さがらです。

Snowflakeの「Masking Policy」と「Row Access Policy」を試してみたので、その内容をまとめてみます。

Masking Policyとは

Masking Policyは、SnowflakeのDynamic Data Maskingを適用させる際に必要なポリシーです。

例えば、Dynamic Data Maskingをあるカラムに対して適用することで、Aというロールには全ての値を見せるが、Bというロールにはすべて「*」などでマスキングした値を見せる、ということが可能です。

Masking Policyのサンプル

以下では、FIRST_NAMEというカラムにおいて、sagara_admin_roleには値を見せるが、それ以外のロールには「*********」を表示する、というMasking Policyを作成し適用しています。

-- Masking Policyの作成と適用に、必要な権限の付与
use role accountadmin;
grant create masking policy on schema sagara_rawdata_db.jaffle_shop to role sagara_admin_role;
grant apply masking policy on account to role sagara_admin_role;

-- Masking Policyの作成
use role sagara_admin_role;
create or replace masking policy first_name_mask as (val string) returns string ->
  case
    when current_role() in ('SAGARA_ADMIN_ROLE') then val
    else '*********'
  end;

-- 対象のカラムへ適用
alter table if exists customers modify column first_name set masking policy first_name_mask;

実際にクエリを発行してみると、この様になります。

  • カラムの値を見ることが出来るsagara_admin_roleからのクエリ実行
-- カラムの値を見ることが出来るロールでの実行
use role sagara_admin_role;
select * from customers;

  • カラムの値を見ることが出来ないsagara_dev_roleからのクエリ実行
-- カラムの値を見ることが出来ないロールでの実行
use role sagara_dev_role;
select * from customers;

Row Access Policyとは

Row Access Policyは、Snowflakeにおいてレコードレベルのアクセス制御を適用させる際に必要なポリシーです。

例えば、使用しているロールと各テーブルのレコードに含まれる部署などのカラムを紐づけて、あるロールの人にはこの部署のレコードだけを見せる、といったことが可能です。

Row Access Policyのサンプル

以下では、sagara_admin_roleには全レコードの値を見せるが、それ以外のロールには全レコード見せない、というRow Access Policyを作成し適用しています。 ※あくまで今回は検証のため、一番手っ取り早い方法を試しています。実際にはマッピングテーブルと併せて、特定のレコードのみにアクセスさせるユースケースの方が多いと思います。

※今回使用するsagara_admin_roleは対象のスキーマの所有者権限を持っているので、CREATE ROW ACCESS POLICY権限も自動でついてきます。対象のスキーマへの所有者権限を持たないロールでポリシーを定義する場合は、この権限の付与を忘れずにしましょう。

-- Row Access Policyの作成
use role sagara_admin_role;
create or replace row access policy row_access_only_sagara_admin as (check_first_name varchar) returns boolean ->
  case
      when 'SAGARA_ADMIN_ROLE' = current_role() then true
      else false
  end
;

実際にクエリを発行してみると、この様になります。

  • 値を見ることが出来るsagara_admin_roleからのクエリ実行
-- 値を見ることが出来るロールでの実行
use role sagara_admin_role;
select * from customers;

  • 値を見ることが出来ないsagara_dev_roleからのクエリ実行
-- 値を見ることが出来ないロールでの実行
use role sagara_dev_role;
select * from customers;

2つのポリシーを適用する際の注意

このように非常に便利なMasking PolicyとRow Access Policyですが、同時に適用する場合には注意しないといけないことがあります。

公式Docに記載されている注意事項について記しておきます。

同じカラムに対してMasking PolicyとRow Access Policyは付与できない

Masking PolicyとRow Access Policyですが、1つのカラムに対してこれらのポリシー両方を付与することが出来ません

実際私も検証をしている中で、すでにMasking Policyを適用中のfirst_nameカラムにRow Access Policyを適用しようとしたところ、下図のようにエラーとなりました

あるテーブルにMasking PolicyとRow Access Policyがどちらも設定されている場合、Row Access Policyが優先して評価される

サブタイトルのとおりですが、あるテーブルにMasking PolicyとRow Access Policyがどちらも設定されている場合、Row Access Policyが優先して評価されます

例えば、下記のクエリを順番に実行して、あるテーブルにMasking PolicyとRow Access Policyをどちらも適用したとします。

-- Masking Policyの作成
use role sagara_admin_role;
create or replace masking policy first_name_mask as (val string) returns string ->
  case
    when current_role() in ('SAGARA_ADMIN_ROLE') then val
    else '*********'
  end;

-- Masking Policyを対象のカラムへ適用
alter table if exists customers modify column first_name set masking policy first_name_mask;

-- Row Access Policyの作成
use role sagara_admin_role;
create or replace row access policy row_access_only_sagara_admin as (check_first_name varchar) returns boolean ->
  case
      when 'SAGARA_ADMIN_ROLE' = current_role() then true
      else false
  end;

-- Row Access Policyを対象のカラムへ適用
use role sagara_admin_role;
alter table customers add row access policy jaffle_shop.row_access_only_sagara_admin on (last_name);

この上で、下記のクエリを実行すると、Row Access Policyの方が先に適用され、結果欄には何も出てこなくなります。

-- どちらのポリシーでも値を見ることが出来ないロールでの実行
use role sagara_dev_role;
select * from customers;

最後に

SnowflakeのMasking PolicyとRow Access Policyを試してみました。どちらも元データを書き換えることなく動的に対応してくれる機能なので非常に便利ですが、上述の通り同時に適用する場合には注意したいですね。

Masking Policyについては、現在(2022年12月1日時点)はタグを介した付与も可能なので、この機能も近日中に試してみます!