mcpField
D
dd-gcp-integration

dd-gcp-integration

github.com/datadog-labsクラウド・DevOps18348 回インストール今日更新
リポジトリ

dd-gcp-integration について

TerraformでDatadogのGCP連携を設定する、対話型のスキルです。クラウド監視を設定する担当者向けに、認証情報の確認、対象範囲の選定、長期キーを使わないサービスアカウントの偽装を案内します。

主な機能

  1. 01TerraformによるGCP連携設定
  2. 02Datadog認証情報の検証
  3. 03委任プリンシパルの確認・作成
  4. 04プロジェクトとフォルダーの範囲確認
  5. 05適用前の確認取得

活用シーン

  1. 01選択したGCPプロジェクトのDatadog監視設定
  2. 02長期サービスアカウントキーを使わないアクセス設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/datadog-labs/agent-skills --skill dd-gcp-integration

インストール後、Claude Code で/dd-gcp-integrationを入力して読み込まれたか確認します。

同梱ファイルreferences/terraform.md

詳細

Datadog GCP インテグレーション

Terraform を使って Datadog GCP インテグレーションを設定するユーザーを支援します。

このインテグレーションでは、顧客のプロジェクトに GCP サービスアカウントを作成し、roles/iam.serviceAccountTokenCreator を使って Datadog のデリゲートプリンシパルがそのアカウントを偽装できるようにします。これにより、長期間有効なキーを完全に避けられます。

実際に操作しながら設定を進めます。コマンドをユーザーに渡すだけでなく、会話の中で自分で実行し、ユーザーに進捗を伝えてください。また、terraform apply の前に確認を求めてください。

別のスキルを実行する

以下の手順では、別のスキル(たとえば 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- | sed 's/^["'\'']//;s/["'\'']$//'); [ -n "$v" ] && export "$k=$v"; done; done
: "${DD_SITE:=datadoghq.com}"
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 が 403API キーが無効か、DD_SITE とは異なるリージョンのものですキーがどのサイトに属するか尋ね、DD_SITE を修正して再確認します
validate が 200、current_user が 403アプリキーが誤っているか、別のリージョンのものです。API キーではありません<APP_BASE>/organization-settings/application-keys から取得します
いずれかのキーが未設定検証するものがありません商用サイトの場合は dd-account-setup スキルを実行してから戻ります。ddog-gov.com または us2.ddog-gov.com の場合は、ユーザーにキーを直接尋ねてください。このスキルは、政府向けサイトを除外した一覧に照らして DD_SITE を検証するため、これらのサイトは拒否されます

アプリの URL。 Datadog アプリのホストは、すべてのサイトで app.${DD_SITE} になるわけではありません。https://app.datadoghq.com(US1)、https://app.datadoghq.eu(EU1)、https://app.ddog-gov.com(Gov)です。それ以外のすべてのサイトでは、https://us3.datadoghq.com、https://us5.datadoghq.com、https://ap1.datadoghq.com、https://ap2.datadoghq.com、https://uk1.datadoghq.com のように、https://${DD_SITE} 自体がアプリのホストになります。これを一度解決し、以下で <APP_BASE> が出てくる箇所に置き換えてください。全サイトの一覧:https://docs.datadoghq.com/getting_started/site/ 解決済みの DD_SITE を記憶してください。 ほとんどのエージェントランタイムではコマンドごとに新しいシェルが起動するため、上記の export は次のブロックでは引き継がれません。そのため、認証情報が必要な後続の各ブロックの先頭に、ローダー行をそのまま繰り返しています。これは意図的なもので、不要な重複ではありません。削除しないでください。DD_SITE はシークレットではないため、後続の各ブロックでは DD_SITE='<site>'; export DD_SITE を明示して自ら設定します。Phase 0 で確認したサイトに置き換えてください。これは意図的に : "${DD_SITE:=...}" ではなく、単純な代入にしています。:= は値が未設定または空の場合にしか設定しないため、.env に誤った空でない DD_SITE があると、そのまま残り、すべての呼び出しが誤ったリージョンに送信されてしまいます。一方、キーには :? を使っているため、キーがない場合は空のヘッダーを送るのではなく、エラーで明確に中断します。キーの値をインラインで記述しないでください。必ずローダーを介して $DD_API_KEY / $DD_APP_KEY として渡す必要があります。これにより、意図的に次の2つの結果が得られます。

  • Datadog への呼び出しでは、ヘッダーを stdin から渡します。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 が必要です。また、Phase 1 では jq も必要です。検出には gcloud CLI を任意で使用できますが、いずれの場合も google プロバイダーには GCP の認証情報が必要です(gcloud auth application-default login または GOOGLE_APPLICATION_CREDENTIALS)。

command -v terraform || echo "MISSING terraform - https://developer.hashicorp.com/terraform/install"
command -v jq || echo "MISSING jq - needed to read the delegate email in Phase 1"
command -v gcloud >/dev/null 2>&1 && echo "gcloud: available" || echo "gcloud: not installed"

jq を利用できない場合は、Phase 1 の生の JSON レスポンスから data.attributes.delegate_account_email を自分で読み取ってください。jq にパイプで渡す代わりに、こちらを使用します。

ここにあるスニペットは POSIX シェル用です。 PowerShell または cmd では、Windows 版のコマンド(Get-Command、$env:VAR、2>$null、curl.exe)を使用してください。呼び出しと順序は同じです。

Phase 1: Datadog の委任プリンシパルを取得する

Datadog は、組織ごとに用意される委任サービスアカウントを通じて顧客のサービスアカウントを偽装します。そのメールアドレスを取得してください。まず GET を実行し、組織に委任アカウントがまだない場合に限り POST してください。既存のアカウントを再作成せずに再利用できます。

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- | 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/sts_delegate")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
if [ "$code" = "404" ]; then
  echo "no delegate exists yet (HTTP 404) - creating one"
  resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
    | curl -sS -w '\n%{http_code}' -X POST -H "Content-Type: application/json" -d '{}' \
        -H @- "https://api.${DD_SITE}/api/v2/integration/gcp/sts_delegate")
  code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
elif [ "$code" != "200" ]; then
  echo "GET sts_delegate returned HTTP $code - not creating anything. Response:"
  printf '%s\n' "$body"
  echo "403 means the app key lacks permission, 429 is rate limiting, 000 is a transport failure, 5xx is"
  echo "server-side. None of those mean 'no delegate exists', so a POST here could create one you did not"
  echo "intend. Resolve the error, then re-run. If the body says no delegate exists, POST explicitly."
  exit 1
fi
[ "$code" = "200" ] || { echo "sts_delegate failed with HTTP $code:"; printf '%s\n' "$body"; exit 1; }
email=$(printf '%s' "$body" | jq -r '.data.attributes.delegate_account_email // empty')
case "$email" in
  *@*.iam.gserviceaccount.com) echo "DATADOG_PRINCIPAL_ID=$email" ;;
  *) echo "did not get a delegate service-account email; response was:"; printf '%s\n' "$body"; exit 1 ;;
esac

表示されたメールアドレスを DATADOG_PRINCIPAL_ID として記録してください。以下の Terraform で必要になります。これは組織ごとに異なるため、ハードコードできません。

メールアドレスが空、または null の場合は、絶対に続行しないでください。 上記のガードがあるのは、エラーレスポンスに対して curl -s | jq -r を実行すると null が出力され、それがそのまま Terraform の member = "serviceAccount:null" になり、認証できないインテグレーションが作成されてしまうためです。

jq を利用できない場合は、email=$(... | jq -r ...) の行だけを除き、ブロックを記述どおりに実行してください。認証情報を渡すのは printf ... | curl -H @- のパイプラインなので、削除しないでください。$body から data.attributes.delegate_account_email を自分で読み取り、同じルールを適用してください。[email protected] 形式のアドレスであることを確認できない限り、続行しないでください。

フェーズ 2:対象範囲を決定する

監視対象にする GCP プロジェクト ID やフォルダー ID がすでに決まっているか、ユーザーに尋ねます。

決まっている場合は、以下を確認します。

  • Datadog サービスアカウントを配置する GCP プロジェクト(「ホストプロジェクト」)はどれですか?
  • 監視対象にするプロジェクト ID やフォルダー ID の一覧

決まっていない場合、または特定にサポートが必要な場合:

gcloud CLI が利用可能な場合は、GCP 環境を調べることを提案します。gcloud を使って組織、フォルダー、プロジェクトの一覧を取得し、ユーザーが監視対象を選べるようにすることを説明します。これはベストエフォートです。各コマンドを個別に実行し、成功した結果を使って作業を進めます。

組織:

gcloud organizations list --format="table(displayName, name)"

フォルダー(REST API を使って組織内のすべてのアクティブなフォルダーを検索します。アクセストークンの取得にも gcloud が必要です):

printf 'Authorization: Bearer %s\n' "$(gcloud auth print-access-token)" \
  | curl -sS -H @- -H "Content-Type: application/json" \
      -d '{"query": "lifecycleState=ACTIVE"}' \
      "https://cloudresourcemanager.googleapis.com/v2/folders:search"

応答に nextPageToken が含まれている場合は、すべてのフォルダーを取得するまで、リクエスト本文に "pageToken": "<token>" を追加してページネーションします。

ネストされたフォルダーは自分で展開します。 上記の検索では組織内のすべてのアクティブなフォルダーが返されるため、ユーザーが選んだフォルダーについて、子孫にあたるフォルダーをすべて列挙します。選択された各フォルダーについて、parent の階層をたどってそのフォルダーに行き着くすべてのフォルダーを集め、それらすべてのフォルダーに属するプロジェクトを一覧表示します。

# replace these with the chosen folder and every folder nested beneath it
set -- 123456789012 987654321098
for folder do
  gcloud projects list --filter="parent.id=${folder} AND lifecycleState=ACTIVE AND NOT projectId:sys*" \
    --format="value(projectId)"
done | sort -u

展開した一覧を Terraform の project_ids に追加するとともに、選択されたフォルダーは folder_ids にも残します。テンプレートでは、フォルダーレベルの IAM はすべての子孫プロジェクトに継承されますが、API の有効化は継承されず、google_projects データソースは直近の親のみを対象とするためです。folder_ids は IAM を適用します(後から作成されたプロジェクトも対象です)。展開した project_ids によって、既存の各プロジェクトで必要な API が実際に有効になります。展開を省略すると、統合の設定が完了したように見えても、サブフォルダー内のプロジェクトからは何も収集されません。

プロジェクト(アクティブなもののみ。システムプロジェクトは除外):

gcloud projects list --filter="lifecycleState=ACTIVE AND NOT projectId:sys*" --format="table(projectId, name, parent.id)"

個々のコマンドが失敗した場合(例:組織やフォルダーを一覧表示する権限がない場合)は、どのコマンドが失敗したか、その理由とともにユーザーに伝えます。ただし、正常に取得できた情報を使って続行します。たとえば、プロジェクトは一覧表示できてもフォルダーを一覧表示できない場合は、プロジェクト単位のセットアップを進めます。

それ以外の場合(gcloud がインストールされていない、または認証されていない場合)は、GCP コンソールから ID を取得するようユーザーに依頼します。

  • プロジェクト ID:console.cloud.google.com → プロジェクト選択メニュー(上部バー)→ 各プロジェクトの名前の横に ID が表示されます。
  • フォルダー ID(任意):console.cloud.google.com → IAM と管理 → リソースの管理 → 組織ツリーを展開します。フォルダー ID はリソースマネージャーに表示されます。
  • 該当するフォルダー内のすべてのプロジェクト(ネストされたサブフォルダー内のものを含む):リソースの管理でサブツリー全体を展開し、各プロジェクト ID を集めます。これは任意の作業ではありません。Terraform はプロジェクトごとに必要な API を有効にするため、一覧に含まれないプロジェクトにはフォルダーから IAM が継承されますが、API は有効にならず、何も収集されません。ユーザーがすべてのプロジェクトを列挙しない場合は、フォルダー単位のセットアップにはサブツリーを自動的に展開できる gcloud が必要であることを伝え、代わりにプロジェクト単位のセットアップを提案します。
  • ホストプロジェクト:Datadog サービスアカウントをどのプロジェクトに配置するか尋ねます。

取得できた結果を読みやすい形式で示し、ユーザーに次のいずれかを選んでもらいます。

  • 特定のプロジェクト:プロジェクト ID の一覧
  • フォルダー:フォルダー ID の一覧(Datadog がその中のすべてのアクティブなプロジェクトを検出します)
  • 両方:明示的に指定するプロジェクトとフォルダーの組み合わせ

その後、Datadog サービスアカウントをどのプロジェクトに配置するか尋ねます。

フェーズ 3:Terraform の生成と適用

既存の設定を確認する - まずローカルの Terraform、次に Datadog

何かを生成または適用する前に、次の順番で確認します。ローカルの状態を最初に確認してください。既存のインテグレーションを更新できるのか、変更してはいけないのかがそれで決まるためです。

find . -maxdepth 1 -type f \( -name '*.tf' -o -name 'terraform.tfstate' \) -print
# A project is "present" if it has configuration - .terraform/ may simply not exist yet on a fresh clone
# with a remote backend, and terraform.tfstate does not exist at all when state is remote.
if [ -n "$(find . -maxdepth 1 -type f \( -name '*.tf' -o -name '*.tf.json' \) -print -quit)" ]; then
  terraform init -input=false >/dev/null || { echo "terraform init failed - resolve that before concluding anything about existing state"; exit 1; }
  out=$(terraform state list 2>&1); rc=$?
  if [ "$rc" -ne 0 ]; then
    case $out in
      *'No state file'*|*'no state'*|*'Backend initialization required'*)
        echo "project is initialized but has no state yet - treat as a clean install" ;;
      *)
        printf '%s\n' "$out"
        echo "could not read state (backend or credentials problem) - do NOT treat this as 'nothing exists'"; exit 1 ;;
    esac
  elif [ -z "$out" ]; then
    echo "state is empty - treat as a clean install"
  else
    printf '%s\n' "$out" | grep -F 'datadog_integration_gcp_sts' || echo "state exists but holds no datadog_integration_gcp_sts resource"
  fi
else
  echo "no Terraform configuration here yet - clean install"
fi

緩い grep -i datadog ではなく、リソースアドレス datadog_integration_gcp_sts と完全に一致するものを照合してください。無関係な Datadog リソースや、部分的な適用で残ったクラウド IAM を照合すると、管理対象のインテグレーションとして扱われてしまいます。

次に、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- | 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 'not connected':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"

ここで、何かを実行する前に、2つの結果を照合します。

  • Datadog に存在せず、ローカルの状態にも存在しない - 新規インストールです。続行します。

  • Datadog に存在し、ローカルの状態にも存在する - これは重複ではなく、更新・修復のケースです。 以下の Terraform に進み、既存のリソースへの変更として扱い、変更内容をプランで確認します。

  • Datadog に存在するが、ローカルの状態には存在しない(Phase 2 で作成したホストプロジェクト用のサービスアカウントがすでに登録されている) - 停止します。適用すると、重複を作成するか、管理元と競合する可能性があります。そのことを明確に伝え、次の選択肢を提示します。既存のオブジェクトをこのプロジェクトにインポートする(terraform import datadog_integration_gcp_sts.datadog_integration "<integration-uuid>" - uuid はプロジェクト ID やサービスアカウントのメールアドレスではなく、GET /api/v2/integration/gcp/accounts から取得します)、すでに管理されている場所で管理する、または Datadog で削除する、のいずれかです。ユーザーが選択して確認した場合にのみ続行します。 インポートに関する注意点は、次の2つです。この順番で対応します。まず構成を生成します(以下の Terraform を、すでに存在する ID(同じロール、アプリ、サービスアカウント名)に合わせて調整します)。terraform import は既存のオブジェクトを構成済みのリソースアドレスに紐付けるため、構成がないと失敗します。また、Datadog の登録だけをインポートしても不十分です。クラウド側の ID(IAM ロール、アプリの登録、サービスアカウント)は引き続き状態の管理対象外なので、それらもインポートするか、データソースで参照する必要があります。そうしないと、次回の適用時に再作成が試みられ、競合します。

    # the uuid comes from the accounts listing, not the project id or service-account email
    terraform import datadog_integration_gcp_sts.datadog_integration "<integration-uuid>"
    
  • ローカルの状態には存在するが、Datadog には存在しない - 部分的なインストール、またはロールバックされたインストールです。登録がなくても、クラウド側のリソースは存在する可能性があります。最初からやり直さず、プランを実行して不足しているものを確認し、登録だけが再作成されることを想定してください。

既存の Terraform を確認する

新しい Terraform 構成を生成する前に、ユーザーが現在のディレクトリまたはその近くにすでに Terraform プロジェクトを持っているか確認します。

find . -maxdepth 1 -type f \( -name '*.tf' -o -name 'terraform.tfstate' \) -print

既存の .tf ファイルが見つかった場合:

  • 既存のプロバイダーとリソースを把握するため、ファイルを読みます。
  • datadog プロバイダーがすでにある場合は、その構成を再利用します。重複して作成しないでください。
  • google プロバイダーがすでにある場合は、それを再利用します。
  • 既存のプロジェクトには、必要な新しいリソース(サービスアカウント、IAM バインディング、datadog_integration_gcp_sts)のみを追加します。すでに存在するプロバイダー、変数、terraform ブロックを再生成しないでください。
  • ユーザーがモジュール化された構成を使用している場合は、Datadog リソース用に datadog-gcp-integration.tf のような新しいファイルを作成します。

既存の Terraform が見つからない場合は、単独で使用できる構成を生成します。

プロバイダー、API の有効化、サービスアカウント、Datadog のデリゲート用のトークン作成者バインディング、プロジェクトとフォルダーのロールバインディング、および datadog_integration_gcp_sts の登録を含む完全な HCL テンプレートは、プロジェクトのみ、およびフォルダーのみのバリエーションとともに references/terraform.md にあります。今すぐ読み込み、プレースホルダーを埋めて出力してください。

Terraform の適用

  1. テンプレート内のすべての <PLACEHOLDER> の値を、収集した実際の値に置き換えます。

    • Phase 2 の <USER_FOLDER_IDS> と <USER_PROJECT_IDS>
    • Phase 2 の <HOST_PROJECT_ID>
    • Phase 1 の <DATADOG_PRINCIPAL_ID>
    • Phase 0 の <DD_SITE>
  2. ユーザーがプロジェクトのみを選択した場合(フォルダーを選択していない場合)は、folder_ids ローカル値、google_projects.folder_projects データソース、google_folder_iam_member リソースを削除し、all_project_ids を local.project_ids のみに簡略化します。

  3. ユーザーがフォルダーのみを選択した場合(プロジェクトを明示的に選択していない場合)も、Phase 2 で取得した子孫プロジェクトの一覧を project_ids に設定します。[] に設定しないでください。folder_ids は IAM 権限を付与し(後から作成されるプロジェクトも対象になります)、API の有効化はプロジェクトごとに行われるため、project_ids が空だと、それらのフォルダーにある既存のすべてのプロジェクトで必要な API が有効になりません。

  4. terraform init を実行してプロバイダーをインストールします。

  5. プランを作成し、ファイルに保存します。Datadog プロバイダーは環境変数から DD_API_KEY / DD_APP_KEY を直接読み取るため、ルート変数も -var= 引数も不要です。秘密情報がプランファイル、ステート、コマンドラインに含まれることはありません。

    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- | 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)}"
    umask 077          # tighten permissions on the plan file anyway
    terraform plan -out=tfplan
    

    プランの出力をユーザーに表示し、明示的な確認を待ちます。

  6. ユーザーが確認した後に限り、保存したプランを適用します。ファイルを適用することで、確認の意味が保たれます。プランファイルを指定せずに terraform apply を実行すると、新しいプランが作成されます。また、-auto-approve を使うと誰にも確認されずに実行されるため、プラン作成後に変更された内容が未確認のまま適用されてしまいます。

    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- | 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   # the plan file goes away even if this is interrupted
    if terraform apply tfplan; then
      echo "apply complete"
    else
      echo "terraform apply FAILED - do NOT verify or report success"
      exit 1
    fi
    

    trap は、ユーザーが判断中に Ctrl-C を押した場合も含め、どの終了経路でもプランファイルを削除します。apply を if/else で囲むことも重要です。ブロックの最後にクリーンアップコマンドを置くと、apply が失敗しても終了コードが 0 になり、デプロイが行われていないのにエージェントが「検証」に進んでしまいます。(zsh では status が読み取り専用変数のため、意図的に status=$? ではなく if を使っています。)

    キーが Terraform の値になることはなく、プロバイダーが環境変数から読み取るため、プランファイルにキー情報が含まれることはありません。そのため、Terraform のバージョンを問わず、ここでは -out を安全に使用できます。また、既存のプロジェクトでも変数を変更する必要はありません。

  7. terraform apply が成功したら、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- | 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 'not connected':"; printf '%s\n' "$body"; exit 1; }
    printf '%s\n' "$body"
    

    応答に、今作成したサービスアカウントのメールアドレスが含まれていることを確認します。含まれていない場合は、ユーザーがデバッグできるよう、応答を提示します。

インテグレーションを最大限に活用する

terraform apply が正常に完了したら、ユーザーを祝福し、通常 5〜10 分以内にメトリクスが届くことを伝えます。その後、初期メトリクスを確認し、ウィジェットを表示します。

メトリクスの確認

数秒待ってから、メトリクス API にクエリを 1 回だけ送信します。<MONITORED_PROJECT_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- | 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)}"
sleep 10
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" \
  | curl -sS -w '\n%{http_code}' -G -H @- "https://api.${DD_SITE}/api/v1/query" \
  --data-urlencode "from=$(($(date +%s) - 900))" \
  --data-urlencode "to=$(date +%s)" \
  --data-urlencode "query=avg:gcp.gce.instance.cpu.utilization{project_id:<MONITORED_PROJECT_ID>} by {instance_name}")
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "metric query failed with HTTP $code - that is NOT 'metrics still propagating':"; printf '%s\n' "$body"; exit 1; }
printf '%s\n' "$body"
ウィジェットのレンダリング

series 配列が空でない場合は、実データから ASCII チャートを描画します。

  • pointlist の値を使用して折れ線をプロットし、Y 軸を実際の最小値/最大値に合わせてスケーリングします。
  • ボックス描画文字(╭、╰、─、│、┤)を使用して線を描画します。
  • 各 series の scope からインスタンス名を取得し、下部に一覧表示します。
  • 複数の series が返された場合は、平均値が上位 3 件の series を表示します。

series 配列が空の場合は、代わりに次の静的プレビューを表示し、メトリクスはまだ反映中であることをユーザーに知らせます。

┌─────────────────────────────────────────────────────────┐
│  gcp.gce.instance.cpu.utilization   ▂▃▅▆▇▆▅▃▂▁▂▃▅  │
│  100% ┤                                          ╭──╮   │
│   75% ┤                    ╭───╮              ╭──╯  │   │
│   50% ┤              ╭────╯   ╰──╮     ╭────╯     │   │
│   25% ┤    ╭────────╯            ╰────╯           │   │
│    0% ┤────╯                                       │   │
│       └────────────────────────────────────────────┘   │
│                                                         │
│  メトリクスはまもなく表示されます。数分後にもう一度ご確認ください │
└─────────────────────────────────────────────────────────┘
Metrics Explorer: <APP_BASE>/metric/explorer?exp_metric=gcp.gce.instance.cpu.utilization

インテグレーションの設定が完了しており、データはまもなく表示されることをユーザーに伝えます。すべてのリンクでは DD_SITE を使用します。リンクは <APP_BASE>/... の形式で作成してください。

  • GCP Integration タイル:<APP_BASE>/integrations/google-cloud-platform — 事前構築済みダッシュボードにアクセスし、インテグレーションが有効であることを確認します。
  • Metrics Explorer:<APP_BASE>/metric/explorer?exp_metric=gcp.gce.instance.cpu.utilization — データが流れていることを確認します。
  • GCP の各サブインテグレーション(Cloud SQL、Cloud Run、Pub/Sub、GKE など)には専用のダッシュボードがあり、該当サービスのメトリクスが検出されると自動的に有効になります。

推奨モニター — 一般的な GCP の健全性シグナルを監視するモニターを <APP_BASE>/monitors/create で作成するよう提案します。

  • Compute Engine の CPU 使用率がしきい値を超えた場合
  • Cloud SQL の接続数が上限に近づいた場合
  • GKE ノードが NotReady 状態になった場合
  • Pub/Sub のデッドレターキューが増加した場合

リソース収集が有効な場合:

  • Resource Catalog:<APP_BASE>/infrastructure/catalog — Compute インスタンス、Cloud SQL データベース、GKE クラスターなどを参照します。
  • Infrastructure Map:<APP_BASE>/infrastructure/map — GCP インフラストラクチャを可視化します。

Datadog のその他の製品を確認する:

  • Log Management:<APP_BASE>/logs — GCP ログをストリーミングして、一元的な検索とアラートに利用します。セットアップ方法:https://docs.datadoghq.com/integrations/google_cloud_platform/#log-collection
  • APM & Traces:<APP_BASE>/apm/getting-started — Cloud Run、GKE、Compute Engine 上のアプリケーション向けの分散トレーシングです。
  • Notebooks:<APP_BASE>/notebook — メトリクス、ログ、イベントを組み合わせた調査を共有できます。

重要な注意事項

  • Terraform を生成する前に、プロジェクト ID、フォルダー ID、ホストプロジェクトを必ずユーザーに確認してください。
  • ユーザーには、対象範囲内のすべてのプロジェクトとフォルダーで、サービスアカウントの作成、サービスの有効化、IAM ポリシーの設定を行う権限が必要です。具体的には、roles/resourcemanager.projectIamAdmin/roles/resourcemanager.folderIamAdmin、ホストプロジェクトの roles/iam.serviceAccountAdmin、および設定で API を有効にするすべてのプロジェクト(ホストプロジェクトを含みます。ホストプロジェクトでは iam.googleapis.com と iamcredentials.googleapis.com が有効になります)の roles/serviceusage.serviceUsageAdmin が必要です。サービスアカウント自体に付与される roles/serviceusage.serviceUsageConsumer では、API を有効化できません。
  • Datadog の委任先プリンシパル ID は組織ごとに異なるため、API から取得する必要があります。ハードコードすることはできません。
  • Datadog API キーとアプリキーを値として Terraform に渡すことはありません。datadog プロバイダーは環境変数から DD_API_KEY と DD_APP_KEY を読み取るため、ルート変数も -var= 引数も不要で、Terraform のステートや保存済みプランに記録されることもありません。キー変数を宣言したり、コミット対象の .tfvars ファイルやその他の永続ファイルにキーを書き込んだりしないでください。
  • 事前にプランをユーザーに提示せずに、terraform apply を実行してはいけません。

コメント