[小ネタ]dbtのgrantsとSnowflakeのCOPY GRANTS・FUTURE GRANTSの関係を検証してみた

[小ネタ]dbtのgrantsとSnowflakeのCOPY GRANTS・FUTURE GRANTSの関係を検証してみた

2025.10.10

かわばたです。

dbtのgrants機能を検証する中で、SnowflakeのCOPY GRANTSFUTURE GRANTSと組み合わせた場合に権限がどのように変化するのか、いくつかのパターンについて挙動を確認しました。

【dbt grantsを使用してアクセス制御を行ってみた】
https://dev.classmethod.jp/articles/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 GRANTSgrantsは併用可能なのか
  • SnowflakeのFUTURE GRANTSとgrantsの関係はどうなるのか

実際に試してみた

COPY GRANTS

概要

COPY GRANTSはSnowflakeのCREATE TABLEのオプションです。
CREATE OR REPLACE TABLEなどのクエリが起こった際に、元のテーブルからのアクセス権限を保持することを指定します。
dbtでは下記のようにdbt_project.ymlで定義することで、このオプションを設定することができます。

			
			models:
  +copy_grants: true

		

【公式ドキュメント】
https://docs.getdbt.com/reference/resource-configs/snowflake-configs#copying-grants

【Snowflakeドキュメント】
https://docs.snowflake.com/ja/sql-reference/sql/create-table#label-create-table-copy-grants

検証

dbtでCOPY GRANTSgrantsを併用した場合どうなるのか検証してみました。

まずは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;

		

2025-10-10_16h12_00

想定通りの権限が付与されていることが確認できました。


続いて、COPY GRANTSをコメントアウトを外して実行しますが、事前にSnowflake側でselect権限を付与します。

			
			-- select権限付与
GRANT SELECT ON TABLE kawabata_mart_db.DBT_TKAWABATA.LOCATIONS TO ROLE ANALYST_ROLE;

		

2025-10-10_16h17_47

無事に権限が付与されたことを確認しました。

			
			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のコメントアウトを外して実行しました。

2025-10-10_16h24_11

上記のとおり、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


		

2025-10-10_16h43_18

上記のとおり、COPY GRANTSが機能してselect権限が残っていることが分かります。

検証したところ、動作の順序としてCOPY GRANTSが先に機能し、その後にgrantsが適用されることが分かりました。

FUTURE GRANTS

概要
SnowflakeにはFUTURE GRANTSのようにスキーマやデータベース内に将来新しく作成されるオブジェクト(テーブル、ビューなど)に対して、あらかじめ権限を自動的に付与しておくことができる機能です。

【公式ドキュメント】
https://docs.snowflake.com/ja/sql-reference/sql/grant-privilege

検証

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;

		

2025-10-10_16h58_13

権限が付与されていることが分かります。

確認する対象のテーブルは下記のように、OWNERSHIP権限以外付与していない状態です。
2025-10-10_17h00_31

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


		

2025-10-10_17h09_25

上記が結果となります。
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)などを個別に追加する形。

この記事が何かの参考になれば幸いです!

この記事をシェアする

FacebookHatena blogX

関連記事