Looker上で動的にSnowflakeのロールを切り替えてDynamic Data Maskingを適用させてみた #SnowflakeDB
※本エントリは、Snowflakeをもっと使いこなそう! Advent Calendar 2022の21日目の記事となります。
さがらです。
Looker上で動的にSnowflakeのロールを切り替えてSnowflakeのDynamic Data Maskingを適用させてみたので、その内容をまとめてみます。
本検証の意義について
まず、どうしてこんな検証をしようと考えたのか、その意義について記します。
前提:SnowflakeのDynamic Data Maskingについて
SnowflakeのDynamic Data Maskingは、クエリ発行元のロールやユーザー名などを利用し、動的にマスキング処理を行うことができる機能です。
例として、以下は、値を見ることができるロールの場合にはそのまま値を表示し、値を見ることが出来ない場合はアスタリスクでマスキングした値を表示しています。
- カラムの値を見ることが出来る
sagara_admin_role
からのクエリ実行
- カラムの値を見ることが出来ない
sagara_dev_role
からのクエリ実行
LookerにSnowflake Dynamic Data Maskingを適用させる意義
LookerはLookMLを介してSemantic Layer層を構築し、ユーザーが使用する各指標の定義にガバナンスを利かす事ができるBIツールです。
そんなLookerですが、実はLooker単体でもマスキング処理を施すことが可能です。下記の記事のように、検証をされている方もいます。
じゃあどうして、SnowflakeのDynamic Data MaskingをLooker上で適用させる必要があるのか、そのメリットはこの2点だと思います。
- 1つカラムを定義すれば、そのカラムを使用する全てのdimension・measureに対してマスキング処理が行われるため、LookML上でマスキング周りのロジックを記述しなくてよい
- SQL Runnerで実行した際も、マスキング処理が行われる
一方でデメリットとしては、この2点が挙げられると思います。
- 対象のマスキングを適用したカラムを用いた集計結果が、閲覧者によって値が異なる可能性がある ※例えば「~という文字列を含むのは何行あるか」みたいな集計では、マスキングされた結果をベースに集計が行われるため
- SnowflakeとLookerをまたがるので、Lookerからどのカラムに対してDynamic Data Maskingを適用しているかすぐにわからない
こうメリットとデメリットをまとめてみると、一概にすべてのSnowflake×Looker環境で適用させて良い内容とは言えないですね。
ただ、どこかしらで役立つ場面もあると思うので、今回は試してみます!
試してみた
Snowflake上でDynamic Data Maskingの定義と適用
Snowflake上で下記のクエリを実行して、Dynamic Data Maskingの定義と適用をしておきます。
sagara_admin_role
:対象のカラムの値を見ることができる- 上記以外のロール:対象のカラムの値を見ようとすると全てアスタリスクで表示される
-- マスキングポリシー必要な権限の付与 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; -- マスキングポリシーの作成 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;
Looker上でUser Attributeの作成
続いて、Looker上のユーザーごとにSnowflakeのロールを動的に切り替えられるように、User Attributeを作成します。
下図のような設定で、「snowflake_role」というUser Attributeを作成します。Default Value
は任意の設定ですが、ユーザーに対してこのUser Attributeの値を設定し忘れるとConnectionのエラーでLookMLで定義したModelがうまく参照できなくなる可能性があるので、設定しておいたほうが無難かとは思います。
この後に、今回検証を行うLooker上のユーザーに対してこの「snowflake_role」の値を下記のように定義しておきます。
- Looker上のユーザー「Satoshi Sagara」 ※値を見せたいユーザー
- 「snowflake_role」の値は、
SAGARA_ADMIN_ROLE
にする
- 「snowflake_role」の値は、
- Looker上のユーザー「Test1 Sagara」 ※値をマスキングして見せたいユーザー
- 「snowflake_role」の値は、
SAGARA_DEV_ROLE
にする
- 「snowflake_role」の値は、
Connectionの設定
続いて、このLooker環境からSnowflakeのConnectionの設定をします。このConnectionの設定が、動的にSnowflakeのロールを切り替える際の肝となります。
ここでは、Connectionの設定で注意すべき1点だけ触れておきます。
それはAdditional Params
に対して、role={{ _user_attributes['先程作成したUser Attribute名'] }}
と記述することです。この記述方法についてはLookerの公式Docにも記載があります。
下図が実際に私が試した例となります。
この上で各ユーザーでConnectionのテストをすると、role
の値が動的に切り替わっているのがわかりますね!
LookMLの定義
続いて、LookMLの定義なのですが、ここは特別なことは必要ありません。
今回の検証にかかわる所だけ記しておくと、マスキングを適用したカラムを定義するdimension、マスキングを適用したカラムの文字数に応じて結果が変わるmeasure、この2つを下記のように定義しておきます。
# マスキングを適用しているカラムのdimension定義 dimension: first_name { type: string sql: ${TABLE}."FIRST_NAME" ;; } # マスキング処理を適用したカラムの文字数に応じて結果が変わるmeasure定義 measure: count_over4char { type: number sql: sum(case when len(${first_name}) > 4 then 1 else 0 end);; }
カラムの値を見ることが出来るユーザーから参照してみる
では、実際にどのようにユーザーから見えるのか確認してみます!まずはカラムの値を見ることが出来るユーザー「Satoshi Sagara」から試してみます。
各dimensionとmeasureの確認
まず、dimensionは問題なく値が見えますね。
続いて、カラムの文字数に応じて結果が変わるmeasureを見てみると、こちらも問題なさそうです。定義した通り、値が5文字以上のユーザーは正しく「1」と出ていることがわかります。
SQL Runnerからの確認
SQL Runnerからも、問題なく値を見ることが出来ました。
カラムの値を見ることが出来ないユーザーから参照してみる
続いて、カラムの値を見ることが出来ないユーザー「Test1 Sagara」で試してみます。
各dimensionとmeasureの確認
まず、対象のdimensionを見てみると、マスキングされた値しか表示されないことがわかります。
続いて、カラムの文字数に応じて結果が変わるmeasureを見てみると、マスキングは9文字で構成されているため、すべて「1」が返ってきました。これを良しと見るか悪しと見るかは、ユースケースによりそうですね…
SQL Runnerからの確認
SQL Runnerからも確認してみると、ちゃんとマスキングされた値しか表示されませんでした!これはLookerだけでマスキング処理を行った場合では出来ないことなので、今回試した手法の良いところと言えると思います。
最後に
Looker上で動的にSnowflakeのロールを切り替えてSnowflakeのDynamic Data Maskingを適用させてみました。
使いどころは限られるかも知れませんが、使えそうなユースケースがある場合には是非試してみてください!