dd-azure-log-forwarding について
Automated Azure Log Forwarding を使って Azure リソースのログを Datadog に転送するスキルです。Terraform は生成せず、Azure CLI から公式インストーラーを実行し、連携、権限、サブスクリプション範囲を確認します。
主な機能
- 01Log Forwarding Orchestrator の利用
- 02Azure CLI で公式インストーラーを実行
- 03Datadog Azure 連携の確認
- 04サブスクリプション範囲と権限の確認
活用シーン
- 01Datadog に接続済みの Azure テナントで転送を設定
- 02制御プレーンと監視対象の権限を確認
- 03ログ転送対象のサブスクリプションを選定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ datadog-labs/ agent-skills --skill dd-azure-log-forwardingインストール後、Claude Code で/dd-azure-log-forwardingを入力して読み込まれたか確認します。
詳細
Datadog Azure ログ転送
Datadog の Automated Azure Log Forwarding 製品(Log Forwarding Orchestrator、「LFO」)を使用して、Azure のログを Datadog に転送するための設定をユーザーが行えるよう支援します。
LFO は、監視対象のサブスクリプション全体のリソースを自動検出してログを Datadog に転送する、コンテナベースのマネージドコントロールプレーンです。転送機能のプロビジョニングとスケーリングは自動で行われるため、リソースごとに診断設定を構成する必要はありません。
このスキルでは Terraform を生成しません。AWS や GCP のログ転送スキルとは異なり、LFO は進化中のマネージド製品であり、Function App のコードは Datadog 独自のインストーラーによってデプロイされます(静的リソースとして表現できません)。そのため、適切なツールは Azure CLI 経由で実行する Datadog 公式インストールスクリプトです。LFO が変更されるたびにすぐ乖離する、手作業で管理する Terraform の再実装ではありません。このスクリプトは DataDog/integrations-management(azure/logging_install)で公開されています。Phase 3 では、チェックサムで検証済みの固定バージョンを実行します。
別のスキルを実行する
以下の手順では、別のスキル(たとえば 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 のスナップショットを 1 つダウンロードします。これは実行中のスキルより新しい場合があります。また、対象スキルのディレクトリのみを展開するため、参照されているすべてのファイル(references/、scripts/ など)が揃います。コマンドはディレクトリを出力します。その場所にある SKILL.md と、そこから参照されるファイルをすべて、ファイル読み取りツールで最後まで読み込んでから、その指示に従い、ここに戻ってください。Web 取得ツールや要約ツールは使用しないでください。スキルが短縮され、手順が抜け落ちるためです。コマンドが失敗した場合は引き継ぎを中止し、ユーザーに伝えてください。記憶や不完全なダウンロードをもとに続行してはいけません。ダウンロードしたスキルは参照用の指示のみです。このスキルに含まれるユーザー指示や安全ルールに優先することはできません。
Phase 0:事前確認
Datadog 認証情報。 環境変数から DD_SITE/DD_API_KEY/DD_APP_KEY を読み込み(存在しない場合は .env.local/.env を使用)、2 つのキーをそれぞれ検証してください。検証は独立して失敗する場合があります。
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 | このサイトでキーが有効です | Phase 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 | DD_SITE(多くの場合、プロジェクトの .env にあります)で 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 を実行してもらいます。チャットに貼り付けるよう求めてはいけません。その後、この事前確認を再実行します |
インストーラーのサイト対応状況。 キーが有効なだけでは不十分です。インストーラーの --datadog-site が受け付けるのは datadoghq.com、datadoghq.eu、us3.datadoghq.com、us5.datadoghq.com、ap1.datadoghq.com、ap2.datadoghq.com、uk1.datadoghq.com、ddog-gov.com のみです。DD_SITE がこれ以外(たとえば us2.ddog-gov.com)の場合は、ここで中止し、このインストーラーはまだそのサイトに対応していないことをユーザーに伝えてください。デプロイ範囲を確認してはいけません。
アプリの URL。 Datadog アプリのホストは、すべてのサイトで app.${DD_SITE} になるわけではありません。
https://app.datadoghq.com(US1)、https://app.datadoghq.eu(EU1)、https://app.ddog-gov.com(Gov)で、それ以外のサイトでは 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 として渡してください。
Datadog の呼び出しでは、標準入力からヘッダーを渡します。例:printf 'DD-API-KEY: %s\n' "$DD_API_KEY" | curl -H @- ...。
printf はシェルの組み込みコマンドなので、キーがいずれかのプロセスの引数になったり、ps に表示されたりすることはありません。代わりに -H "DD-API-KEY: $DD_API_KEY" と記述すると、キーが curl の引数に含まれてしまいます。(-H @- には curl 7.55 以降が必要です。ヘッダー行だけが読み込まれるため、-d と --data-urlencode は通常どおり使用できます。)
ローダーと組み合わせることで、両方のキーがトランスクリプトとシェル履歴に残りません。
ツール。 az CLI、python3、bash がすべて必要です。
command -v bash >/dev/null 2>&1 && echo "bash: available" || echo "MISSING bash - the Phase 3 block needs it for pipefail"
command -v az >/dev/null 2>&1 && echo "az: available" || echo "MISSING az - https://learn.microsoft.com/cli/azure/install-azure-cli"
command -v python3 >/dev/null 2>&1 && echo "python3: available" || echo "MISSING python3"
ここにあるスニペットは bash で実行してください。 ほとんどは POSIX シェルですが、Phase 3 のインストーラーブロックでは set -o pipefail を使用します。これは dash などの /bin/sh 実装では拒否されます。また、実行前に bash があることも確認します。Windows では、WSL または Git Bash の bash を使用してください。
フェーズ 1:前提条件
-
Azure CLI で認証済みであること。
az account showで確認します。失敗する場合は、ユーザーにaz loginを実行してもらいます。 -
Python 3 が利用できること(インストーラーは Python の zipapp です)。
command -v python3インストールされていない場合は、Python 3 のインストールを依頼します。
-
権限。 インストーラーは、コントロールプレーンサブスクリプションにリソースグループ、カスタムロール、ロール割り当てを作成し、すべての監視対象サブスクリプションにリソースグループとロール割り当てを作成します。コントロールプレーンサブスクリプションでは、Owner、または Contributor と User Access Administrator の組み合わせが必要です。インストーラーはカスタムロールのために
az role definition createを実行し、これにはMicrosoft.Authorization/roleDefinitions/writeが必要です。Role Based Access Control Administrator ではこの権限は付与されません(ロール割り当てのみが対象です)。各監視対象サブスクリプションでは、Owner、または Contributor と Role Based Access Control Administrator もしくは User Access Administrator の組み合わせで十分です。インストーラーの実行前に確認してください。権限が不足していると、コントロールプレーンのリソースがすでにデプロイされた後でインストールが失敗する場合があります。スクリプトの実行中に認証エラーが発生した場合は、Azure 管理者に問い合わせるよう案内してください。環境に問題があると決めつけないでください。 -
Datadog Azure インテグレーションがすでに存在すること。 このスキルがインストールするのはログ転送のみです。インテグレーション自体を作成するのは
dd-azure-integrationだけです。インストーラーの実行前に、テナントが Datadog に登録されていることを確認します。テナント ID を取得します。az account show --query "tenantId" -o tsv次に、Datadog にすでに登録されている Azure テナントを問い合わせます。
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/v1/integration/azure") 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"- エントリの
tenant_nameがテナント ID と一致する場合 - インテグレーションは存在します。テナント ID をTENANT_IDとして記録し、フェーズ 2 に進みます。この確認の対象はこのテナントのみです。フェーズ 2 で選択するサブスクリプションは、すべてこのテナントに属している必要があります。別のテナントからログを転送するには、そのテナントでこの前提条件の確認(az login --tenant <id>)を行い、そのテナントで別途インストールしてください。 - 一致するエントリがない場合(またはリストが空の場合) - 作業を中止します。Azure インテグレーションがまだ設定されていないことをユーザーに伝え、dd-azure-integration スキルを実行してから、ここに戻りフェーズ 0 からやり直します。このスキルでインテグレーションを作成しないでください。
- 照会に失敗した場合(
200以外) - 応答内容を提示します。「未接続」とみなさないでください。
- エントリの
フェーズ 2:対象範囲の決定
以下を確認します。
- コントロールプレーンのリージョン - コントロールプレーンをホストする Azure リージョン(例:
eastus、westus2)。 - コントロールプレーンのサブスクリプション - コントロールプレーンをデプロイするサブスクリプション ID。既定では、
az account show --query id -o tsvで取得した現在のサブスクリプションを使用します。TENANT_IDに属している必要があります。 - コントロールプレーンのリソースグループ - コントロールプレーンのリソースグループ名。既定値は
datadog-log-forwardingです。これをCONTROL_PLANE_RGとして記録します。 - 監視対象のサブスクリプション - ログの転送元となるサブスクリプション ID。既定では、フェーズ 1 で検証したテナント内でユーザーがアクセスできるすべてのサブスクリプションから転送します。リストを表示し、ユーザーに確認または絞り込みを依頼します(フェーズ 1 の
TENANT_IDに置き換えます)。
選択した ID をカンマ区切りのリストとして渡します。az account list --query "[?tenantId=='<TENANT_ID>'].{name:name, id:id}" -o table
次に、コントロールプレーンサブスクリプションとすべての監視対象サブスクリプションがそのテナントに属していることを確認し、フェーズ 1 のインテグレーション確認を回避するサブスクリプションがないようにします。
TENANT_ID='<TENANT_ID>'
for sub in '<CONTROL_PLANE_SUBSCRIPTION_ID>' '<SUB_ID_1>' '<SUB_ID_2>'; do
t=$(az account show --subscription "$sub" --query tenantId -o tsv) || { echo "cannot read subscription $sub - stop"; exit 1; }
[ "$t" = "$TENANT_ID" ] && echo "ok: $sub" || { echo "subscription $sub is in tenant $t, not $TENANT_ID - its integration was not checked; stop"; exit 1; }
done
いずれかのサブスクリプションの確認に失敗した場合は、続行する前にこのインストールから除外するか、フェーズ 1 の説明に従って別のテナントとして処理します。
任意(ユーザーから依頼があった場合のみ):
- リソースタグフィルター -
datadog:true,env:prodのように、タグに一致するリソースからのみ転送します。 - PII スクラバーのルール - 転送されるログに適用する、YAML 形式のマスキングルール。
タグや PII についてユーザーに希望がない場合、新規インストールでは何も使用しません(すべてのログがフィルターなしで転送されます)。既存のインストールでは現在の値が維持されます。現在の値は次のステップで読み取ります。
既存のインストールを確認する
既存のインストールに対してインストーラーを再実行すると、インストールが更新されます。この更新には、次の2つの破壊的な変更があります。設定はマージされず、置き換えられます。--resource-tag-filters または
--pii-scrubber-rules を省略すると、空の値が送信され、すでに設定されているタグフィルターと PII スクラバーのルールがクリアされます。また、現在インストールが監視しているサブスクリプションのうち、新しいリストに含まれていないものはすべてロールの割り当てが削除され、そのサブスクリプション内にあるコントロールプレーンのリソースグループと同じ名前のリソースグループがインストーラーによって削除されます。そのため、続行を確定する前に現在の状態を確認してください。このブロックは Azure に対して読み取り専用です。現在のタグフィルターと PII ルールを2つのローカルファイルに書き込みます。Phase 3 ではそのファイルをインストーラーに渡します。また、API キーが出力されることはありません。既存のインストールがログをどこに送信するかも確認します。インストーラーの更新処理では保存済みの Datadog サイトと API キーが保持され、--datadog-site / --datadog-api-key は無視されるため、新たに追加したサブスクリプションのログも以前の送信先に転送されます。Phase 0 で確認したサイト、コントロールプレーンのサブスクリプション、および監視対象のサブスクリプションをカンマ区切りで指定してください。
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.
: "${DD_API_KEY:?not set - run dd-account-setup (commercial sites) or supply it directly (government sites)}"
export DD_API_KEY
python3 - '<CONTROL_PLANE_SUBSCRIPTION_ID>' '<SUB_ID_1,SUB_ID_2,...>' <<'EOF'
import json, os, subprocess, sys
def az(*args):
try:
out = subprocess.run(["az", *args, "-o", "json"], check=True, capture_output=True, text=True).stdout
except subprocess.CalledProcessError as err:
sys.exit(f"az {args[0]} {args[1]} failed: {err.stderr.strip()}")
return json.loads(out or "null") or []
control_sub, new_subs = sys.argv[1], [s.strip() for s in sys.argv[2].split(",") if s.strip()]
found = []
for sub in dict.fromkeys([control_sub, *new_subs]):
for rtype in ("Microsoft.App/jobs", "Microsoft.Web/sites"):
for res in az("resource", "list", "--subscription", sub, "--resource-type", rtype,
"--query", "[?starts_with(name, 'resources-task-')].{name:name, rg:resourceGroup, location:location}"):
found.append((sub, res["rg"], res["location"], res["name"].rsplit("-", 1)[-1], rtype))
def env(sub, rg, name, rtype):
if rtype == "Microsoft.App/jobs":
items = az("containerapp", "job", "show", "--subscription", sub, "-g", rg, "-n", name,
"--query", "properties.template.containers[].env[]")
else:
items = az("functionapp", "config", "appsettings", "list", "--subscription", sub, "-g", rg, "-n", name)
return {item["name"]: item.get("value") or "" for item in items}
if not found:
tags, pii = "", ""
print("No existing installation: this is a fresh install.")
elif len(found) > 1:
sys.exit("MULTIPLE existing installations found - the installer refuses to run; remove the extras first.")
else:
sub, rg, location, cp_id, rtype = found[0]
resources_env = env(sub, rg, "resources-task-" + cp_id, rtype)
scaling_env = env(sub, rg, "scaling-task-" + cp_id, rtype)
raw = resources_env.get("MONITORED_SUBSCRIPTIONS", "")
try:
current = json.loads(raw) if raw else []
except json.JSONDecodeError:
current = [s.strip() for s in raw.split(",") if s.strip()]
tags, pii = resources_env.get("RESOURCE_TAG_FILTERS", ""), scaling_env.get("PII_SCRUBBER_RULES", "")
print("EXISTING installation - this run will UPDATE it.")
print(f"control plane: subscription {sub}, resource group {rg}, region {location}")
print("currently monitored:", ", ".join(current) or "none")
case_only = [s for s in new_subs if s not in current and s.lower() in (c.lower() for c in current)]
if case_only:
sys.exit("STOP: these IDs differ from the monitored ones only by letter case: " + ", ".join(case_only)
+ ". The installer compares IDs case-sensitively and would treat each as both added and removed "
"(revoking its permissions and deleting its forwarder resource group). Use the exact spelling "
"shown under 'currently monitored'.")
existing_site = resources_env.get("DD_SITE") or "datadoghq.com"
existing_key = resources_env.get("DD_API_KEY", "")
if existing_key.startswith("@Microsoft.KeyVault"):
existing_key = ""
print("existing Datadog site:", existing_site)
if existing_site != os.environ["DD_SITE"]:
sys.exit(f"STOP: the existing installation forwards to {existing_site}, not {os.environ['DD_SITE']}. "
"The installer's update does not change the destination; moving it is a separate migration.")
print("existing API key:", "not readable" if not existing_key
else "matches DD_API_KEY" if existing_key == os.environ["DD_API_KEY"] else "DIFFERS from DD_API_KEY")
print("ADDED by this run:", ", ".join(s for s in new_subs if s not in current) or "none")
removed = [s for s in current if s not in new_subs]
print(f"REMOVED by this run (permissions revoked, resource group '{rg}' deleted there):",
", ".join(removed) or "none")
if sub.lower() in (s.lower() for s in removed):
sys.exit(f"STOP: the removal set includes the control-plane subscription {sub}. The installer "
f"would delete resource group '{rg}' there, which is the control plane itself.")
print("current resource tag filters:", tags or "none")
print("current PII scrubber rules:", "\n" + pii if pii else "none")
with open("lfo-resource-tag-filters.txt", "w") as f:
f.write(tags)
with open("lfo-pii-scrubber-rules.yaml", "w") as f:
f.write(pii)
EOF
- 新規インストール — 続行します。上記でユーザーがフィルターを指定していない限り、両方のファイルは空です。指定している場合は、合意したタグフィルターを
lfo-resource-tag-filters.txtに、PII YAML をlfo-pii-scrubber-rules.yamlに書き込みます。 existing API key: DIFFERS from DD_API_KEY— 停止します。更新では保存済みのキーが保持されるため、新しいサブスクリプションのログはそのキーを使って転送され、別の Datadog 組織に送信される可能性があります。ユーザーに伝えてください。送信先の変更は別の移行作業(アンインストールして再インストール)であり、インストーラーの更新ではできません。existing API key: not readable(Container App Job のインストールでは、キーはシークレットへの参照として保存されています) — Azure から送信先の組織を確認できません。現在監視対象のサブスクリプションについて、今すぐ Phase 4 のログ検索を実行してください。この組織でforwarder:lfoのログが届いていれば、送信先を確認できます。ログが届かない場合は停止し、更新を承認する前に、このインストールがどの組織に転送しているか Datadog で確認するようユーザーに依頼してください。送信先を確認できないまま続行しないでください。STOP: these IDs differ ... only by letter case—currently monitoredの下に表示された正確な表記を使って監視対象のリストを書き換え、この確認を再実行してください。- 既存のインストール(サイトが一致し、キーが一致するか送信先が確認済み) — インストーラーがインプレースで更新するのは、コントロールプレーンのサブスクリプション、リソースグループ、リージョンが表示されたものと一致する場合のみです。そのため、Phase 3 では表示された値を使用してください。2つのファイルには現在のタグフィルターと PII ルールが保存されています。ユーザーから明示的に変更を求められない限り、そのままにしてください。変更を求められた場合は、ファイルを編集してください。「デフォルトを使う」ためにファイルを空にしないでください。ユーザーが既存のフィルタリングと PII のマスキングを失うことになります。
REMOVEDの下に何か表示されている場合は、ユーザーがそのサブスクリプションの削除を希望していることを確認してください。 STOP: the removal set includes the control-plane subscription— 停止します。インストーラーは、削除対象の各サブスクリプションにあるコントロールプレーンのリソースグループと同じ名前のリソースグループを削除します。コントロールプレーンのサブスクリプションでは、そのリソースグループがコントロールプレーンそのものです。したがって、これを削除すると、残りすべてのサブスクリプションの転送が停止します。ユーザーの承認があっても、インストーラーの更新で削除することはできません。監視対象のリストに残してください。そのサブスクリプションのログ収集を停止するには、リソースタグフィルターを使うか、インストール全体をアンインストールしてください。MULTIPLEまたはazの失敗 — 停止して、メッセージをユーザーに伝えてください。
フェーズ 3:インストーラーを実行する
デプロイ前に確認してください。 インストーラーは課金対象のインフラストラクチャを作成し、サブスクリプション全体に権限を付与するため、変更内容をユーザーに正確に示し、明示的な「はい」を待ってから実行してください。
- コントロールプレーン:リージョン、サブスクリプション、リソースグループ(
CONTROL_PLANE_RG)。タスク用の Function Apps と、スケジュールされた Container App デプロイヤーが配置されます。 - 監視対象のサブスクリプション:
--monitored-subscriptionsに渡すすべての ID。 - 権限:コントロールプレーン用のカスタムロールとロールの割り当て。コントロールプレーンのサブスクリプションおよび監視対象のすべてのサブスクリプションに加え、それらのサブスクリプション内に作成されるフォワーダーのリソースグループにも適用されます。
- フィルター:2 つのファイルにあるリソースタグのフィルターと PII スクラバーのルール、または「なし - すべてのログを転送」。更新時は、変更がないか、どのような変更があるかを伝えてください。
- 更新時:追加されるサブスクリプションと、削除されるすべてのサブスクリプション。削除されたサブスクリプションではロールの割り当てが取り消され、コントロールプレーンと同じ名前のリソースグループが削除されます。
- コスト:コントロールプレーンと、そこからプロビジョニングされるフォワーダーは継続的に稼働し、Azure のコスト(コンピューティング、ストレージ)が発生します。
ユーザーがこの概要を承認するまで、以下のブロックを実行しないでください。
スクリプトをダウンロードし、収集した値を使って実行してください。キーをそのまま貼り付けず、$DD_API_KEY を直接参照してください。そうすることで、キーがシェルの履歴に残りません。インストーラーには、キーを指定する環境変数やファイルのオプションはありません。--datadog-api-key は必須の引数であり、インストーラー自体がキーを実行する az コマンドに渡します。そのため、インストーラーの実行中は、このマシンのほかのユーザーもローカルのプロセス一覧(ps)からキーを確認できます。信頼できるマシンで実行し、実行前にこの情報をユーザーに伝えてください。また、インストーラーはエラーメッセージに az コマンドを出力することがあり、そこには Datadog キーや、az storage container create --account-key に渡すストレージアカウントキーが含まれる場合があります。そこで、以下のブロックではインストーラーの出力をすべてフィルターに通し、Datadog キー、--account-key/--sas-token/--connection-string の値、および AccountKey=、SharedAccessSignature=、sig= の値がトランスクリプトに出力される前にマスクします。終了コードもインストーラーのステータスを引き継ぎます。pipefail を使うため、bash が必要です。
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)}"
case $DD_SITE in
datadoghq.com|datadoghq.eu|us3.datadoghq.com|us5.datadoghq.com|ap1.datadoghq.com|ap2.datadoghq.com|uk1.datadoghq.com|ddog-gov.com) ;;
*) echo "the installer does not support DD_SITE=$DD_SITE - stop"; exit 1 ;;
esac
[ -f lfo-resource-tag-filters.txt ] && [ -f lfo-pii-scrubber-rules.yaml ] \
|| { echo "run the existing-installation check in Phase 2 first"; exit 1; }
# Pinned to release azure-logging_install-v0.1.19 (commit bb854e5) and its SHA-256, so a later push to
# main cannot change what runs with the API key. To upgrade, update both values from a newer release.
INSTALLER_COMMIT=bb854e540eeae6b1f90fb9aef4273e72f37053ec
INSTALLER_SHA256=e0bbe311123caa879be24a7bfe6e76c90984324c8af50e526d91449dc4ad09b5
installer_dir=$(mktemp -d)
curl -fsS --proto '=https' -o "$installer_dir/azure_logging_install.pyz" \
"https://raw.githubusercontent.com/DataDog/integrations-management/${INSTALLER_COMMIT}/azure/logging_install/dist/azure_logging_install.pyz" \
|| { echo "installer download FAILED - do not run anything"; exit 1; }
python3 -c 'import hashlib, sys; sys.exit(hashlib.sha256(open(sys.argv[1], "rb").read()).hexdigest() != sys.argv[2])' \
"$installer_dir/azure_logging_install.pyz" "$INSTALLER_SHA256" \
|| { echo "installer checksum MISMATCH - do not run it"; exit 1; }
[ -n "${BASH_VERSION:-}" ] || { echo "run this block with bash"; exit 1; }
set -o pipefail
python3 "$installer_dir/azure_logging_install.pyz" \
--control-plane-region "<CONTROL_PLANE_REGION>" \
--control-plane-subscription "<CONTROL_PLANE_SUBSCRIPTION_ID>" \
--control-plane-resource-group "<CONTROL_PLANE_RG>" \
--monitored-subscriptions "<SUB_ID_1,SUB_ID_2,...>" \
--resource-tag-filters "$(cat lfo-resource-tag-filters.txt)" \
--pii-scrubber-rules "$(cat lfo-pii-scrubber-rules.yaml)" \
--datadog-api-key "$DD_API_KEY" \
--datadog-site "$DD_SITE" 2>&1 \
| DD_API_KEY="$DD_API_KEY" python3 -c 'import os, re, sys
key = os.environ["DD_API_KEY"]
flags = re.compile(r"(--(?:account-key|sas-token|connection-string)[\x27\"]?[=, ]+)(\x27[^\x27]*\x27|\"[^\"]*\"|\S+)")
pairs = re.compile(r"((?:AccountKey|SharedAccessSignature|sig)=)[^;&\s\x27\"]+", re.I)
for line in sys.stdin:
line = pairs.sub(r"\1***REDACTED***", flags.sub(r"\1***REDACTED***", line.replace(key, "***REDACTED***")))
sys.stdout.write(line); sys.stdout.flush()' \
|| { echo "installer FAILED - surface the (redacted) error above; do not verify or report success"; exit 1; }
タグのフィルターと PII のルールには、常にフェーズ 2 で作成した 2 つのファイルが使われます。そのため、更新時にはユーザーがファイルを変更していない限り、現在の値が維持されます。
スクリプトは、選択したサイトに対して API キーを検証し、コントロールプレーン(タスク用の Function Apps と、スケジュールされた Container App デプロイヤー)をデプロイし、監視対象のサブスクリプション全体に必要な権限を付与して、初回の検出を実行します。処理には数分かかります。完了するまで待ち、出力されたエラーは(機密情報がマスクされた状態で)ユーザーに提示してください。むやみに再試行しないでください。同じコントロールプレーンに対してスクリプトを再実行すると、重複して作成されるのではなく、既存のインストールが更新されます。
フェーズ 4:検証
コントロールプレーンはスケジュールに従ってリソースを検出し、フォワーダーを起動するため、最初のログが表示されるまでに 10~15 分かかることがあります。数分待ってから、LFO フォワーダーが送信したログをサブスクリプションごとに 1 つずつ確認します。各 LFO フォワーダーはログに forwarder:lfo と subscription_id:<id> のタグを付けるため、各検索でほかの Azure ログソースとほかのサブスクリプションを除外できます。監視対象のすべてのサブスクリプションを一覧表示します。
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)}"
sleep 10
for sub in '<SUB_ID_1>' '<SUB_ID_2>'; do
query=$(python3 -c 'import json, sys; print(json.dumps({"filter": {"query": "forwarder:lfo subscription_id:" + sys.argv[1], "from": "now-15m", "to": "now"}, "page": {"limit": 1}}))' "$sub")
resp=$(printf 'DD-API-KEY: %s\nDD-APPLICATION-KEY: %s\n' "$DD_API_KEY" "$DD_APP_KEY" |
curl -H @- -sS -w '\n%{http_code}' -X POST "https://api.${DD_SITE}/api/v2/logs/events/search" \
-H "Content-Type: application/json" -d "$query") \
|| { echo "request failed (network or TLS) - this is not 'no logs yet'"; exit 1; }
code=$(printf '%s' "$resp" | tail -1); body=$(printf '%s' "$resp" | sed '$d')
[ "$code" = "200" ] || { echo "log search failed with HTTP $code - an API or auth error, not 'no logs yet':"; printf '%s\n' "$body"; exit 1; }
printf '%s' "$body" | python3 -c 'import json, sys; print(sys.argv[1] + ": " + ("logs received" if json.load(sys.stdin).get("data") else "no logs yet"))' "$sub"
done
サブスクリプションごとに結果を報告します。logs received と表示されたサブスクリプションでは転送中です。それ以外のサブスクリプションについては、まだ検証されていないとユーザーに伝えてください。フォワーダーは現在プロビジョニング中(デプロイヤーはスケジュールに従って実行されます)で、まもなくログが表示されるはずです。そのため、動作中だと報告するのではなく、後でこのブロックを再実行してください。リクエストの失敗や 200 以外の応答は、プロビジョニングの遅延ではなく、報告すべきエラーです。今回の実行前に LFO がこれらのサブスクリプションのログをすでに転送していた場合(インストーラーが更新を報告した場合)、ここに表示されるイベントは以前のインストールからのものである可能性があり、今回の実行で何かが変更されたことの証明にはなりません。
リンクを提示します(フェーズ 0 で解決した App URL を使用して、<APP_BASE>/... の形式で作成します)。
- Logs Explorer:
<APP_BASE>/logs- Azure ログを検索およびフィルタリングします。 - Log Pipelines:
<APP_BASE>/logs/pipelines- ログを解析してエンリッチします。 - Log Monitors:
<APP_BASE>/monitors/create- ログのパターン、件数、異常に対してアラートを設定します。
重要事項
- コントロールプレーン(Function Apps と Container App デプロイヤー)および、コントロールプレーンがプロビジョニングするフォワーダーは、ユーザーのサブスクリプション内で継続的に実行され、Azure のコスト(コンピューティング、ストレージ)が発生します。
- API キーはフェーズ 0 で読み込んだ
$DD_API_KEY環境変数から展開され、インストーラーの--datadog-api-key引数に渡されるため、シェルの履歴に残らず、ローカルファイルや Terraform の状態ファイルにも書き込まれません。インストーラーと、インストーラーが実行するazコマンドの実行中は、コマンドライン上に表示されます。インストーラーには環境変数やファイルを指定するオプションがありません。LFO は製品の一部として、Azure のサーバー側(アプリ設定/コンテナーシークレット)にこのキーを保存します。azコマンドが失敗した場合、キーがトランスクリプトに残らないようにインストーラーの出力はフィルタリングされます。 - フォワーダーは、監視対象のリソースグループごとにコントロールプレーンによって自動的に作成されます。診断設定を手動で構成する必要はありません。
- アンインストールするには、コントロールプレーンのリソースグループと、サブスクリプションごとのフォワーダーのリソースグループを削除します。削除の詳細は
DataDog/integrations-management(azure/logging_install)を参照してください。 - このスキルがインストールするのはログ転送のみです。メトリクス統合は設定しません(メトリクス統合は前提条件である
dd-azure-integrationです)。