dbt

dbt のCIで環境変数とシークレットを安全に扱う: 環境別切替の実装指針

2026-04-19
NicheeLab編集部

CI上でdbtを動かすとき、最大の落とし穴は「秘密情報の露出」と「環境切替の一貫性不足」です。この記事は、dbtの標準機能(env_var、profiles.yml、target)と一般的なCIのシークレットストアを使い、開発・検証・本番を安全に切り替える最小構成を示します。

Analytics Engineer試験で頻出の論点も併せて整理します。特に、env_varの既定値、profiles.ymlのJinja、target.nameの使い分け、CIログのマスキング、そして環境ごとのスキーマ切替がチェックされがちです。

前提と用語整理: env_var、profiles.yml、target の役割

dbtはJinja経由で環境変数を参照できます。env_var('KEY', 'default')の形式で、CIから注入した値やローカルの環境変数を安全に取り込みます。defaultを省くと、未定義時にコンパイルエラーになり、事故を防げます。

接続設定はprofiles.ymlに置き、ターゲット(target)でdev/stg/prodなどの出力先を切り替えます。モデル側はtarget.nameやtarget.schemaを参照できます。秘密情報(パスワード、トークン、接続文字列)は必ずCIやdbt Cloudのシークレットストアから環境変数として注入し、リポジトリに書かないのが原則です。

  • env_varはdbt_project.yml、profiles.yml、モデルJinjaのいずれからでも参照可能
  • default未指定で未定義だとエラー→CIで早期失敗にできる
  • ターゲット名は切替の最小単位。SQL内に環境名で分岐を書くより、設定で切り替える

env_varの基本用法(モデル/Jinjaとdbt_project.yml)

-- models/stg_orders.sql
{{
  config(
    schema=env_var('DBT_SCHEMA', target.schema)  # CIで上書き、未設定ならtarget.schema
  )
}}

select *
from {{ source('raw', 'orders') }}

-- dbt_project.yml(抜粋)
name: my_dbt
version: 1.0.0
config-version: 2

models:
  +materialized: view

vars:
  environment: "{{ env_var('DBT_ENVIRONMENT', 'dev') }}"

環境別切替の実装パターン: profiles.yml と target の設計

環境ごとの差分はprofiles.ymlで吸収するのが定石です。ターゲットはenv_varで外から指定できるようにし、スキーマやデータベース名にも環境サフィックスを付けます。これによりCIとローカルの切替が対称になります。

スキーマ名の分岐はgenerate_schema_nameマクロやconfig(schema=...)で一元管理。SQL本文にif文を書かず、構成で切り替えるとメンテナンス性が高く、試験でも模範解答に近い扱いです。

  • profiles.ymlのtargetをenv_varで外だし
  • スキーマ/DB/ロール/ウェアハウス等は環境変数で上書き可能に
  • 命名規則: <ベーススキーマ>_<環境> など一意に

Snowflake例: profiles.ymlで環境とシークレットを外だし

my_profile:
  target: "{{ env_var('DBT_TARGET_NAME', 'dev') }}"
  outputs:
    dev:
      type: snowflake
      account: "{{ env_var('SNOWFLAKE_ACCOUNT') }}"
      user: "{{ env_var('SNOWFLAKE_USER') }}"
      password: "{{ env_var('SNOWFLAKE_PASSWORD') }}"
      role: "{{ env_var('SNOWFLAKE_ROLE', 'DEV_ROLE') }}"
      warehouse: "{{ env_var('SNOWFLAKE_WAREHOUSE', 'DEV_WH') }}"
      database: "{{ env_var('SNOWFLAKE_DATABASE', 'ANALYTICS_DEV') }}"
      schema: "{{ env_var('DBT_SCHEMA', 'dbt_dev') }}"
    ci:
      type: snowflake
      account: "{{ env_var('SNOWFLAKE_ACCOUNT') }}"
      user: "{{ env_var('SNOWFLAKE_USER') }}"
      password: "{{ env_var('SNOWFLAKE_PASSWORD') }}"
      role: "{{ env_var('SNOWFLAKE_ROLE', 'CI_ROLE') }}"
      warehouse: "{{ env_var('SNOWFLAKE_WAREHOUSE', 'CI_WH') }}"
      database: "{{ env_var('SNOWFLAKE_DATABASE', 'ANALYTICS_CI') }}"
      schema: "{{ env_var('DBT_SCHEMA', 'dbt_ci') }}"
    prod:
      type: snowflake
      account: "{{ env_var('SNOWFLAKE_ACCOUNT') }}"
      user: "{{ env_var('SNOWFLAKE_USER') }}"
      password: "{{ env_var('SNOWFLAKE_PASSWORD') }}"
      role: "{{ env_var('SNOWFLAKE_ROLE', 'PROD_ROLE') }}"
      warehouse: "{{ env_var('SNOWFLAKE_WAREHOUSE', 'PROD_WH') }}"
      database: "{{ env_var('SNOWFLAKE_DATABASE', 'ANALYTICS') }}"
      schema: "{{ env_var('DBT_SCHEMA', 'dbt') }}"

CIのシークレット管理オプション比較とベストプラクティス

CIが提供するシークレットストア(GitHub Actions Secrets、GitLab CI/CD Variables、CircleCI Contexts等)は、環境変数として注入され、ログで自動マスキングされます。dbt側はenv_varで受け取るだけで済み、単純で安全です。

大規模・高規制環境ではHashiCorp Vault等の専用ストアを併用し、CIから短命トークンを取得して注入する設計が一般的です。どの場合も、リポジトリやprofiles.ymlに秘密値を直書きしないこと、権限を最小化すること、ログに出さないことが原則です。

  • リポジトリに秘密を置かない(コミット禁止)
  • CIログのマスキング/保護ブランチでの使用制御を有効化
  • ローテーション容易な認証方式(キーペア/OAuth/短命トークン)を優先
方式注入方法マスキング/権限制御適合シーン
GitHub Actions Secretsenv: KEY: ${{ secrets.KEY }}自動マスキング・環境/環境保護中小規模〜一般用途のCI
GitLab CI/CD Variablesvariables/Masked/Protectedマスク/保護ブランチ/環境スコープ環境ごとの厳格制御が必要な場合
dbt Cloud(環境変数)環境/Jobに設定→Jinjaでenv_var暗号化保存・UI制御dbt Cloudで一元管理したい場合
HashiCorp Vault併用CIがOIDC等で短命トークン取得→env注入きめ細かなポリシー/監査高規制・ゼロトラスト要件

GitHub Actionsでの安全な注入例(envに束ねる)

env:
  DBT_TARGET_NAME: ci
  DBT_ENVIRONMENT: ci
  SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
  SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
  SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
  SNOWFLAKE_ROLE: ${{ secrets.SNOWFLAKE_ROLE }}
  SNOWFLAKE_WAREHOUSE: ${{ secrets.SNOWFLAKE_WAREHOUSE }}
  SNOWFLAKE_DATABASE: ${{ secrets.SNOWFLAKE_DATABASE }}

標準的なCIパイプライン例とデータフロー(ASCII図)

最小構成は、依存解決→コンパイル/検証→実行→テストの直列です。ターゲットはciに固定し、スキーマ/DBはCI専用リソースを使います。実行ログはマスクされ、SQL内に秘密値が含まれない設計にします。

以下はGitHub Actionsでdbt-snowflakeを動かす例です。各CIのYAMLでも考え方は同じです。

  • deps→debug(接続検証)→compile→run→testの順で早期失敗
  • --target ci とenv_varで切替一元化
  • CIスキーマは使い捨てにすると衝突/掃除の手間が減る

CIでのシークレット注入と実行フロー

Git Repo(dbt project)CI Runner(GitHub/GitLab)pushdbtcompile/run/testenv / secrets (masked in logs)Data Warehouse(dev/ci schema)Git Repo → CI Runner → dbt → Data Warehouse

GitHub Actions: dbt CIワークフロー(抜粋)

name: dbt-ci
on:
  pull_request:
    branches: [ main ]

jobs:
  run-dbt:
    runs-on: ubuntu-latest
    env:
      DBT_TARGET_NAME: ci
      DBT_ENVIRONMENT: ci
      SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
      SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
      SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
      SNOWFLAKE_ROLE: ${{ secrets.SNOWFLAKE_ROLE }}
      SNOWFLAKE_WAREHOUSE: ${{ secrets.SNOWFLAKE_WAREHOUSE }}
      SNOWFLAKE_DATABASE: ${{ secrets.SNOWFLAKE_DATABASE }}
      DBT_SCHEMA: dbt_ci_${{ github.actor }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - name: Install dbt adapter
        run: |
          python -m pip install --upgrade pip
          pip install dbt-snowflake
      - name: Verify deps and connection
        run: |
          dbt deps
          dbt debug --target ci --no-write-json
      - name: Compile
        run: dbt compile --target ci --warn-error
      - name: Run and test
        run: |
          dbt run  --target ci --fail-fast --select state:modified+
          dbt test --target ci --fail-fast

ログ安全性と落とし穴: 秘密値を出さない運用

CIのset -xやechoで環境変数を出力するとマスクが効かないケースがあります。秘密値は参照しない・ログに書かない・画面に出さないが基本です。dbtのログは接続テスト結果などを出しますが、CI側でマスキングを有効化し、debugの詳細出力を最小限にします。

Jinja内で必須の環境変数が欠落している場合は、早期にコンパイルエラーを発生させて停止させます。これにより、誤った接続先や匿名接続で実行してしまう事故を避けられます。

  • シェルでset +x(コマンドエコー抑止)を明示
  • dbt debugはCIでは--no-write-jsonや適切なlog-levelで実行
  • env_var未設定時は例外を投げて早期失敗

秘密値を出さないための実用スニペット

# シェル: コマンドエコー抑止
set +x

# Jinja: 必須環境変数の検査(任意のmacroやmodel冒頭で)
{% if not env_var('SNOWFLAKE_PASSWORD', none) %}
  {{ exceptions.raise_compiler_error('Missing SNOWFLAKE_PASSWORD') }}
{% endif %}

# dbt実行時は必要最小限の出力
# 例: 失敗時にのみ詳細を参照する運用
dbt run --target ci --fail-fast
# 必要なら --log-level warn などで情報量を絞る

試験対策の要点とチェックリスト

Analytics Engineer試験では、環境変数と構成の責務分離がよく問われます。環境依存の分岐をSQL本文に持ち込まず、profiles.ymlとtargetで切り替える、秘密はCIやdbt Cloudのセキュアストアから注入、env_varの既定値を理解している、が鍵です。

また、開発から本番まで同一パイプラインで構成を差し替えられるか、ログ/メタデータに秘密が出ていないか、といった運用面の判断問題も出題されます。

  • env_var('KEY', 'default')の既定値と未設定時の挙動
  • profiles.ymlのJinjaレンダリングとtarget.nameの参照
  • スキーマ/DB名の命名規則で環境衝突を回避
  • CIログで秘密をマスクし、リポジトリに直書きしない

環境を切り替えて実行する例(コマンド)

# CIターゲットで実行
DBT_TARGET_NAME=ci DBT_ENVIRONMENT=ci dbt run --target ci

# ローカル開発(デフォルトのdevにフォールバック)
dbt run  # profiles.ymlのtarget: dev が使われることを想定

# 明示的にprodを指定(本番は保護ブランチ/承認必須が望ましい)
DBT_TARGET_NAME=prod dbt test --target prod

問題で確認

Analytics Engineer

問題 1

Snowflakeに接続するdbt CoreプロジェクトをCIで実行する。パスワードをリポジトリに含めず、ブランチごとにスキーマを切り替えたい。最も適切な組み合わせはどれか?

  1. profiles.ymlのpasswordやschemaをenv_varで参照し、CIのシークレットから環境変数を注入。ターゲット名はciに固定し、DBT_SCHEMAをブランチ名で上書きする
  2. dbt_project.ymlにpasswordをvarsとして定義し、モデル内で{{ var('password') }}を参照する。スキーマはSQL内のcase文で分岐する
  3. profiles.ymlに開発/本番の固定値を書き分け、CIでは何も注入しない。ブランチごとに手動でprofiles.ymlを書き換える
  4. モデル内でos.environ['SNOWFLAKE_PASSWORD']を直接参照し、コンパイル済みSQLに書き込む

正解: A

秘密はCIのシークレットストアから環境変数で注入し、profiles.ymlでenv_varを使って参照するのが標準かつ安全。スキーマはDBT_SCHEMA等で外だしし、ターゲットはciに固定して構成で切り替える。varsにパスワードを置く・SQLで分岐・手作業変更は非推奨。

よくある質問

env_varとvarsの違いは?どちらに秘密を置くべき?

env_varはOS環境変数をJinjaから参照する仕組み、varsはdbtのユーザー変数です。秘密値はvarsではなく、CIやdbt Cloudのシークレットストア→環境変数→env_varで参照するのが原則です。

dbt Cloudではどう環境変数を使う?

EnvironmentやJobの設定で環境変数を登録し、モデルやdbt_project.yml/profiles.ymlのJinjaでenv_var('KEY')として参照します。値はUIで管理され、リポジトリには含まれません。

未設定の環境変数を検知して安全に失敗させるには?

env_var('KEY')のdefaultを省略すると未定義でコンパイルエラーになります。あるいはJinjaで検査し、exceptions.raise_compiler_errorで明示的に停止させる方法も有効です。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
dbt

dbt Model の基礎: SQL で定義する変換の最小単位

Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...

dbt

dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点

dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...

dbt

dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点

dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...

dbt

dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト

Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....

dbt

dbt_project.yml の読み方:主要設定と命名を最短で掴む

dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...

dbtの記事一覧 (101件)
© 2026 NicheeLab All rights reserved.