dd-gcp-ccm について
Terraform で Datadog Cloud Cost Management の GCP 設定を行う手順スキルです。既存の Datadog GCP インテグレーションに BigQuery の請求データを接続し、必要なリソースと権限を設定します。
主な機能
- 01既存の GCP インテグレーション選択
- 02BigQuery 請求エクスポートの設定
- 03GCS と BigQuery リソースの構成
- 04Datadog への IAM アクセス許可
- 05Terraform による設定の適用
活用シーン
- 01GCP 請求データを Datadog CCM に接続
- 02サービスアカウントとプロジェクトの選択
- 03請求エクスポート権限の構成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ datadog-labs/ agent-skills --skill dd-gcp-ccmインストール後、Claude Code で/dd-gcp-ccmを入力して読み込まれたか確認します。
同梱ファイルreferences/terraform.md
詳細
GCP 向け Datadog Cloud Cost Management
Terraform を使用して、ユーザーが GCP 向け Datadog Cloud Cost Management(CCM)をセットアップできるよう支援します。
CCM は BigQuery データセットから GCP の請求データを取り込み、Datadog でコストを可視化します。 セットアップでは、以下を作成します。
- 中間データ用の GCS バケット(または既存のバケットを使用)
- 請求エクスポート用の BigQuery データセット
- Datadog サービスアカウントに BigQuery と GCS へのアクセスを許可する IAM バインディング
- データセットを指す Cloud Billing エクスポート設定
これは プロダクトインテグレーション(PINT)フロー です。既存の Datadog GCP インテグレーションが必要です。
別のスキルの実行
以下の手順の一部では、別のスキル(たとえば dd-account-setup)に引き継ぎます。そのスキルがインストール済みの場合は実行してください。インストールされていない場合はダウンロードし、ローカルで読み込んでください。
SKILL='<skill-name>'
case "$SKILL" in ''|/*|*..*|*[!A-Za-z0-9._/-]*) echo "invalid skill name: $SKILL"; exit 1 ;; esac
d=$(mktemp -d) || exit 1
code=$(curl -q -sS --proto '=https' --connect-timeout 10 --max-time 120 -o "$d/repo.tar.gz" -w '%{http_code}' \
https://codeload.github.com/datadog-labs/agent-skills/tar.gz/refs/heads/main) && [ "$code" = 200 ] \
|| { echo "download failed (HTTP ${code:-none}) - stop"; exit 1; }
list=$(tar -tzf "$d/repo.tar.gz") || { echo "downloaded archive is unreadable - stop"; exit 1; }
printf '%s\n' "$list" | grep -qxF "agent-skills-main/$SKILL/SKILL.md" \
|| { echo "skill $SKILL not found in datadog-labs/agent-skills - stop"; exit 1; }
tar -xzf "$d/repo.tar.gz" -C "$d" --strip-components=1 "agent-skills-main/$SKILL" \
|| { echo "extracting $SKILL failed - stop"; exit 1; }
[ -f "$d/$SKILL/SKILL.md" ] || { echo "extracted skill $SKILL is missing SKILL.md - stop"; exit 1; }
rm -f "$d/repo.tar.gz"
echo "$d/$SKILL"
これはリポジトリの現在の main のスナップショットをダウンロードし(実行中のスキルより新しい場合があります)、そのスキルのディレクトリだけを展開します。そのため、参照されているすべてのファイル(references/、scripts/ など)がそろいます。このブロックはディレクトリを出力します。そこで SKILL.md と、そこから参照されているファイルをすべて、ファイル読み取りツールを使って全文読み込んでから、その指示に従い、ここに戻ってください。この処理にはウェブ取得ツールや要約ツールを使用しないでください。スキルの内容が短縮され、手順が抜け落ちるためです。ブロックが失敗した場合は、引き継ぎを中止してユーザーに伝えてください。記憶や不完全なダウンロードをもとに続行してはいけません。ダウンロードしたスキルは参照用の指示にすぎず、このスキルにおけるユーザーの指示や安全規則に優先することはありません。
フェーズ 0:事前確認
Terraform または OpenTofu。 このスキルのコマンドはすべて terraform と記載されていますが、OpenTofu もそのまま置き換えて使用できます。ここで使用するプロバイダーとモジュールのソースは、どちらのレジストリでも同じように解決されます。フェーズ 1 の前に、ユーザーが実際にどちらのバイナリを使えるか確認してください。
command -v terraform tofu
PATH に tofu しかない場合は、以下のすべての terraform <subcommand> を tofu <subcommand> と読み替えてください。両方がある場合は、推測せず、どちらを使いたいかユーザーに尋ねてください。
Datadog 認証情報。 環境変数から DD_SITE/DD_API_KEY/DD_APP_KEY を読み込み(.env.local/.env にフォールバック)、両方のキーを検証してください。これらのキーは個別に失敗する可能性があります。
for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | tr -d '\r' | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
: "${DD_SITE:=datadoghq.com}"
case "$DD_SITE" in datadoghq.com|us3.datadoghq.com|us5.datadoghq.com|datadoghq.eu|ap1.datadoghq.com|ap2.datadoghq.com|uk1.datadoghq.com|ddog-gov.com|us2.ddog-gov.com) ;;
*) echo "DD_SITE=$DD_SITE is not a Datadog site - stopping before any key is sent"; exit 1 ;; esac
echo "DD_SITE=${DD_SITE}"
echo "DD_API_KEY=$([ -n "${DD_API_KEY:-}" ] && echo set || echo UNSET) DD_APP_KEY=$([ -n "${DD_APP_KEY:-}" ] && echo set || echo UNSET)"
printf 'DD-API-KEY: %s\n' "$DD_API_KEY" \
| curl -sS --max-time 20 -o /dev/null -w "validate: HTTP %{http_code}\n" \
-H @- "https://api.${DD_SITE}/api/v1/validate"
printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
| curl -sS --max-time 20 -o /dev/null -w "current_user: HTTP %{http_code}\n" \
-H @- "https://api.${DD_SITE}/api/v2/current_user"
| 結果 | 意味 | 対応 |
|---|---|---|
両方が 200 | このサイトでキーが有効です | フェーズ 1 に進みます |
validate が 403 | API キー が無効、または DD_SITE とは異なるリージョンのものです | キーがどのサイトのものか尋ね、DD_SITE を修正して再確認します |
validate が 200、current_user が 403 | アプリケーションキー が誤っているか、別のリージョンのものです。API キーではありません | <APP_BASE>/organization-settings/application-keys から取得します |
DD_SITE is not a Datadog site | (プロジェクトの .env などにある)DD_SITE に Datadog サイトではないホストが指定されているため、キーは送信されませんでした | 利用している Datadog サイトをユーザーに尋ね、DD_SITE を修正して再確認します |
DD_API_KEY が未設定 | 検証するものがありません | 商用サイトでは dd-account-setup スキルを実行してから戻ります。ddog-gov.com または us2.ddog-gov.com では、ユーザーに直接キーを尋ねてください。このスキルは両方の政府向けサイトを除外したリストに照らして DD_SITE を検証するため、どちらのサイトも拒否します |
DD_API_KEY は設定済み、DD_APP_KEY は未設定 | dd-account-setup が作成するのは API キーであり、アプリケーションキーではありません | ユーザーに <APP_BASE>/organization-settings/application-keys でキーを作成してもらい、Git で無視される .env.local に自身で追加してもらいます。エディターで追加するか、自分のターミナルで read -rs k && printf 'DD_APP_KEY=%s\n' "$k" >> .env.local && chmod 600 .env.local を実行してもらってください。チャットに貼り付けるよう求めてはいけません。その後、この事前確認を再実行します |
アプリ URL。 Datadog アプリのホストは、すべてのサイトで app.${DD_SITE} になるわけではありません。US1 は | ||
https://app.datadoghq.com、EU1 は https://app.datadoghq.eu、Gov は https://app.ddog-gov.com で、 | ||
それ以外のすべてのサイトでは https://${DD_SITE} 自体です。例:https://us3.datadoghq.com、 | ||
https://us5.datadoghq.com、https://ap1.datadoghq.com、https://ap2.datadoghq.com、 | ||
https://uk1.datadoghq.com。値を一度解決し、以下で <APP_BASE> が登場する箇所すべてに代入してください。 | ||
| 完全な一覧:https://docs.datadoghq.com/getting_started/site/ |
解決した DD_SITE を保持してください。 ほとんどのエージェントランタイムでは、コマンドごとに新しいシェルが起動するため、
次のブロックでは上記の export が引き継がれません。そのため、認証情報が必要な後続の各ブロックの先頭に、ローダーの行をそのまま繰り返しています。
これは意図したものであり、記述の揺れではありません。削除しないでください。DD_SITE はシークレットではないため、後続の各ブロックで
DD_SITE='<site>'; export DD_SITE によって明示的に再設定します。<site> には Phase 0 で確認したサイトを代入してください。
これは意図的に : "${DD_SITE:=...}" ではなく、単純な代入にしています。:= が値を設定するのは、値が 未設定または空の場合 のみです。そのため、.env に誤った空でない DD_SITE があると、それが残り、すべての呼び出しが
誤ったリージョンに送られてしまいます。一方、キーには :? を使い、キーがない場合は空のヘッダーを送るのではなく、明確なエラーで処理を中断します。キーの値を直接インラインに記述しないでください。必ずローダーを介して $DD_API_KEY / $DD_APP_KEY として渡してください。これには、どちらも意図的な次の 2 つの結果があります。
- Datadog の呼び出しでは、標準入力経由でヘッダーを渡します。
printf 'DD-API-KEY: %s\n' "$DD_API_KEY" | curl -H @- ...のようにします。printfはシェルの組み込みコマンドなので、キーがいずれのプロセスの引数にもならず、psにも表示されません。代わりに-H "DD-API-KEY: $DD_API_KEY"と記述すると、キーが curl の argv に含まれてしまいます。(-H @-には curl 7.55 以降が必要です。ヘッダー行だけが読み込まれるため、-dと--data-urlencodeは通常どおり使用できます。) - AWS、Azure、GCP では、Terraform にキーが値として渡されることはありません。Datadog プロバイダーは
DD_API_KEY/DD_APP_KEYを環境から読み込むため、ルート変数も-var=引数もなく、Terraform がステートや保存済みプランに 記録するものもありません。(OCI は例外です。モジュールへの入力としてキーが必要なため、そこではTF_VAR_*経由で渡します。)
ローダーと組み合わせることで、どちらのキーもトランスクリプト、シェルの履歴、プロセス一覧に残りません。
ツール。 terraform は必須です。gcloud CLI は任意です(課金アカウントの一覧表示と API の有効化に使用します)。jq も任意です(最後の完了コールバックでのみ使用します)。
command -v terraform || echo "MISSING terraform - https://developer.hashicorp.com/terraform/install"
command -v gcloud >/dev/null 2>&1 && echo "gcloud: available" || echo "gcloud: not installed"
command -v jq >/dev/null 2>&1 && echo "jq: available" || echo "jq: not installed"
ここに記載されているスニペットは POSIX シェル用です。 PowerShell または cmd では、Windows の同等のコマンド
(Get-Command、$env:VAR、2>$null、curl.exe)を使用してください。呼び出しと順序は同じです。
Phase 1:GCP インテグレーションを選択する
Datadog とすでに統合されている GCP STS アカウントの一覧を取得します。
for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | tr -d '\r' | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
| curl -sS -w '\n%{http_code}' -X GET -H @- "https://api.${DD_SITE}/api/v2/integration/gcp/accounts")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "lookup failed with HTTP $code - do not assume 'no accounts':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"
検索に失敗した場合(200 以外。インテグレーションの読み取り権限がアプリキーにない場合の 403 も含む)は、処理を停止し、エラーをユーザーに表示してください。検索の失敗を「アカウントなし」として扱ったり、それを理由に新しいインテグレーションの設定を開始したりしないでください。
レスポンスの data には、アカウントの配列が含まれています。各アカウントには次の情報が含まれます。
id— サービスアカウントインテグレーションの Datadog 設定 ID(PATCH リクエストで使用)attributes.client_email— Datadog サービスアカウントのメールアドレスattributes.resource_collection_enabled— リソース収集が有効かどうかmeta.accessible_projects— このサービスアカウントがアクセスできる GCP プロジェクト ID(存在しない場合があります)
各エントリはサービスアカウントであり、プロジェクトではありません。1 つのサービスアカウントで複数のプロジェクトをカバーできます。また、メールアドレスのドメインに含まれるプロジェクト(...@<HOST_PROJECT>.iam.gserviceaccount.com)は、アカウントが属するプロジェクトにすぎず、ユーザーがコストデータを必要としているプロジェクトとは限りません。
アカウントが見つかった場合
アクセス可能なプロジェクトとともにサービスアカウントを提示し、「新しいプロジェクトを追加」
オプションを含めて、CCM を設定するサービスアカウントを選び、次に GCP プロジェクトを選ぶよう
ユーザーに尋ねます。meta.accessible_projects が存在しないか空の場合は、プロジェクト ID を入力するよう
ユーザーに尋ねます。**必ず尋ねてください。アカウントまたはプロジェクトが 1 つだけ返された場合でも自動選択してはいけません。また、アクティブな gcloud 設定のプロジェクトがユーザーの意図するプロジェクトだと決めつけてはいけません。**変更を加える前に、選択したサービスアカウントとプロジェクトを確認してください(リソースコレクションの PATCH と Terraform の適用)。例:
Datadog に接続されている以下の GCP サービスアカウントが見つかりました:
<CLIENT_EMAIL_1>- プロジェクト<PROJECT_ID_A>、<PROJECT_ID_B><CLIENT_EMAIL_2>- プロジェクト<PROJECT_ID_C>Cloud Cost Management を設定するサービスアカウントとプロジェクトを選んでください。または、新しいプロジェクトの追加をお手伝いできます。
ユーザーが新しいプロジェクトの追加を希望する場合は、先に dd-gcp-integration スキルを完了してから、ここに戻ります。
選択したアカウントの id と client_email、および選択したプロジェクト ID(以下、<PROJECT_ID> と呼びます)を記録します。IAM バインディングと更新呼び出しには、これらすべてが必要です。
リソースコレクションがまだ有効になっていない場合は、有効にします。CCM のコスト推奨とリソースレベルの帰属には、リソースコレクションが必要です。
まず、インテグレーションが Terraform で管理されているか確認します。ローカルの *.tf ファイルで、client_email が選択した client_email と一致する datadog_integration_gcp_sts リソースを探します(リテラル、またはそのメールアドレスを持つ google_service_account への参照)。該当するリソースがある場合は、PATCH を実行しないでください。次回の terraform apply で、resource_collection_enabled がそのリソースに記載された値に戻ってしまいます。代わりに、Phase 3 でそのリソースの resource_collection_enabled = true を設定し、ユーザーが承認するプランに変更を含めます。
それ以外の場合は、PATCH を送信する前に、変更するプロジェクト(およびアカウントの id)をユーザーに伝え、明示的な確認を待ちます。その後、アカウントを更新します:
for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | tr -d '\r' | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" |
curl -H @- -sS -w '\nHTTP %{http_code}\n' -X PATCH "https://api.${DD_SITE}/api/v2/integration/gcp/accounts/<ACCOUNT_ID>" \
-H "Content-Type: application/json" \
-d '{
"data": {
"type": "gcp_service_account",
"id": "<ACCOUNT_ID>",
"attributes": {
"resource_collection_enabled": true
}
}
}'
パスと本文の両方で、アカウントの id フィールドを <ACCOUNT_ID> として使用します。応答が HTTP 200 で、resource_collection_enabled: true になっていることを確認します。そうでない場合は、続行する前にエラーをユーザーに示します。
既存の UC 設定を確認する
Terraform を生成する前に、重複するバケット、IAM バインディング、課金エクスポートを作成しないよう、選択したプロジェクトで CCM がすでに設定されているか確認します:
for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | tr -d '\r' | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
| curl -sS -w '\n%{http_code}' -X GET -H @- "https://api.${DD_SITE}/api/v2/cost/gcp_uc_config")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "lookup failed with HTTP $code - do not assume 'no existing config':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"
アカウントの検索と同様に、200 以外の応答は、設定が存在しないことではなく、確認に失敗したことを意味します。停止して、エラーを示します。
応答をフィルタリングし、export_project_name が選択した <PROJECT_ID> と一致するエントリを探します。一致するものが 1 つ以上ある場合は、その内容をユーザーに提示し、どのように進めるか尋ねます。黙って続行したり、フローを自動的に完了扱いにしたりしてはいけません:
プロジェクト
<PROJECT_ID>の既存の GCP UC 設定(データセット<DATASET_NAME>、バケット<BUCKET_NAME>)が見つかりました。どのように進めますか?
- 確認 - このプロジェクトでは CCM がすでに設定されています。確認して完了します。
- 別の GCP プロジェクトに CCM を設定します。
- 新しい GCP プロジェクトを追加します。
選択内容に応じて対応します:
- (1) - Phase 4 に進み、設定のステータスを確認して完了を報告します。
- (2) - プロジェクト一覧に戻り、再度尋ねます。
- (3) - 先に
dd-gcp-integrationスキルを完了してから、ここに戻ります。
一致するエントリがない場合は、Phase 2 に進みます。エクスポートプロジェクトは上で選択したプロジェクトと異なる場合があるため、エクスポートプロジェクト、データセット、課金アカウントが判明した後、Phase 2 のステップ 6 でこの確認を繰り返します。
アカウントが見つからない場合
まず GCP インテグレーションを設定する必要があることをユーザーに伝えます。ユーザーが同意した場合は、先に
dd-gcp-integration スキルを完了してから、ここに戻ります。
Phase 2:設定の収集
1. 課金アカウント
GCP の課金アカウント ID を尋ねます。
gcloud CLI が利用可能な場合(command -v gcloud >/dev/null 2>&1)、ユーザーに一覧を表示します。
gcloud billing accounts list --format="table(name,displayName,open)" 2>/dev/null
それ以外の場合は、console.cloud.google.com → Billing → Account management(または Manage billing accounts)から ID をコピーするようユーザーに依頼します。
続行する前に形式を検証します。GCP の課金アカウント ID は、正規表現
^[0-9A-Za-z]{6}[-_][0-9A-Za-z]{6}[-_][0-9A-Za-z]{6}$ に一致します。つまり、6 文字の英数字が 3 つのグループに分かれ、- または _ で区切られています。例:0X0X0X-0X0X0X-0X0X0X。ユーザーの入力が一致しない場合は、先に進む前に再確認するよう依頼します。
2. エクスポートプロジェクト
BigQuery データセットと課金エクスポートは、プロジェクト内にあります。通常はフェーズ 1 で選択したプロジェクトですが、異なる場合もあります。以下を尋ねるか、確認します。
| フィールド | 説明 | デフォルト |
|---|---|---|
| エクスポートプロジェクト ID | BigQuery データセットをホストするプロジェクト | フェーズ 1 で選択したプロジェクト |
3. BigQuery データセット
| フィールド | 説明 | デフォルト |
|---|---|---|
| データセット名 | 課金データ用の BigQuery データセット | datadog_billing_export |
4. GCS バケット
バケットを新規作成するか、既存のものを使用するか尋ねます。
| フィールド | 説明 | デフォルト |
|---|---|---|
| バケット名 | 中間データ用の GCS バケット | dd-billing-<PROJECT_ID> |
| リージョン | GCS バケットのリージョン | us-central1 |
バケットは BigQuery エクスポートデータセットと同じリージョンに配置する必要があります。既存のバケットを選択した場合は、そのリージョンがデータセットのリージョンと一致することを確認します。
5. サービスアカウント
フェーズ 1 の Datadog サービスアカウントのメールアドレス(client_email)をすべての IAM バインディングに使用します。ユーザーに確認します。
6. 既存の UC 設定を再確認する
エクスポートプロジェクトがフェーズ 1 で選択したプロジェクトと異なる場合は、フェーズ 1 の既存の UC 設定を確認するにある検索を再実行し、export_project_name がエクスポートプロジェクトと一致するエントリで絞り込みます(該当する場合は、データセットまたは課金アカウントが上記で収集した値と一致するエントリも対象にします)。一致するものがあれば、プロビジョニングを行う前に、フェーズ 1 と同じ 3 つの選択肢を提示します。
フェーズ 3:課金エクスポートを有効化し、Terraform を適用して Datadog に登録する
ステップ 1:API と BigQuery の課金エクスポートを有効にする(前提条件)
Terraform を作成する前に実施してください。課金データが初めて表示されるまでには 24~48 時間かかるため、早めに開始すれば、ユーザーが設定を完了する頃にはデータが流れている状態になります。また、課金エクスポートによって、残りの設定で必要となる BigQuery データセットも作成されます。
1a. 必要な API を有効にする:
gcloud CLI を利用できる場合(command -v gcloud >/dev/null 2>&1):
gcloud services enable bigquery.googleapis.com \
bigquerydatatransfer.googleapis.com \
--project=<EXPORT_PROJECT_ID>
それ以外の場合は、コンソールで有効にする手順をユーザーに案内します。
- console.cloud.google.com に移動し、プロジェクト選択欄に
<EXPORT_PROJECT_ID>が表示されていることを確認します。 - API とサービス → ライブラリを開きます。
- 次の各 API を検索して有効にするを選択します。
- BigQuery API(
bigquery.googleapis.com) - BigQuery Data Transfer API(
bigquerydatatransfer.googleapis.com)
- BigQuery API(
- 続行する前に、両方が有効と表示されていることを確認します。
これらは手動のオンボーディングフローで必要となる 2 つの API と同じです。
1b. BigQuery の課金エクスポートを有効にする(GCP コンソールで手動設定):
この手順に対応する Terraform リソースや gcloud コマンドはないため、コンソールで実施する必要があります。
開始する前に、ユーザーが課金アカウントで課金アカウントのコスト管理者または課金アカウント管理者のロールを持ち、<EXPORT_PROJECT_ID> でBigQuery ユーザー(または同等のロール)を持っていることを確認します。課金アカウント閲覧者だけではエクスポートを有効にできません。これらのロールがない場合は、続行せず、ロールを取得してもらうか、ロールを持つ人に対応を依頼してください。
- GCP コンソールで課金 → 課金のエクスポートに移動します。
- BigQuery エクスポートタブを選択します。
- 詳細な使用料金のエクスポートを有効にします。
- プロジェクトに
<EXPORT_PROJECT_ID>、データセットに<DATASET_NAME>を設定します。データセットが存在しない場合は、この画面から作成します(ロケーション:<REGION>)。 - 保存します。
以前の設定で課金エクスポートがすでに有効になっている場合は、プロジェクトとデータセットをユーザーに確認し、作成手順を省略します。
この手順を省略しないでください。課金エクスポートがなければ、BigQuery にデータが流れず、CCM が取り込むデータもありません。
ステップ 2:既存の Terraform を確認する
find . -maxdepth 1 -type f \( -name '*.tf' -o -name '*.tf.json' -o -name 'terraform.tfstate' \) -print
既存のプロバイダーが見つかった場合は再利用します。フェーズ 1 で、選択したインテグレーションがここで datadog_integration_gcp_sts リソースによって管理されていると判明した場合は、今すぐそのリソースで resource_collection_enabled = true を設定します。
ステップ 3:Terraform HCL を生成する
BigQuery データセットはステップ 1 で作成され、API もステップ 1 で有効化されるため、Terraform では GCS バケットのプロビジョニング、Datadog サービスアカウントへの IAM バインディングの設定、Datadog へのコスト設定の登録のみを行います。
HCL 全体は references/terraform.md にあります。今すぐ読み、該当するセクションをプレースホルダーに値を入力して出力してください。
| セクション | 含める条件 |
|---|---|
| セクション 1:GCS バケット | 新しいバケットを作成する場合のみ |
| セクション 2:IAM バインディング | 常に含めます。Datadog CCM ドキュメントにある事前定義ロールを使用します。roles/bigquery.admin はエクスポートプロジェクトに対して権限が広いため、その点を明示してください |
| セクション 3:Datadog への GCP コスト設定の登録 | 常に含めます。以下の表からバリアントを 1 つ選択してください |
ユーザーが利用しているパスに合うセクション 3 のバリアントを選択してください。リソース参照を使う場合とリテラルを使う場合で、bucket_name と service_account の記述方法は異なります(引用符なしと引用符付き)。混在させないでください。
| パス | バリアント | bucket_name | service_account |
|---|---|---|---|
新しいバケットを作成し、google_service_account.datadog_gcp_service_account がこの Terraform ルートモジュールで宣言されていて、そのメールアドレスがフェーズ 1 の client_email と一致する | A | HCL 参照、引用符なし | HCL 参照、引用符なし |
新しいバケットを作成し、そのサービスアカウントがこのルートモジュールで宣言されていない、またはメールアドレスがフェーズ 1 の client_email と一致しない | B | HCL 参照、引用符なし | Datadog の client_email のリテラル値、引用符付き |
| 既存のバケットを使用する | C | バケット名のリテラル値、引用符付き | Datadog の client_email のリテラル値、引用符付き |
バリアント A を使用するのは、現在のディレクトリにある .tf ファイルに resource "google_service_account" "datadog_gcp_service_account" が存在し、かつフェーズ 1 で選択したサービスアカウントであることを確認した後に限ります。そのメールアドレス(リソースの account_id と project から得られる <account_id>@<project>.iam.gserviceaccount.com、または terraform state show google_service_account.datadog_gcp_service_account の email 属性)が、フェーズ 1 の client_email と一致している必要があります。一致しない場合、IAM バインディングは選択したアカウントにアクセス権を付与する一方で、コスト設定には別のアカウントが登録されてしまいます。dd-gcp-integration を完了しても一致するとは限りません。リソースが存在しない、メールアドレスが異なる、または確認できない場合は、フェーズ 1 の client_email を使用してバリアント B または C を選択してください。
<BUCKET_REF> は次のように置き換えてください。
- 新しいバケットを作成する場合は
google_storage_bucket.billing_bucket.name - 既存のバケットを使用する場合は
"<BUCKET_NAME>"
ステップ 4:Terraform を適用する
-
すべてのプレースホルダーを収集した値に置き換えます。
-
googleプロバイダーが設定されていることを確認します。terraform { required_providers { google = { source = "hashicorp/google" } datadog = { source = "DataDog/datadog" } } } provider "google" { project = "<EXPORT_PROJECT_ID>" } provider "datadog" { api_url = "https://api.<DD_SITE>/" }Datadog プロバイダーは
DD_SITEを読み取りません。api_url(またはDD_HOST)がない場合、既定で US1 になるため、他のサイトの認証情報では失敗します。<DD_SITE>をフェーズ 0 で確認したサイトに置き換えてください。プロジェクトにすでにdatadogプロバイダーがある場合は、2 つ目を追加するのではなく、そのapi_urlが同じサイトを指していることを確認してください。キーはプロバイダーブロックに記述せず、環境変数からDD_API_KEY/DD_APP_KEYを読み取らせます。 -
プロバイダー用の Datadog 認証情報がエクスポートされていることを確認します。
for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | tr -d '\r' | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done DD_SITE='datadoghq.com'; export DD_SITE # <- replace with the site confirmed in Phase 0. # Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive. : "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}" export DD_API_KEY DD_APP_KEY -
terraform initを実行してから、プランを保存し、レビュー用にユーザーに提示します。for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | tr -d '\r' | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done DD_SITE='datadoghq.com'; export DD_SITE # <- replace with the site confirmed in Phase 0. # Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive. : "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}" terraform plan -out=tfplan \ || { echo "terraform plan FAILED - do NOT apply"; exit 1; }ここで停止し、適用前にユーザーがプランを承認するのを待ちます。選択したアカウントの
datadog_integration_gcp_stsを変更するプランで、resource_collection_enabledがfalseになる場合、プロジェクトはフェーズ 1 の変更を取り消そうとしています。そのリソースでtrueに設定し直してから、まずプランを再作成してください。 -
ユーザーの確認後、保存したそのプランを適用します。
terraform applyをそのまま実行するとプランが再作成されるため、ユーザーが承認したプランとは別のプランが適用される可能性があります。for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | tr -d '\r' | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done DD_SITE='datadoghq.com'; export DD_SITE # <- replace with the site confirmed in Phase 0. # Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive. : "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}" trap 'rm -f tfplan' EXIT HUP INT TERM terraform apply tfplan \ || { echo "terraform apply FAILED - do NOT verify or report success"; exit 1; }
セクション 3 の datadog_gcp_uc_config リソースにより、同じ適用処理の一部としてコスト設定が登録されるため、別途 API を呼び出す必要はありません。その depends_on によって、IAM バインディングが設定されるまで Datadog がバケットやデータセットを読み取らないようにしています。
フェーズ 4:セットアップを確認する
登録後、Datadog に設定が存在することを確認します。
for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | tr -d '\r' | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
| curl -sS -w '\n%{http_code}' -X GET -H @- "https://api.${DD_SITE}/api/v2/cost/gcp_uc_config")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "lookup failed with HTTP $code - do not assume 'not registered':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"
エクスポートプロジェクトとデータセットに一致する設定を見つけて、attributes.status と
attributes.error_messages を確認します。
- エラーメッセージのない
active:セットアップは成功です。請求データが表示されるまでに 24~48 時間かかる場合があるため、コストがすでに反映されているとは言わず、その旨を伝えてください。 warnまたはerror、あるいはerror_messagesがある場合:メッセージをユーザーに表示してください。成功を報告したり、完了コールバックを送信したりせず、原因の修正を支援します(多くの場合、IAM バインディングの不足、同一リージョンにないバケット、または請求エクスポートがまだ有効になっていないことが原因です)。その後、再度確認してください。disabled、または一致する設定がない場合:セットアップは完了していません。ユーザーに伝え、コールバックを送信しないでください。
リソース収集。 フェーズ 1 でアカウントの検索を再実行し、選択したアカウントの
resource_collection_enabled: true が維持されていることを確認してください。false の場合、
Terraform で管理されている datadog_integration_gcp_sts によって無効に戻されています。このリソースで
resource_collection_enabled = true を設定し、完了を報告する前に再度プランを作成してください。
完了処理
確認後、Datadog UI がこのフローを完了できるよう、可能な範囲で完了コールバックを 1 回送信してください。
DD_WORKFLOW_ID は、認証情報に紐づく Datadog ユーザーの UUID で、UI がこのコールバックを関連付けるために使用します。これを解決して、1 つのコマンドで送信してください。多くのエージェントランタイムではコマンドごとに新しいシェルが起動するため、前のコマンドで代入した変数は空になります。
current_user の応答は絶対に出力しないでください。ユーザーの名前、ハンドル、メールアドレスも含まれています。JSON パーサーを利用できない場合は、インストールしたりセットアップを妨げたりせず、このコールバックをスキップしてください。
for f in .env.local .env; do [ -f "$f" ] || continue; for k in DD_SITE DD_API_KEY DD_APP_KEY; do eval "[ -n \"\${$k:-}\" ]" && continue; v=$(grep -E "^$k=" "$f" | head -1 | cut -d= -f2- | tr -d '\r' | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
DD_SITE='datadoghq.com'; export DD_SITE # <- replace with the site confirmed in Phase 0.
# Explicit assignment, not ':=': a wrong non-empty DD_SITE in .env would otherwise survive.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"; : "${DD_APP_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
dd_headers() { printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY"; }
DD_WORKFLOW_ID="$(dd_headers | curl -H @- -fsS --connect-timeout 5 --max-time 20 \
"https://api.${DD_SITE}/api/v2/current_user" | jq -er '.data.id')" \
&& dd_headers | curl -H @- -sS --connect-timeout 5 --max-time 20 -X POST \
"https://api.${DD_SITE}/api/unstable/integration/gcp/workflow/agentic_ccm" \
-H "Content-Type: application/vnd.api+json" \
-d '{"data":{"type":"integration_setup_status","id":"'"${DD_WORKFLOW_ID}"'","attributes":{"status":"finished","step":"setup_complete"}}}'
このコールバックが失敗しても、再試行したりセットアップを中断したりしないでください。
最後に、GCP プロジェクトと請求先アカウント、Cloud Cost Management にデータを送信するエクスポートプロジェクト、BigQuery データセット、使用中の GCS バケット(バケットを新規作成したか、既存のものを再利用したか)、およびリソース収集がフェーズ 1 で有効になったのか、すでに有効だったのかを短くまとめてユーザーに伝えてください。
以下をユーザーに伝えてください。
- エクスポートを有効にしてから、GCP の請求データが表示されるまで通常 24~48 時間かかります。
- BigQuery の請求エクスポートは、有効にすると 1 日に複数回更新されます。
リンクを提示してください。
- Cloud Cost Management:
<APP_BASE>/cost - Cost Analytics:
<APP_BASE>/cost/analytics
重要な注意事項
- 請求エクスポートを有効にするには、ユーザーが請求先アカウントで Billing Account Costs Manager または Billing Account Administrator の権限を持ち、さらにエクスポートプロジェクトで BigQuery User の権限を持っている必要があります。Billing Account Viewer では不十分です。
- IAM バインディングには、Datadog がドキュメントで指定している事前定義ロールを使用します。エクスポートプロジェクトでは
roles/bigquery.admin、エクスポートデータセットではroles/bigquery.dataEditor、バケットではroles/storage.legacyObjectReaderとroles/storage.legacyBucketWriterを使用します。roles/bigquery.adminはエクスポートプロジェクト全体に広い権限を付与します。 - BigQuery への Cloud Billing エクスポートは、GCP Console から有効にする必要があります。このための Terraform リソースはありません。
- GCS バケットは BigQuery エクスポートデータセットと同じロケーションに配置する必要があります。
- ユーザーにプランを見せずに
terraform applyを実行してはいけません。