dbt Projects on Snowflake を GitHub Actions + OIDC 認証で CI/CD を試してみた

dbt Projects on Snowflake を GitHub Actions + OIDC 認証で CI/CD を試してみた

GitHub ActionsのOIDCトークンとSnowflakeのWorkload Identity Federationを組み合わせることで、長期シークレットなしでdbt Projects on Snowflakeの安全なCI/CDパイプラインを構築する方法を紹介します。
2026.07.23

かわばたです。

dbt Projects on Snowflake で dbt プロジェクトを Snowflake 上で直接実行できるようになり、開発フローに CI/CD を組み込みたいケースは多いのではないでしょうか。その際に気になるのが GitHub Actions から Snowflake への認証方法です。パスワードや PAT(Programmatic Access Token)を GitHub Secrets に保存する方式は、長期シークレットの管理・ローテーションという運用負荷がつきまといます。

本記事では、GitHub Actions の OIDC トークンと Snowflake の Workload Identity Federation を使い、長期シークレットなしで「PR 時に dev 環境で dbt build を実行する CI」と「main マージ時に snow dbt deploy で本番デプロイする CD」を構築してみます。

https://docs.snowflake.com/en/user-guide/tutorials/dbt-projects-on-snowflake-ci-cd-tutorial

構成の概要

dbt Projects on Snowflake の CI/CD

dbt Projects on Snowflake では、dbt プロジェクトをスキーマレベルの DBT PROJECT オブジェクトとしてデプロイし、Snowflake 上で実行します。公式ドキュメントでは次の CI/CD 構成が示されています。

  • CI: Pull Request ごとにテスト用の DBT PROJECT オブジェクトをデプロイし、dev 環境に対して dbt build を実行する
  • CD: main ブランチへのマージ後に snow dbt deploy で本番用 DBT PROJECT オブジェクトを更新する

snow dbt deploy はバージョン付きのデプロイであり、デプロイのたびに新しいバージョンが積み上がります。実行履歴も保持されるため、いつどのバージョンで実行されたかを追跡できます。

OIDC(Workload Identity Federation)による認証

Snowflake の Workload Identity Federation を使うと、GitHub Actions が発行する短期の OIDC トークンで Snowflake に認証できます。GitHub Secrets に保存するのはアカウント識別子のみで、パスワード・PAT・キーペアは一切不要です。

仕組みとしては、TYPE = SERVICE のユーザーに WORKLOAD_IDENTITY として ISSUER(トークン発行者)と SUBJECT(トークンの sub claim)を登録しておき、Snowflake 側で GitHub の OIDC トークンを検証します。

https://docs.snowflake.com/en/user-guide/workload-identity-federation

sub claim とサービスユーザーの設計

GitHub Actions の OIDC トークンの sub claim は、トリガーとなるイベントによって形式が変わります。

イベント sub claim の形式
pull_request repo:<org>/<repo>:pull_request
push(ブランチ) repo:<org>/<repo>:ref:refs/heads/<branch>
environment 指定ありのジョブ repo:<org>/<repo>:environment:<name>

Snowflake のサービスユーザーは SUBJECT と sub claim の完全一致が必要です。公式チュートリアルでは CI/CD 両方のジョブに environment: prod を指定して sub claim を統一し、サービスユーザー 1 つで構成しています。

今回は GitHub Environment を使わないシンプルな構成とするため、CI(pull_request)用と CD(main への push)用でサービスユーザーを 2 つ作成します。認証主体が分かれることで、CI 用ユーザーには dev のみ、CD 用ユーザーには prod のみといった権限分離にも発展させやすい構成です。

なお、本記事では検証を簡潔にするため 2 ユーザーに共通ロール(dbt_cicd_role)を付与しており、この構成のままでは CI 用ユーザーも prod にアクセス可能です。権限分離まで行う場合は、dbt_ci_role(dev と raw のみ)/ dbt_cd_role(prod と raw のみ)のようにロールを分け、各サービスユーザーへの付与と profiles.yml の各 target の role を対応させてください。

前提条件

  • Snowflake アカウント(サービスユーザー作成のため ACCOUNTADMIN 相当の権限が必要)
  • GitHub Actions が有効なリポジトリ
  • Snowflake CLI 3.11.0 以上(OIDC 認証の要件。snowflakedb/snowflake-actions@v3 で導入)
  • dbt プロジェクト: 本記事では jaffle-shop(dbt Labs のサンプルプロジェクト)を使用
  • dbt バージョン: dbt Core 1.11.11 を指定
  • 本記事ではデフォルトブランチを main と仮定しています。master など別のブランチ名を使う場合は、ワークフローの branches と CD 用サービスユーザーの SUBJECT を実際のブランチ名に合わせて変更してください

事前準備

Snowflake 環境の作成

データベース、dev / prod スキーマ、ウェアハウス、CI/CD 用のロールを作成します。公式チュートリアルは ACCOUNTADMIN をそのまま使う構成ですが、今回は専用ロールに最小限の権限を付与します。

Snowflake 環境の作成
USE ROLE ACCOUNTADMIN;

CREATE DATABASE IF NOT EXISTS jaffle_shop_db;
CREATE SCHEMA IF NOT EXISTS jaffle_shop_db.dev;
CREATE SCHEMA IF NOT EXISTS jaffle_shop_db.prod;
CREATE SCHEMA IF NOT EXISTS jaffle_shop_db.raw;   -- ソースデータ(seeds)用

CREATE WAREHOUSE IF NOT EXISTS jaffle_shop_wh
  WAREHOUSE_SIZE = XSMALL
  AUTO_SUSPEND = 60
  AUTO_RESUME = TRUE
  INITIALLY_SUSPENDED = TRUE;

CREATE ROLE IF NOT EXISTS dbt_cicd_role;
GRANT USAGE ON DATABASE jaffle_shop_db TO ROLE dbt_cicd_role;
GRANT USAGE ON WAREHOUSE jaffle_shop_wh TO ROLE dbt_cicd_role;
GRANT ALL ON SCHEMA jaffle_shop_db.dev  TO ROLE dbt_cicd_role;
GRANT ALL ON SCHEMA jaffle_shop_db.prod TO ROLE dbt_cicd_role;
GRANT ALL ON SCHEMA jaffle_shop_db.raw  TO ROLE dbt_cicd_role;

GRANT CREATE DBT PROJECT ON SCHEMA jaffle_shop_db.dev  TO ROLE dbt_cicd_role;
GRANT CREATE DBT PROJECT ON SCHEMA jaffle_shop_db.prod TO ROLE dbt_cicd_role;

GRANT CREATE SCHEMA ON DATABASE jaffle_shop_db TO ROLE dbt_cicd_role;

CREATE DBT PROJECT 権限が snow dbt deploy に必要な権限です。また、dbt は実行時にターゲットスキーマの存在確認と作成(CREATE SCHEMA IF NOT EXISTS)を行うため、スキーマを事前に作成済みでも、データベースへの CREATE SCHEMA 権限がないと dbt build が権限エラーで失敗します(検証時に実際に踏んだエラーです)。アクセス制御の詳細は以下のドキュメントにまとまっています。

https://docs.snowflake.com/en/user-guide/data-engineering/dbt-projects-on-snowflake-access-control

dbt プロジェクト(jaffle-shop)の調整

dbt Projects on Snowflake では dbt_project.yml に加えて profiles.yml がプロジェクトルートに必須です。dev / prod の 2 ターゲットを定義します。

profiles.yml
jaffle_shop:
  target: dev
  outputs:
    dev:
      type: snowflake
      account: '_'   # プレースホルダー。実行は Snowflake 内部のため未使用
      user: '_'      # 同上
      role: DBT_CICD_ROLE
      database: JAFFLE_SHOP_DB
      schema: DEV
      warehouse: JAFFLE_SHOP_WH
      threads: 8
    prod:
      type: snowflake
      account: '_'
      user: '_'
      role: DBT_CICD_ROLE
      database: JAFFLE_SHOP_DB
      schema: PROD
      warehouse: JAFFLE_SHOP_WH
      threads: 8

注意: 実行は Snowflake 内部で行われるため、accountuser にはプレースホルダー文字列で問題ありません。パスワードの記載も不要です。一方で type / database / schema / role / warehouse は必須です。さらに snow dbt deploy はデプロイ前に profiles.yml の内容を実環境に対して検証し、rolewarehouse が存在しない・接続ユーザーからアクセスできない場合は「Role 'XXX' does not exist or is not accessible.」のようなエラーで弾かれます(全ターゲットが検証対象です)。実環境のオブジェクト名と完全に一致させてください。

OIDC サービスユーザーの作成

CI 用と CD 用の 2 ユーザーを作成します。SUBJECT がそれぞれのイベントの sub claim と完全一致するように設定します。

OIDC サービスユーザーの作成
USE ROLE ACCOUNTADMIN;

-- CI 用(pull_request イベント)
CREATE USER IF NOT EXISTS svc_gha_dbt_ci
  TYPE = SERVICE
  WORKLOAD_IDENTITY = (
    TYPE = OIDC
    ISSUER = 'https://token.actions.githubusercontent.com'
    SUBJECT = 'repo:<your-org>/<your-dbt-repo>:pull_request'
  )
  DEFAULT_ROLE = dbt_cicd_role
  DEFAULT_WAREHOUSE = jaffle_shop_wh
  COMMENT = 'GitHub Actions CI (pull_request) service user';

-- CD 用(main への push イベント)
CREATE USER IF NOT EXISTS svc_gha_dbt_cd
  TYPE = SERVICE
  WORKLOAD_IDENTITY = (
    TYPE = OIDC
    ISSUER = 'https://token.actions.githubusercontent.com'
    SUBJECT = 'repo:<your-org>/<your-dbt-repo>:ref:refs/heads/main'
  )
  DEFAULT_ROLE = dbt_cicd_role
  DEFAULT_WAREHOUSE = jaffle_shop_wh
  COMMENT = 'GitHub Actions CD (push to main) service user';

GRANT ROLE dbt_cicd_role TO USER svc_gha_dbt_ci;
GRANT ROLE dbt_cicd_role TO USER svc_gha_dbt_cd;

注意: SUBJECT は sub claim と完全一致している必要があります。<your-org>/<your-dbt-repo> はリポジトリの実際のパスに置き換えてください。大文字小文字も含めて一致が必要です。

WORKLOAD_IDENTITY(TYPE=OIDC) が ISSUER/SUBJECT どおりに登録されているか確認しました。

2026-07-23_14h27_53

GitHub リポジトリの設定

Settings を開き、Secrets and variables → Actions を選択します。New repository secret をクリックし、Secret を 1 件だけ登録します。

  • SNOWFLAKE_ACCOUNT: アカウント識別子(<orgname>-<account_name> 形式)

登録するシークレットはこれだけです。パスワードも PAT も不要という点が OIDC 認証の大きなメリットです。

2026-07-23_14h51_45

CI ワークフローの作成

.github/workflows/ci.yml を作成します。PR をトリガーに、テスト用の DBT PROJECT オブジェクトを dev スキーマにデプロイし、dev ターゲットで dbt build を実行します。

name: CI - dbt build on PR
run-name: PR by ${{ github.actor }}
on:
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]
    branches: [main]

concurrency:
  group: ci-dev
  cancel-in-progress: false

permissions:
  contents: read
  id-token: write   # OIDC トークン発行に必須

jobs:
  dbt-ci:
    runs-on: ubuntu-latest
    env:
      SNOWFLAKE_CLI_FEATURES_ENABLE_DBT: true
      SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
      SNOWFLAKE_ROLE: DBT_CICD_ROLE
      SNOWFLAKE_WAREHOUSE: JAFFLE_SHOP_WH
      SNOWFLAKE_DATABASE: JAFFLE_SHOP_DB
      SNOWFLAKE_SCHEMA: DEV
    steps:
      - uses: actions/checkout@v4

      - name: Install dbt and resolve dependencies
        run: |
          pip install 'dbt-core==1.11.*'
          dbt deps

      - name: Install Snowflake CLI
        uses: snowflakedb/snowflake-actions@v3
        with:
          use-oidc: true

      - name: Test connection
        run: snow connection test -x

      - name: Deploy tester dbt project object
        run: snow dbt deploy ci_jaffle_shop --source . --dbt-version 1.11.11 -x

      - name: Build and test on dev
        run: snow dbt execute -x ci_jaffle_shop build --target dev

ポイントは次のとおりです。

  • permissionsid-token: write が OIDC トークン発行に必須
  • snowflakedb/snowflake-actions@v3use-oidc: true を渡すと、認証用の環境変数(SNOWFLAKE_AUTHENTICATOR=WORKLOAD_IDENTITY 等)が自動設定される
  • snow dbt コマンドの利用には環境変数 SNOWFLAKE_CLI_FEATURES_ENABLE_DBT: true が必要
  • -x は一時接続(temporary connection)オプションで、config ファイルなしに環境変数ベースで接続する
  • SNOWFLAKE_ROLE / SNOWFLAKE_WAREHOUSE を明示することで、サービスユーザーのデフォルトロール設定に依存せず接続コンテキストを確定させる(未指定でデフォルトロールが効いていないと「Could not use database」エラーになる)
  • concurrency で CI を直列化している。全 PR が同じ ci_jaffle_shop オブジェクトを共有しており、同一 DBT PROJECT オブジェクトへの EXECUTE DBT PROJECT の同時実行はサポートされないため

CD ワークフローの作成

.github/workflows/deploy.yml を作成します。main への push をトリガーに、本番用 DBT PROJECT オブジェクトを prod スキーマにデプロイし、続けて prod ターゲットで build を実行します。

name: CD - deploy dbt project on merge
run-name: Deploy by ${{ github.actor }}
on:
  push:
    branches: [main]

concurrency:
  group: cd-prod
  cancel-in-progress: false

permissions:
  contents: read
  id-token: write

jobs:
  dbt-deploy:
    runs-on: ubuntu-latest
    env:
      SNOWFLAKE_CLI_FEATURES_ENABLE_DBT: true
      SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
      SNOWFLAKE_ROLE: DBT_CICD_ROLE
      SNOWFLAKE_WAREHOUSE: JAFFLE_SHOP_WH
      SNOWFLAKE_DATABASE: JAFFLE_SHOP_DB
      SNOWFLAKE_SCHEMA: PROD
    steps:
      - uses: actions/checkout@v4

      - name: Install dbt and resolve dependencies
        run: |
          pip install 'dbt-core==1.11.*'
          dbt deps

      - name: Install Snowflake CLI
        uses: snowflakedb/snowflake-actions@v3
        with:
          use-oidc: true

      - name: Test connection
        run: snow connection test -x

      - name: Deploy production dbt project object
        run: snow dbt deploy jaffle_shop --source . --default-target prod --dbt-version 1.11.11 -x

      - name: Build models on prod
        run: snow dbt execute -x jaffle_shop build --target prod

      - name: List dbt project objects
        run: snow dbt list -x

CD では --default-target prod を指定し、DBT PROJECT オブジェクトのデフォルトターゲットを prod にしています。当初はデプロイのみの構成で検証しましたが、デプロイだけでは DBT PROJECT オブジェクトの新バージョンが登録されるのみで prod スキーマのテーブルは更新されないため、マージでデータまで反映されるよう build ステップを追加しています。モデル数が多い本番運用では、build を Snowflake Task のスケジュール実行に分離し、CD はデプロイのみとする構成も選択肢です。

また concurrency は CD の直列化のためのものです。同一 DBT PROJECT オブジェクトへの EXECUTE DBT PROJECT は同時実行できないため、マージが連続した場合に build が衝突しないよう cancel-in-progress: false で後続を待機させます。

試してみた

OIDC 認証の確認

ワークフローを main に push すると CD が起動します。まずは snow connection test -x の結果で OIDC 認証が通ることを確認します。

2026-07-23_18h32_39

CI: PR 作成でテストが実行される

feature branch でモデルに軽微な変更を加えて PR を作成すると、CI ワークフローが起動します。
今回はcustomers.sqlのカラム名を一部変更しています。

2026-07-23_18h27_21

PRを作成します。
2026-07-23_18h30_29

CI ではテスト用オブジェクト ci_jaffle_shop が dev スキーマにデプロイされ、dev ターゲットで dbt build が実行されます。

2026-07-23_18h36_19

この時点で dev スキーマには変更が反映され、prod スキーマは変更前のままであることを確認できます。

2026-07-23_18h34_43

CD: マージで本番オブジェクトが更新される

PR をマージすると CD ワークフローが起動し、本番オブジェクトが新しいバージョンとしてデプロイされ、続く build ステップで prod スキーマのテーブル・ビューも更新されます。

2026-07-23_18h36_51

2026-07-23_18h41_56

prod スキーマにも反映されていることが確認できました。

2026-07-23_18h43_54

テスト失敗時に CI がブロックされることの確認

意図的にテストが失敗する変更(not_null 違反など)で PR を作成すると、CI が失敗します。ブランチ保護ルールと組み合わせることで、テストが通らない変更のマージをブロックできます。

今回はcustomers.sqlに対して、下記内容を最後に加えています。

-- test: 検証のため customer_id を意図的に重複させ、unique テストを失敗させる
select * from joined

union all

(select * from joined limit 1)

2026-07-23_19h01_17

制限事項・注意点

  • snow dbt deploy --forceCREATE OR REPLACE DBT PROJECT として動作し、既存のバージョンと実行履歴が失われます。通常の CD パイプラインでは使用しないことを推奨します
  • DBT PROJECT オブジェクトは Serverless Task では実行できず、ユーザー管理のウェアハウスが必要です
  • 同一 DBT PROJECT オブジェクトに対する EXECUTE DBT PROJECT の同時実行はサポートされません
  • dbt Cloud プロジェクトは非サポートです(dbt Core / dbt Fusion のみ)
  • アカウントでネットワークポリシーを運用している場合、GitHub ホステッドランナーからの接続には Snowflake マネージドのネットワークルール SNOWFLAKE.NETWORK_SECURITY.GITHUBACTIONS_GLOBAL を許可リストに追加する必要があります
  • 本記事はシンプル構成のためサービスユーザーを 2 つに分けましたが、本番運用では GitHub Environment(environment: prod)と必須承認者を設定し、SUBJECT を repo:<org>/<repo>:environment:prod とする構成を推奨します。承認ゲートを通過するまでデプロイジョブが実行されないため、より安全な CD になります
  • GitHub の OIDC トークンの sub claim 仕様は変更・拡張される可能性があるため、実装時は GitHub 公式ドキュメントも確認してください

https://docs.snowflake.com/en/user-guide/data-engineering/dbt-projects-on-snowflake-limitations

最後に

GitHub Actions の OIDC トークンと Workload Identity Federation により、GitHub Secrets にはアカウント識別子のみという構成で dbt Projects on Snowflake の CI/CD を構築できました。

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


Snowflakeの導入支援はクラスメソッドに!

クラスメソッドでは Snowflake の導入を支援しております。
製品の詳細や支援の内容についてお気軽にお問い合わせください。

Snowflakeの詳細を見る

この記事をシェアする

関連記事