dbt grantsを使用してアクセス制御を行ってみた

dbt grantsを使用してアクセス制御を行ってみた

2025.10.08

かわばたです。

dbt grantsを使用して、dbt Cloudでアクセス制御を行ってみます。

【公式ドキュメント】

https://docs.getdbt.com/reference/resource-configs/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;

		

今回行わないこと

今回は基本的なdbt grantsの機能を試していきます。
ですので、post-hook内でGRANT文を記述するなど高度な要件については触れません。

【参考ドキュメント】

https://docs.getdbt.com/reference/resource-configs/pre-hook-post-hook

dbt grantsの概要

dbtのgrantsは、dbtが生成するテーブルやビューといったデータセットへのアクセス権限を、dbtプロジェクト内のコードとして管理するための機能です。
特徴としては、宣言的な権限管理で「このテーブルは、このロールにSELECT権限を持つべき」という最終的な状態をコードで定義します。

  • Snowflakeにおける権限のマッピング
権限 (dbt config) 一般的な目的 Snowflake
select データの読み取り SELECT
insert データの追加 INSERT
update データの更新 UPDATE
delete データの削除 DELETE
usage スキーマ内のオブジェクトへのアクセス USAGE

実際に試してみた

martsフォルダ内のみ反映

下記のようにdbt_project.ymlを設定しました。これはmodelsフォルダのmartsフォルダ内のオブジェクト(ここではテーブル)に対して、ANALYST_ROLEはselectinsert権限を付与し、BI_USERはselect権限を付与しています。

			
			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:
  jaffle_shop:
    # Materialize staging models as views, and marts as tables
    staging:
      +materialized: view
    marts:
      +materialized: table
      ## martsフォルダ内のANALYST_ROLEとBI_USERへ権限を付与
      +grants:
        select: ['ANALYST_ROLE', 'BI_USER']
        insert: 'ANALYST_ROLE'
flags:
  require_generic_test_arguments_property: true

		

実際にこちらの設定で実行してみます。
2025-10-08_15h07_05

Snowflake側も確認してみましょう。

2025-10-08_15h08_51

上記のように、GRANT文が実行されていることが分かります。

試しに一つのテーブルについて権限を確認してみました。

			
			SHOW GRANTS ON TABLE kawabata_mart_db.DBT_TKAWABATA.LOCATIONS;

		

2025-10-08_15h10_55

想定通りの付与ができています。

念のため、スキーマに影響がないか確認してみます。

			
			SHOW GRANTS ON SCHEMA kawabata_mart_db.DBT_TKAWABATA;

		

2025-10-08_15h13_05

こちらには反映されていませんでした。想定通りテーブルのみに付与されていることが分かります。

宣言的な権限管理の確認

さきほどはselectinsert権限を付与しましたが、selectdelete権限にして対応してみます。
宣言的に権限管理するため、insert権限がなくなるはずです。

			
			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:
  jaffle_shop:
    # Materialize staging models as views, and marts as tables
    staging:
      +materialized: view
    marts:
      +materialized: table
      ## martsフォルダ内のANALYST_ROLEとBI_USERへ権限を付与
      +grants:
        select: ['ANALYST_ROLE', 'BI_USER']
        delete: 'ANALYST_ROLE'
flags:
  require_generic_test_arguments_property: true

		

実行結果を確認すると

			
			SHOW GRANTS ON TABLE kawabata_mart_db.DBT_TKAWABATA.LOCATIONS;

		

2025-10-08_15h19_06

delete権限に置き換わっていることが分かります。

継承の上書きor追加

先ほどまではフォルダ内全体へ権限を付与していましたが、モデルごとに付与することも可能です。
その際に、dbt_project.ymlで定義していたフォルダ内全体へ権限付与と合わせてモデルでの権限付与を行った場合、権限を上書きするか、追加するかを確認していきます。

ここでは、dbt_project.ymlは「宣言的な権限管理の確認」で確認した時の内容となります。

  • select
    • ANALYST_ROLE, BI_USER
  • delete
    • ANALYST_ROLE

上書き

あわせてモデルに権限付与のconfigを加えます。例として、locations.sqlを使用しています。

			
			-- BI_USERにdelete権限付与
{{ config(
    grants={
        'delete':'BI_USER'
    }
) }}

with

locations as (

    select * from {{ ref('stg_locations') }}

)

select * from locations

		

この場合、権限が上書きされるためlocationsテーブルはdelete権限がBI_USERとなるはずです。

			
			SHOW GRANTS ON TABLE kawabata_mart_db.DBT_TKAWABATA.LOCATIONS;

		

2025-10-08_15h46_27

想定通りの内容でした。
念のため他のモデルに影響ないか確認します。

			
			SHOW GRANTS ON TABLE kawabata_mart_db.DBT_TKAWABATA.products;

		

2025-10-08_15h47_58

こちらはdelete権限がANALYST_ROLEのままでした。

追加
上書きではなく、所定のテーブルだけ権限を追加したいケースもあるかと思います。その場合+プレフィックスを活用します。先ほどの設定に+を追加しています。

			
			-- BI_USERにdelete権限付与
{{ config(
    grants={
        '+delete':'BI_USER'
    }
) }}

with

locations as (

    select * from {{ ref('stg_locations') }}

)

select * from locations

		

この場合は権限が追加されるためlocationsテーブルはdelete権限がANALYST_ROLEBI_USERとなるはずです。

			
			SHOW GRANTS ON TABLE kawabata_mart_db.DBT_TKAWABATA.LOCATIONS;

		

2025-10-08_15h53_13

想定通りのロール構成となっていました。

targetによる動的な権限付与

開発環境と本番環境によって権限を分けたいケースがあるかと思います。
そのようなケースの時に、targetによる動的な権限付与が有効です。

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:
  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' の場合
        select: "{{ '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

		

今回簡易な条件分岐の方法を取ったため、unused権限を明示的に記載しています。なにも割り当てないとGRANT文の生成時にエラーとなる可能性があるため付与しています。

開発環境
開発環境では、ANALYST_ROLEselect,insert,update権限が付与されて、BI_USERには権限が付与されない形です。

			
			SHOW GRANTS ON TABLE kawabata_mart_db.DBT_TKAWABATA.LOCATIONS;

		

2025-10-08_16h11_20

想定通りANALYST_ROLEにのみ権限が付与されていました。

本番環境
下記のようにjobの設定でtarget nameをprodとして実行しました。

2025-10-08_16h18_17

			
			SHOW GRANTS ON TABLE kawabata_mart_db.PROD_SCHEMA.LOCATIONS;

		

2025-10-08_17h11_23

想定通りBI_USERselect権限が付与されて、ANALYST_ROLEには権限が付与されていないことが分かります。

最後に

今回の例ではロールに対して権限を付与してきましたが、ユーザーに対して付与することも可能です。
ただ、基本的にはロールへの付与を推奨しています。
ユーザーに直接権限を付与していた場合、例えば離任などで現場を離れる際に都度dbtのコードを修正し、権限設定を更新する必要があります。
ロールの場合は、Snowflake上で該当ユーザーからロールを剥奪するだけで済むため、dbtのコードを触れずに対応することができます。

dbtのアクセス制御は宣言的に権限を付与できるので、是非活用してみてください!

この記事をシェアする

FacebookHatena blogX

関連記事

dbt grantsを使用してアクセス制御を行ってみた | DevelopersIO