env_var() は便利だが、使い方を誤るとパスワードがコンパイル済みSQLやログに残る。試験でも実務でも、どこで評価され何に残るかを理解しておくことが重要。
本稿では、dbt-core の公式挙動に沿って安全な利用法とアンチパターン、CI/CD・Vault等の組み合わせ、監査の観点を整理する。
env_var(name, default=None) は、Jinja が評価されるタイミングで OS の環境変数を参照する。dbt における Jinja の主な評価点は、モデルやマクロのコンパイル時、dbt_project.yml・profiles.yml の読み込み時である。
重要なのは、SQL ファイル内で env_var() を使うと、その値がコンパイル済みSQL(target/compiled 配下)に埋め込まれうる点だ。シークレットは SQL へ埋め込まず、接続情報(profiles.yml)でのみ参照するのが原則。
profiles.yml は実行成果物(manifest.json, run_results.json, catalog.json)に含まれない。一方、dbt_project.yml の vars やモデルの config で与えた値は成果物へ含まれる可能性があるため、そこにシークレットを置くのは避ける。
profiles.yml での安全な参照例(Snowflake)
snowflake:
target: prod
outputs:
prod:
type: snowflake
account: "{{ env_var('SNOWFLAKE_ACCOUNT') }}"
user: "{{ env_var('SNOWFLAKE_USER') }}"
password: "{{ env_var('SNOWFLAKE_PASSWORD') }}"
role: "{{ env_var('SNOWFLAKE_ROLE') }}" # シークレットではない任意値でも default は慎重に
warehouse: "{{ env_var('SNOWFLAKE_WAREHOUSE') }}"
database: ANALYTICS
schema: CORE
シークレットが漏れやすい箇所は、コンパイル済みSQL、実行ログ、dbt の成果物(manifest.json 等)、CI/CD のジョブログ・環境ダンプだ。env_var() 自体は単に値を返すだけなので、どこで参照するかが決定的に重要になる。
dbt は一部の機微情報をマスクする実装を持つことがあるが、全てを保証できるわけではない。運用側で“出さない・残さない”設計を徹底する。
危険な例(モデル内での出力や SQL 埋め込み)
-- model.sql(やってはいけない)
{{ log(env_var('SNOWFLAKE_PASSWORD'), info=True) }} -- ログに出る
select '{{ env_var('SNOWFLAKE_PASSWORD') }}' as leaked; -- コンパイル物に残る
原則は、秘密は外部シークレットマネージャで保管し、CI/CD 実行時に環境変数として一時注入、dbt は profiles.yml の env_var() でのみ参照する。これにより秘密は SQL・成果物に入らず、ローテーションも容易になる。
dbt Cloud を使う場合は、プロバイダ連携やマネージドな接続設定を優先し、任意の env_var で秘密を扱わない。OSS 実行では CI プラットフォームのマスク機能(GitHub Actions secrets、GitLab CI variables 等)と組み合わせる。
GitHub Actions での一時注入例(OSS 実行)
jobs:
run-dbt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install dbt-snowflake
- name: Run dbt
env:
SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
SNOWFLAKE_WAREHOUSE: ${{ secrets.SNOWFLAKE_WAREHOUSE }}
run: |
dbt deps
dbt build --target prod
秘密を vars に入れる、モデルやマクロで log() 出力する、Jinja で SQL へ文字列埋め込みする、といったパターンはすべて長期的に漏えいリスクを高める。特に vars は成果物に残るため、禁止する。
未設定時の default で“通ってしまう”のも事故の温床。env_var() の存在チェック用にヘルパーマクロを用意し、欠落時は明示的に失敗させるとよい。
必須環境変数の検証マクロ(欠落なら失敗)
{% macro required_env_var(name) -%}
{% set val = env_var(name) %}
{% if not val %}
{{ exceptions.raise_compiler_error('Missing required env var: ' ~ name) }}
{% endif %}
{{ return(val) }}
{%- endmacro %}
# profiles.yml 側での利用例(Jinja 可)
password: "{{ required_env_var('SNOWFLAKE_PASSWORD') }}"
実務と試験の両面で正解となるのは、外部で保管し実行時に環境変数として注入、profiles.yml の env_var() でのみ参照する構成である。以下に代表的手段を比較する。
| 手段 | 可視化リスク(SQL/ログ/成果物) | ローテーション容易性 | 試験での推奨度 |
|---|---|---|---|
| dbt_project.yml の vars に格納 | 高い(成果物に載りやすい) | 低い(コード変更が必要) | 不可 |
| profiles.yml に平文ハードコード | 中(成果物には載らないが漏えい時の影響大) | 低い(配布・差替えが手作業) | 不可 |
| 外部 Secret → 環境変数 → profiles.yml の env_var() | 低い(SQL・成果物に残さない設計が可能) | 高い(外部で一括ローテーション) | 推奨(標準解) |
| dbt Cloud のマネージド接続 | 低い(プラットフォームが管理) | 高い(UI/API で更新) | 推奨(Cloud 利用時) |
| Vault 等の動的認証 + CI 注入 + env_var() | 低い(短命・最小権限で設計可能) | 高い(自動ローテーション) | 推奨(成熟運用) |
Databricks(トークン)例:profiles.yml
databricks:
target: prod
outputs:
prod:
type: databricks
host: "{{ env_var('DATABRICKS_HOST') }}"
http_path: "{{ env_var('DATABRICKS_HTTP_PATH') }}"
token: "{{ required_env_var('DATABRICKS_TOKEN') }}"
catalog: main
schema: core
監査観点では、成果物・コンパイル物・ログに秘密が出ていないかの機械検査、CI のマスク設定と権限分離、トークンの有効期限・ローテーションの定期点検が肝要。dbt 側は“profiles.yml の env_var() でのみ秘密参照”“vars・SQL へは出さない”の2点を守る。
試験対策としては、env_var() の評価タイミング、vars へ秘密を置くと manifest.json に残るという点、未設定時 default で通ってしまう危険、dbt Cloud ではプラットフォーム管理を優先、を押さえる。
安全なシークレットフロー(概念図)
[Secret Manager]
|
v (masked, short-lived)
[CI/CD Runner] --(env export)--> [Process Env]
|
v
[dbt env_var()]
|
v
[Adapter/Driver]
|
v
[Warehouse/BI]
モデルやマクロで“使わない”ためのガイドコメント例
{#
注意:
- env_var() をモデルSQLや log() に渡さないこと。
- シークレットは profiles.yml でのみ参照。
- 未設定は required_env_var() で即時失敗させる。
#}
Analytics Engineer
問題 1
OSS の dbt を GitHub Actions で実行する。Snowflake のパスワードを安全に扱う最も適切な方法はどれか?
正解: A
秘密は外部で保管し、実行時に環境変数として注入、profiles.yml の env_var() でのみ参照するのが安全かつ標準的。vars やモデル SQL、ログ出力は漏えいリスクが高く不適切。
dbt は .env ファイルを自動で読み込みますか?
いいえ。dbt-core 自身は .env を自動読込しない。シェルで export するか、CI/CD のシークレット機能で環境変数として注入する。外部の dotenv ツールを使う場合も、平文ファイルの取り扱いに注意すること。
env_var() の値は dbt の成果物に残りますか?
profiles.yml で接続情報として参照する分には成果物(manifest.json 等)に含まれない。一方、dbt_project.yml の vars やモデル/マクロで env_var() を使って値を構成すると、内容がコンパイル済みSQLや成果物へ入る可能性がある。
env_var() に default を指定しても良いですか?
シークレットには原則として指定しない。未設定時に既定値で“通る”と誤接続や検知遅延を招く。欠落時は required_env_var() 等で明示的に失敗させる。default はロール名など非機微・挙動が明確な項目に限定する。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
dbt Model の基礎: SQL で定義する変換の最小単位
Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...
dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点
dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...
dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点
dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...
dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト
Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....
dbt_project.yml の読み方:主要設定と命名を最短で掴む
dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...