1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CloudWatchアラームからEventBridge経由でAWS DevOps Agentの自動調査を開始する(調査開始までの時間も計測)

1
Last updated at Posted at 2026-08-09

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のインシデントレスポンス調査を開始します。

AWSDevOpsAgent-Alarmトリガー.png

DevOps AgentのWebhookの設定

まず、DevOps Agentを起動するためのWebhookを設定します。すべてコンソールから作業をします。

エージェントスペース > ウェブフック > Webhook を追加
image.png

データスキーマを検証を次へ
image-1.png

ウェブフックの認証タイプはHMACを選択します。
image-2.png

URL と認証情報を生成する
image-3.png

URL と認証情報を生成して保存
スクリーンショット 2026-08-07 23.27.17.png

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

curlで疎通確認

Webhookが準備できたので疎通確認をします。
AWSドキュメントに「コードの例」として記載されているものをそのまま使います。

「バージョン 1 (HMAC 認証) - cURL」というのをそのまま使ってみます。

以下を「curl.sh」などに保存して bash curl.sh で実行します。

WEBHOOK_URLSECRET は先ほど発行した 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)
image-6.png

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"]
    }
  }
}

image-7.png

ターゲットはLambda関数に設定します。ターゲットのLambda関数で受け取ったイベントをWebhookでDevOps Agentに送ることになります。
image-8.png

上記以外の条件で絞り込みがしたい方はドキュメントのイベント例を参考にしてみてください。

EventBridgeからのイベント形式を確認

イベントを受け取りWebhookでDevOps Agentに送るLambda関数を作成する前に、CloudWatchアラームから発行されるイベント形式を確認します。
EventBridge→SNSにイベントを送るよう設定して確認します。
スクリーンショット 2026-08-09 11.42.48.png

Lambda が受け取るイベント

CloudWatchアラームの状態がアラート状態になったときのイベントが確認できました。
この内容をLambda関数でDevOps Agentに送る形にします。

image-9.png

{
  "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アラームの状態をアラート状態にしました。
image-10.png

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

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

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

アラート発生からDevOps Agentによる調査開始・調査完了までの時間

アラート発生から、DevOps Agentによる調査開始・調査完了までの時間を計測します。
見たい点としては、「アラート発生からどのくらいの速さで調査開始できるか」です。

CloudWatchアラームを見ると、「2026-08-09 11:58:54」にアラート状態になっています。
スクリーンショット 2026-08-09 15.40.32.png

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

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

DevOps Agentの調査開始は「2026-08-09 11:59:53」、調査完了は「2026-08-09 12:05:39」でした。
スクリーンショット 2026-08-09 15.47.40.png

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

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回目の既存調査に関連付けられていたからでした。
スクリーンショット 2026-08-09 20.30.02.png

詳細を見ると、以下のように「リンクされた調査」と結論付けられていました。

リンクされた調査
CloudWatch Alarm: medaka-prod-lambda-errors にリンクされています。 同一のCloudWatchアラーム(medaka-prod-lambda-errors)、同一サービス(Medaka Prod注文通知Lambda)、同一メトリクス種別(Lambdaエラー閾値超過)であり、プライマリのタイムスタンプ(07:15:52)から約8分後に発生しています。継続中の同一エラー状態が再検知されたものと判断できるため、同一根本原因として関連付けます。
スクリーンショット 2026-08-09 20.27.48.png

同じ原因で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の自動調査ができたら良いなと感じました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?