![[小ネタ]dbtのgrantsとSnowflakeのCOPY GRANTS・FUTURE GRANTSの関係を検証してみた](https://images.ctfassets.net/ct0aopd36mqt/wp-refcat-img-a0f70de29a00d596aa50512303131e72/2fcbfee571e6db80cd904c3c64f7cecc/dbt-1200x630-1.jpg?w=3840&fm=webp)
[小ネタ]dbtのgrantsとSnowflakeのCOPY GRANTS・FUTURE GRANTSの関係を検証してみた
かわばたです。
dbtのgrants
機能を検証する中で、SnowflakeのCOPY GRANTS
やFUTURE GRANTS
と組み合わせた場合に権限がどのように変化するのか、いくつかのパターンについて挙動を確認しました。
【dbt grantsを使用してアクセス制御を行ってみた】
対象読者
- dbtのアクセス制御について確認したい方
検証環境と事前準備
検証環境
- dbt CloudのEnterprise版
- SnowflakeトライアルアカウントのEnterprise版
事前準備
dbtのサンプルデータであるjaffle_shop
を活用しています。
また、Snowflakeにデータベース・スキーマ・ロールを作成しています。
-- martデータベース作成必要(dbtで加工したマート保存用)
create database KAWABATA_MART_DB;
-- -- スキーマ作成(本番用スキーマ)
create schema KAWABATA_MART_DB.PROD_SCHEMA;
-- ロールの作成
-- 分析者のロール
CREATE ROLE IF NOT EXISTS ANALYST_ROLE;
-- BI使用者のロール
CREATE ROLE IF NOT EXISTS BI_USER;
-- 誰も使用しないロール
CREATE ROLE IF NOT EXISTS unused;
検証内容
COPY GRANTS
とgrants
は併用可能なのか- Snowflakeの
FUTURE GRANTS
とgrantsの関係はどうなるのか
実際に試してみた
COPY GRANTS
概要
COPY GRANTS
はSnowflakeのCREATE TABLEのオプションです。
CREATE OR REPLACE TABLE
などのクエリが起こった際に、元のテーブルからのアクセス権限を保持することを指定します。
dbtでは下記のようにdbt_project.yml
で定義することで、このオプションを設定することができます。
models:
+copy_grants: true
【公式ドキュメント】
【Snowflakeドキュメント】
検証
dbtでCOPY GRANTS
とgrants
を併用した場合どうなるのか検証してみました。
まずはCOPY GRANTS
をコメントアウトし、テーブルレベルの権限をgrants
で付与します。
name: jaffle_shop
version: '1.9.0' # dbt プロジェクトのバージョン
profile: 'default'
seed-paths: ["seeds"]
model-paths: ["models"]
macro-paths: ["macros"]
# clean-targets:
# - "target"
# - "dbt_packages"
seeds:
# Builds seeds into '<your_schema_name>_raw'
jaffle_shop:
+schema: raw
models:
## copy_grantsの有効化
# +copy_grants: true
jaffle_shop:
# Materialize staging models as views, and marts as tables
staging:
+materialized: view
marts:
+materialized: table
## martsフォルダ内のANALYST_ROLEとBI_USERへ権限を付与
+grants:
# target.nameが 'prod' の場合
delete: "{{ 'BI_USER' if target.name == 'prod' else 'ANALYST_ROLE' }}"
# target.nameが 'prod' ではない場合 (開発環境の場合)
insert: "{{ 'ANALYST_ROLE' if target.name != 'prod' else 'unused' }}"
update: "{{ 'ANALYST_ROLE' if target.name != 'prod' else 'unused' }}"
flags:
require_generic_test_arguments_property: true
今回は開発環境で行うので、martsフォルダ内のモデルから作成されたテーブルは下記権限が付与されるはずです。
- ANALYST_ROLE
- delete,insert,update
実際に確認してみます。
-- ロール確認
SHOW GRANTS ON TABLE kawabata_mart_db.DBT_TKAWABATA.LOCATIONS;
想定通りの権限が付与されていることが確認できました。
続いて、COPY GRANTS
をコメントアウトを外して実行しますが、事前にSnowflake側でselect権限を付与します。
-- select権限付与
GRANT SELECT ON TABLE kawabata_mart_db.DBT_TKAWABATA.LOCATIONS TO ROLE ANALYST_ROLE;
無事に権限が付与されたことを確認しました。
name: jaffle_shop
version: '1.9.0' # dbt プロジェクトのバージョン
profile: 'default'
seed-paths: ["seeds"]
model-paths: ["models"]
macro-paths: ["macros"]
# clean-targets:
# - "target"
# - "dbt_packages"
seeds:
# Builds seeds into '<your_schema_name>_raw'
jaffle_shop:
+schema: raw
models:
## copy_grantsの有効化
+copy_grants: true
jaffle_shop:
# Materialize staging models as views, and marts as tables
staging:
+materialized: view
marts:
+materialized: table
## martsフォルダ内のANALYST_ROLEとBI_USERへ権限を付与
+grants:
# target.nameが 'prod' の場合
delete: "{{ 'BI_USER' if target.name == 'prod' else 'ANALYST_ROLE' }}"
# target.nameが 'prod' ではない場合 (開発環境の場合)
insert: "{{ 'ANALYST_ROLE' if target.name != 'prod' else 'unused' }}"
update: "{{ 'ANALYST_ROLE' if target.name != 'prod' else 'unused' }}"
flags:
require_generic_test_arguments_property: true
上記のように、COPY GRANTS
のコメントアウトを外して実行しました。
上記のとおり、select権限が削除されていることからCOPY GRANTS
によって引き継がれた権限が、dbtのgrants
の設定によって上書きされていることが確認できました。
grants
をコメントアウトし、COPY GRANTS
が機能しているか確認してみます。
下記クエリを実行し、select権限のみ残しています。
-- DELETE,INSERT,UPDATE権限削除
REVOKE DELETE ON ALL TABLES IN SCHEMA kawabata_mart_db.DBT_TKAWABATA FROM ROLE ANALYST_ROLE;
REVOKE INSERT ON ALL TABLES IN SCHEMA kawabata_mart_db.DBT_TKAWABATA FROM ROLE ANALYST_ROLE;
REVOKE UPDATE ON ALL TABLES IN SCHEMA kawabata_mart_db.DBT_TKAWABATA FROM ROLE ANALYST_ROLE;
-- select権限付与
GRANT SELECT ON TABLE kawabata_mart_db.DBT_TKAWABATA.LOCATIONS TO ROLE ANALYST_ROLE;
name: jaffle_shop
version: '1.9.0' # dbt プロジェクトのバージョン
profile: 'default'
seed-paths: ["seeds"]
model-paths: ["models"]
macro-paths: ["macros"]
# clean-targets:
# - "target"
# - "dbt_packages"
seeds:
# Builds seeds into '<your_schema_name>_raw'
jaffle_shop:
+schema: raw
models:
## copy_grantsの有効化
+copy_grants: true
jaffle_shop:
# Materialize staging models as views, and marts as tables
staging:
+materialized: view
marts:
+materialized: table
## martsフォルダ内のANALYST_ROLEとBI_USERへ権限を付与
# +grants:
# # target.nameが 'prod' の場合
# delete: "{{ 'BI_USER' if target.name == 'prod' else 'ANALYST_ROLE' }}"
# # target.nameが 'prod' ではない場合 (開発環境の場合)
# insert: "{{ 'ANALYST_ROLE' if target.name != 'prod' else 'unused' }}"
# update: "{{ 'ANALYST_ROLE' if target.name != 'prod' else 'unused' }}"
flags:
require_generic_test_arguments_property: true
上記のとおり、COPY GRANTS
が機能してselect権限が残っていることが分かります。
検証したところ、動作の順序としてCOPY GRANTS
が先に機能し、その後にgrants
が適用されることが分かりました。
FUTURE GRANTS
概要
SnowflakeにはFUTURE GRANTS
のようにスキーマやデータベース内に将来新しく作成されるオブジェクト(テーブル、ビューなど)に対して、あらかじめ権限を自動的に付与しておくことができる機能です。
【公式ドキュメント】
検証
FUTURE GRANTS
が適用されている場合、dbtのgrants
との関係を調べます。
Snowflakeで下記のように設定しselect権限を付与するようにしました。
-- FUTURE
GRANT SELECT ON FUTURE TABLES IN SCHEMA kawabata_mart_db.DBT_TKAWABATA TO ROLE ANALYST_ROLE;
付与されているか確認します。
-- 特定のスキーマのFUTURE GRANTSを確認
SHOW FUTURE GRANTS IN SCHEMA kawabata_mart_db.DBT_TKAWABATA;
権限が付与されていることが分かります。
確認する対象のテーブルは下記のように、OWNERSHIP
権限以外付与していない状態です。
dbt_project.yml
は下記のように定義しています。
name: jaffle_shop
version: '1.9.0' # dbt プロジェクトのバージョン
profile: 'default'
seed-paths: ["seeds"]
model-paths: ["models"]
macro-paths: ["macros"]
# clean-targets:
# - "target"
# - "dbt_packages"
seeds:
# Builds seeds into '<your_schema_name>_raw'
jaffle_shop:
+schema: raw
models:
## copy_grantsの有効化
# +copy_grants: true
jaffle_shop:
# Materialize staging models as views, and marts as tables
staging:
+materialized: view
marts:
+materialized: table
# martsフォルダ内のANALYST_ROLEとBI_USERへ権限を付与
+grants:
# target.nameが 'prod' の場合
delete: "{{ 'BI_USER' if target.name == 'prod' else 'ANALYST_ROLE' }}"
# target.nameが 'prod' ではない場合 (開発環境の場合)
insert: "{{ 'ANALYST_ROLE' if target.name != 'prod' else 'unused' }}"
update: "{{ 'ANALYST_ROLE' if target.name != 'prod' else 'unused' }}"
flags:
require_generic_test_arguments_property: true
上記が結果となります。
dbtのgrants
で設定した権限(DELETE, INSERT, UPDATE)に加え、SnowflakeのFUTURE GRANTS
で設定したSELECT権限も付与されていることが確認できました。
この結果から、FUTURE GRANTS
とdbtのgrants
は競合せず、それぞれ独立して機能することがわかります。
最後に
今回の検証から、dbtの権限管理機能の使い分けについて下記のようなパターンがあるかと思います。
-
権限管理をSnowflake側に寄せたい場合:
dbtでは+copy_grants: true
を設定し、権限付与はSnowflake側で手動またはFUTURE GRANTS
で行う形。 -
権限管理をdbt側に寄せたい(GitOps化したい)場合:
dbtの+grants
設定を積極的に活用し、コードとして管理する形。
ただし、Snowflake側で個別に追加した権限はdbt run
のたびにリセットされる可能性があるため注意が必要です。 -
ハイブリッドで管理する場合:
FUTURE GRANTS
でベースとなる読み取り権限(例:SELECT)を広範囲に付与し、dbtのgrants
でモデルごとに書き込み権限(例:INSERT)などを個別に追加する形。
この記事が何かの参考になれば幸いです!