AWS DevOps AgentでCloudWatchアラームをトリガーに自動インシデント調査を行えるそうですが、自分でやってみたことがなかったので検証します。
ついでにCloudWatchアラームでアラート発生してからDevOps Agentの調査が開始されるまでの時間も計測してみます。せっかくDevOps Agentを導入するなら障害発生時の初動スピードも速くあってほしいと思います。
検証の内容
今回は「CloudWatchアラーム→EventBridge→Lambda→DevOps Agent」という流れを試します。
「CloudWatchアラーム→Lambda→DevOps Agent」という流れでも良いのですが、将来的にHealthイベントやGuarddutyなどCloudWatchアラーム経由でないイベントを拾ってDevOps Agentで調査したいと考え、EventBridgeをはさむ構成にしました。
EventBridgeの有無に限らず、Webhookで実行する必要があるのでLambda関数は必要となります。直接EventBridgeでAPI呼び出しできたらいいですよね。
構成
次の構成で検証をします。
実行するとSNS Publish権限が不足しているエラーが出るように設定したLambda関数を実行して意図的にCloudWatchアラームの状態をアラート状態にします。
CloudWatchアラームのアラート状態遷移を検知するEventBridgeからLambda関数を起動し、そのLambda関数からDevOps Agentのインシデントレスポンス調査を開始します。
DevOps AgentのWebhookの設定
まず、DevOps Agentを起動するためのWebhookを設定します。すべてコンソールから作業をします。
エージェントスペース > ウェブフック > Webhook を追加

Webhook が作成されたら完了です。URL とシークレットはこの画面を離れると二度と表示されないので、必ず控えておきます。

curlで疎通確認
Webhookが準備できたので疎通確認をします。
AWSドキュメントに「コードの例」として記載されているものをそのまま使います。
「バージョン 1 (HMAC 認証) - cURL」というのをそのまま使ってみます。
以下を「curl.sh」などに保存して bash curl.sh で実行します。
WEBHOOK_URL と SECRET は先ほど発行した WebhookURL とシークレットを指定します。
PAYLOAD で指定した値が実際に送信され、DevOps Agentが起動します。「Test」と明示的にメッセージ送っているためすぐに調査完了しますが多少なりともDevOps Agentが動くので注意です。
#!/bin/bash
# Configuration
WEBHOOK_URL="https://event-ai.us-east-1.api.aws/webhook/generic/YOUR_WEBHOOK_ID"
SECRET="YOUR_WEBHOOK_SECRET"
# Create payload
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
INCIDENT_ID="test-alert-$(date +%s)"
PAYLOAD=$(cat <<EOF
{
"eventType": "incident",
"incidentId": "$INCIDENT_ID",
"action": "created",
"priority": "HIGH",
"title": "Test Alert",
"description": "Test alert description",
"service": "TestService",
"timestamp": "$TIMESTAMP"
}
EOF
)
# Generate HMAC signature
SIGNATURE=$(echo -n "${TIMESTAMP}:${PAYLOAD}" | openssl dgst -sha256 -hmac "$SECRET" -binary | base64)
# Send webhook
curl -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-H "x-amzn-event-timestamp: $TIMESTAMP" \
-H "x-amzn-event-signature: $SIGNATURE" \
-d "$PAYLOAD"
スクリプトを実行すると {"message": "Webhook received"} とレスポンスがあります。
% bash curl.sh
{"message": "Webhook received"}
DevOps Agent画面を見ると調査が始まっていました。
Agentの回答に次の内容が確認できたので、メッセージが正常に送信されていることが確認できました。
「これはテストアラートのようで、調査すべき具体的なインシデントの詳細はありません。私が確認した内容は以下のとおりです。Title: Test Alert, Description: Test alert description, Reference URL: (none)」

Lambda関数とCloudWatchアラームを作成
DevOps Agentの調査対象とするLambda関数とCloudWatchアラームを作成します。
次の設定とします。
| 項目 | 内容 |
|---|---|
| Lambda関数 | ・SNSトピックにメッセージを通知 ・意図的にIAMロールにSNS関連の権限をアタッチしないことでinvokeしてもエラーとなる設定 |
| CloudWatchアラーム | ・Lambda関数のエラー数を監視 ・エラー数が1以上の場合にアラートが発生 |
EventBridgeを作成
CloudWatchアラームの状態変更を検知するためのEventBridgeを作成します。
alarmName で指定したアラーム名のCloudWatchアラームが状態が ALARM に変更をした際のイベントを検知するような設定です。
{
"source": ["aws.cloudwatch"],
"detail-type": ["CloudWatch Alarm State Change"],
"detail": {
"alarmName": ["medaka-prod-lambda-errors"],
"state": {
"value": ["ALARM"]
}
}
}
ターゲットはLambda関数に設定します。ターゲットのLambda関数で受け取ったイベントをWebhookでDevOps Agentに送ることになります。

上記以外の条件で絞り込みがしたい方はドキュメントのイベント例を参考にしてみてください。
EventBridgeからのイベント形式を確認
イベントを受け取りWebhookでDevOps Agentに送るLambda関数を作成する前に、CloudWatchアラームから発行されるイベント形式を確認します。
EventBridge→SNSにイベントを送るよう設定して確認します。

Lambda が受け取るイベント
CloudWatchアラームの状態がアラート状態になったときのイベントが確認できました。
この内容をLambda関数でDevOps Agentに送る形にします。
{
"version": "0",
"id": "528a591b-e61b-c146-9875-d66b3c9b5ae4",
"detail-type": "CloudWatch Alarm State Change",
"source": "aws.cloudwatch",
"account": "<ACCOUNT_ID>",
"time": "2026-08-09T02:58:54Z",
"region": "us-east-1",
"resources": [
"arn:aws:cloudwatch:us-east-1:<ACCOUNT_ID>:alarm:medaka-prod-lambda-errors"
],
"detail": {
"alarmName": "medaka-prod-lambda-errors",
"state": {
"value": "ALARM",
"reason": "Threshold Crossed: 1 datapoint [1.0 (09/08/26 02:57:00)] was greater than the threshold (0.0).",
"reasonData": "{\"version\":\"1.0\",\"queryDate\":\"2026-08-09T02:58:54.315+0000\",\"startDate\":\"2026-08-09T02:57:00.000+0000\",\"statistic\":\"Sum\",\"period\":60,\"recentDatapoints\":[1.0],\"threshold\":0.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2026-08-09T02:57:00.000+0000\",\"sampleCount\":1.0,\"value\":1.0}]}",
"timestamp": "2026-08-09T02:58:54.317+0000"
},
"previousState": {
"value": "OK",
"reason": "Threshold Crossed: no datapoints were received for 1 period and 1 missing datapoint was treated as [NonBreaching].",
"reasonData": "{\"version\":\"1.0\",\"queryDate\":\"2026-08-08T07:05:54.317+0000\",\"statistic\":\"Sum\",\"period\":60,\"recentDatapoints\":[],\"threshold\":0.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2026-08-08T07:04:00.000+0000\"}]}",
"timestamp": "2026-08-08T07:05:54.320+0000"
},
"configuration": {
"metrics": [
{
"id": "28cfee6d-79f9-18b0-e22f-0bc3f00af2cf",
"metricStat": {
"metric": {
"namespace": "AWS/Lambda",
"name": "Errors",
"dimensions": {
"FunctionName": "medaka-prod-order-notifier"
}
},
"period": 60,
"stat": "Sum"
},
"returnData": true
}
],
"description": "Order notification errors detected"
}
}
}
Lambda関数を作成
DevOps Agentが受け取るスキーマ形式
次の形でDevOps AgentのWebhookへリクエストを送ります。
{
eventType: 'incident';
incidentId: string;
action: 'created' | 'updated' | 'closed' | 'resolved';
priority: "CRITICAL" | "HIGH" | "MEDIUM" | "LOW" | "MINIMAL";
title: string;
description?: string;
timestamp?: string;
service?: string;
// The original event generated by service is attached here.
data?: object;
}
Lambda関数作成・実行
EventBridgeから受け取ったデータをDevOps Agentに送るLambda関数を作成します。
WebhookのURLとシークレットはSecrets Managerに置きます。値は次の形です。
{"url": "https://event-ai.us-east-1.api.aws/webhook/generic/YOUR_WEBHOOK_ID", "secret": "YOUR_WEBHOOK_SECRET"}
Lambdaの環境変数は WEBHOOK_SECRET_ID にシークレット名、SERVICE_NAME にサービス名を指定します。INCIDENT_PRIORITY は任意で、未指定ならHIGHです。実行ロールには secretsmanager:GetSecretValue を付けます。
クリックして詳細を表示
import base64
import hashlib
import hmac
import json
import os
import urllib.request
from datetime import datetime, timezone
import boto3
SECRET_ID = os.environ["WEBHOOK_SECRET_ID"]
SERVICE_NAME = os.environ["SERVICE_NAME"]
INCIDENT_PRIORITY = os.environ.get("INCIDENT_PRIORITY", "HIGH")
secrets = boto3.client("secretsmanager")
def load_webhook():
parsed = json.loads(secrets.get_secret_value(SecretId=SECRET_ID)["SecretString"])
return parsed["url"], parsed["secret"]
def build_payload(event):
detail = event["detail"]
alarm_name = detail["alarmName"]
state = detail["state"]
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z")
payload = {
"eventType": "incident",
"incidentId": alarm_name + "-" + state["timestamp"],
"action": "created",
"priority": INCIDENT_PRIORITY,
"title": "CloudWatch Alarm: " + alarm_name,
"timestamp": timestamp,
}
parts = [detail["configuration"].get("description"), state["reason"]]
payload["description"] = " / ".join([p for p in parts if p])
payload["service"] = SERVICE_NAME
payload["data"] = event
return payload
def handler(event, context):
print(json.dumps({"level": "INFO", "message": "received alarm event", "event": event}))
payload = build_payload(event)
body = json.dumps(payload)
timestamp = payload["timestamp"]
url, secret = load_webhook()
signature = base64.b64encode(
hmac.new(
secret.encode("utf-8"),
(timestamp + ":" + body).encode("utf-8"),
hashlib.sha256,
).digest()
).decode("utf-8")
request = urllib.request.Request(
url,
data=body.encode("utf-8"),
headers={
"Content-Type": "application/json",
"x-amzn-event-timestamp": timestamp,
"x-amzn-event-signature": signature,
},
method="POST",
)
with urllib.request.urlopen(request, timeout=15) as response:
status = response.status
text = response.read().decode("utf-8")
print(json.dumps({
"level": "INFO",
"message": "webhook responded",
"status": status,
"body": text,
"incidentId": payload["incidentId"],
"sentPayload": {k: v for k, v in payload.items() if k != "data"},
}))
return {"status": status, "incidentId": payload["incidentId"]}
CloudWatchアラームをトリガーにしたDevOps Agentのインシデントレスポンス調査
実行するとSNS Publish権限が不足しているエラーが出るように設定したLambda関数を実行して意図的にCloudWatchアラームの状態をアラート状態にしました。

「CloudWatchアラーム: medaka-prod-lambda-errors」という名前でインシデントレスポンスが開始されていたことが確認できました。

「IAMロール「medaka-prod-order-notifier-role」には、対象のSNSトピックに対するsns:Publish権限がありません。」というアラート原因の調査結果も出してくれました。

「不足しているIAMポリシーを追加する」ように緩和計画を提案してくれています。
安全に変更適用できるよう、準備〜事前検証〜適用〜事後検証まで準備してくれるのが良いですね。また、ロールバックのことまで考慮されているのも本番運用を見据えた場合には使いやすくて良いと思います。


アラート発生からDevOps Agentによる調査開始・調査完了までの時間
アラート発生から、DevOps Agentによる調査開始・調査完了までの時間を計測します。
見たい点としては、「アラート発生からどのくらいの速さで調査開始できるか」です。
CloudWatchアラームを見ると、「2026-08-09 11:58:54」にアラート状態になっています。

EventBridgeのInvocationsメトリクスも「2026-08-09 11:58」に記録されています。

CloudWatchアラームの状態遷移のイベントを受け取ってDevOps Agentを起動するLambda関数のログを確認したところ、「2026-08-09 11:58:55」に実行開始・終了していました。

DevOps Agentの調査開始は「2026-08-09 11:59:53」、調査完了は「2026-08-09 12:05:39」でした。

タイムラインの最後のメッセージには「調査開始から5分21秒経過」と表示されていました。画面の経過時間は最後のメッセージが出た時点のもので、調査完了までの5分45秒とは一致しません。

Webhookを実行するLambda関数実行からDevOps Agentの調査開始まで、1回目は1分ほどかかっていました。
全く同じエラーをLambdaで実行させてCloudWatchアラームのアラート発生→DevOps Agent調査を3回実行したので比較します。
| Webhook送信 | 調査開始 | 送信から開始まで | 調査時間 | 結果 | |
|---|---|---|---|---|---|
| 1 | 11:58:55 | 11:59:53 | 58秒 | 5分45秒 | 完了 |
| 2 | 16:15:42 | 16:15:52 | 10秒 | 8分35秒 | 完了 |
| 3 | 16:23:42 | 16:23:53 | 11秒 | 12秒 | 既存の調査に関連付けられた |
1回目だけ58秒かかっていて、2回目と3回目は10秒台でした。
1回目がその日の最初の実行だったこと以外に違いが見当たらないので理由は分かりません。調査そのものにかかった時間も5分45秒と8分35秒でばらついています。同じ障害を同じ内容で通知してもこの程度は変動するようです。
3回目は12秒で終わっていますが、これは調査が速かったからではありません。
調査結果を見ると「リンク済み」となっていて2回目の既存調査に関連付けられていたからでした。

詳細を見ると、以下のように「リンクされた調査」と結論付けられていました。
リンクされた調査
CloudWatch Alarm: medaka-prod-lambda-errors にリンクされています。 同一のCloudWatchアラーム(medaka-prod-lambda-errors)、同一サービス(Medaka Prod注文通知Lambda)、同一メトリクス種別(Lambdaエラー閾値超過)であり、プライマリのタイムスタンプ(07:15:52)から約8分後に発生しています。継続中の同一エラー状態が再検知されたものと判断できるため、同一根本原因として関連付けます。
同じ原因でCloudWatchアラートが発生→DevOps Agent起動という繰り返しが起きると、毎回DevOps Agentの調査が発生してDevOps Agentのコストが跳ね上がると思っていました。
同じCloudWatchアラームが連続で発生しても調査が積み上がらないので、コスト面でも安心できます。
既存調査と関連付ける挙動は、DevOps Agentの仕様のようでした。新規インシデントが届いた時点より前の20分間に動いている既存調査から類似した調査などを確認してインシデント間の関連性を判断するようです。
新しいインシデントが到着すると、 AWS DevOps Agent はルックバックウィンドウ (通常は 20 分) 内でアクティブな調査とともに分析します。AI を活用した分析を使用して、コンポーネントの類似性、地理的リージョン、タイミングパターンなどの要因を調べ、インシデント間の関係を判断します。
AWS DevOps Agent は、次の 3 つの決定のいずれかを行います。
・リンク済み – インシデントを既存の調査に関連付け、新しいインシデントに関するコンテキストを含むステアリングメッセージをその調査に送信します。
・スキップ済み – インシデントはスキルで定義されたスキップ基準に一致し、調査なしで自動的に却下されます。詳細については、「DevOps エージェントスキル」を参照してください。
・続行 — インシデントの新しい独立した調査をスケジュールします。
まとめ
Webhook経由でDevOps Agentの自動調査を開始できました。
3回試したところ、アラート発生から調査開始までは速いときで10秒台、遅いときで1分でした。
調査そのものにかかる時間も5分45秒から8分35秒までばらついています。
同じ障害を同じ内容で通知してもこの程度は変動すると思っておいたほうが良さそうです。
同じアラートが20分以内に続けて発生した場合、2回目以降は既存の調査に紐づけられて新しい調査がすぐに終わりました。
繰り返しアラートが発生しても調査が長時間走るなどしないことがわかったので、その点は少し安心かもしれません。
今回の検証でEventBridge→Lambda→DevOps Agentという流れで調査開始できたので、今後はHealthイベントやGuarddutyなどとの統合を試してみたいです。
ただ、Webhook用Lambda関数を用意・管理するのも少し手間なので、EventBridgeで直接ペイロードを渡してAPI呼び出しからDevOps Agentの自動調査ができたら良いなと感じました。







