Amazon SNS通知が分かりづらい問題を解決!~Bedrockで要約する実践ハンズオン~

スポンサーリンク
ハンズオン
スポンサーリンク

はじめに

AWSの監視運用では、アラート通知にSNSを利用するケースが多いですが、そのままの通知は情報が多すぎたり形式がバラバラで、内容をすぐに理解するのが難しいと感じる方も多いのではないでしょうか。

例:CloudWatchアラームがアラーム状態になった場合)

You are receiving this email because your Amazon CloudWatch Alarm "LoginFailuresAlarm" in the Asia Pacific (Tokyo) region has entered the ALARM state, because "Threshold Crossed: 1 out of the last 1 datapoints [6.0 (27/09/25 07:23:00)] was greater than or equal to the threshold (5.0) (minimum 1 datapoint for OK -> ALARM transition)." at "Saturday 27 September, 2025 07:38:29 UTC".

View this alarm in the AWS Management Console:
https**********************

Alarm Details:
- Name:                       LoginFailuresAlarm
- Description:                特定の期間内で管理コンソールへのアクセス失敗が複数回確認されたときにアラーム状態になります。
- State Change:               OK -> ALARM
- Reason for State Change:    Threshold Crossed: 1 out of the last 1 datapoints [6.0 (27/09/25 07:23:00)] was greater than or equal to the threshold (5.0) (minimum 1 datapoint for OK -> ALARM transition).
- Timestamp:                  Saturday 27 September, 2025 07:38:29 UTC

- AWS Account:                123456789012
- Alarm Arn:                  arn:aws:cloudwatch:ap-northeast-1:123456789012:alarm:LoginFailuresAlarm

Threshold:
- The alarm is in the ALARM state when the metric is GreaterThanOrEqualToThreshold 5.0 for at least 1 of the last 1 period(s) of 900 seconds.

Monitored Metric:
- MetricNamespace:                     LoginFailuresMetric
- MetricName:                          LoginFailuresMetric
- Dimensions:                         
- Period:                              900 seconds
- Statistic:                           Sum
- Unit:                                not specified
- TreatMissingData:                    notBreaching


State Change Actions:
- OK:
- ALARM: [arn:aws:lambda:ap-northeast-1:123456789012:function:**********] [arn:aws:sns:ap-northeast-1:123456789012:LoginFailureNotification]
- INSUFFICIENT_DATA:

これだとAWSの知識がないと、何が起きているのか、何をしたらいいのか、が分かりづらい内容ですよね。

今回の記事では、この「SNS通知が分かりづらい」という課題を解決するために、Amazon Bedrockを利用して通知内容を自動で要約し、より分かりやすい形でメール通知する仕組みを紹介します。

記事の内容を利用すると以下のようなメールに変換してくれます。
例:一定期間内に複数回の管理コンソールのログイン失敗を検知

※生成AIで原文を日本語で要約しています。生成AIの出力は必ずしも正しいとは限りません。

 【検知】管理コンソールへのログイン失敗アラーム

 【時刻】2025-09-27T08:51:05Z

 【内容】
 - 管理コンソールへのログイン失敗が一定の閾値を超えたことを検知しました。
 - アラーム名: LoginFailuresAlarm
 - アラーム状態: ALARM

 【影響】
 - 管理コンソールへの不正アクセスの可能性があります。
 - セキュリティ上の懸念が生じています。

 【対応】
 - ログ分析を行い、不審な活動の有無を確認する。
 - 必要に応じて、アカウントのロックや監視強化などの対応を検討する。
 - 関係者への通知と、原因究明および再発防止策の検討を行う。

原文は以下
{
  "source": "aws.cloudwatch",
  "alarmArn": "arn:aws:cloudwatch:ap-northeast-1:123456789012:alarm:LoginFailuresAlarm",
  "accountId": "123456789012",
  "time": "2025-09-27T07:38:29.086+0000",
  "region": "ap-northeast-1",
  "alarmData": {
    "alarmName": "LoginFailuresAlarm",
    "state": { 
      "value": "ALARM",
      "reason": "Threshold Crossed: 1 out of the last 1 datapoints [6.0 (27/09/25 07:23:00)] was greater than or equal to the threshold (5.0) (minimum 1 datapoint for OK -> ALARM transition).",
      "reasonData": "{\"version\":\"1.0\",\"queryDate\":\"2025-09-27T07:38:29.085+0000\",\"startDate\":\"2025-09-27T07:23:00.000+0000\",\"statistic\":\"Sum\",\"period\":900,\"recentDatapoints\":[6.0],\"threshold\":5.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2025-09-27T07:23:00.000+0000\",\"sampleCount\":6.0,\"value\":6.0}]}", 
      "timestamp": "2025-09-27T07:38:29.086+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\":\"2025-09-27T07:26:29.083+0000\",\"statistic\":\"Sum\",\"period\":900,\"recentDatapoints\":[],\"threshold\":5.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2025-09-27T07:11:00.000+0000\"}]}", 
      "timestamp": "2025-09-27T07:26:29.085+0000"
    }, 
    "configuration": {
      "description": "特定の期間内で管理コンソールへのアクセス失敗が複数回確認されたときにアラーム状態になります。",
      "metrics": [
        {
          "id": "32ccbabb-24ba-2793-c752-23498692cb7a",
          "metricStat": {
            "metric": {
              "namespace": "LoginFailuresMetric",
              "name": "LoginFailuresMetric",
              "dimensions": {}
            }, 
            "period": 900, 
            "stat": "Sum"
          }, 
          "returnData": true
        }
      ]
    }
  } 
}

実際にハンズオン形式で構築手順を紹介するので、記事を読み終える頃にはご自身の環境でも再現でき、運用保守での初動対応がスムーズになります。

ぜひ最後まで読んで参考にしてみてください!

環境構成

本記事で紹介するハンズオンの環境構成は以下となります。
CloudWatchアラームやEventBridgeのルールは事前に配備されているものとします。

費用

本記事のハンズオンで紹介するAWSのサービスに関する費用についてです。

★注意★

  • CloudWatchアラームやEventBridge、SNSはすでに配備されているものとして費用には含めておりません。
  • 本記事の金額は、2025/9/28時点の価格です。利用するモデルやリージョンによって金額が変わる場合があるため、最新の料金はAWS公式ページでご確認ください。AWS 料金表

1通あたりのコストは微小なので1000通あたりの費用で計算しています。

サービス名 メール1000通あたりの費用(USD) 詳細
IAM 0 USD 今回利用するIAMリソースは
費用が発生しません。
Lambda 0.01 USD 無料枠を考慮しない、かつ、
最小リソースで1000リクエスト
で計算
Bedrock 0.33 USD 1通あたり
入力トークン750→0.00019 USD
出力トークン100→0.00014 USD
CloudWatchログ 0.01 USD
※長期運用した場合
1通あたり1kb
月1000通で12か月保存で計算
→ 0.01 USD
合計 0.35 USD

ハンズオン程度であれば、ほぼ無料の範囲で利用可能です。

ハンズオン

事前準備

以下が事前にある前提でハンズオンを実施します。

  • AWSアカウントが配備済みであること
  • イベントの検知の仕組み(CloudWatchアラーム or EventBridge)が設定済みであること
  • 通知先のSNSトピックが設定済みであること

SNSトピックの作成

アラームを通知するメールアドレスを設定します。すでに作成済みの場合はスキップしていただいて構いません。

上部の検索画面で「SNS」と入力し、検索されたサービスから「Simple Notification Service」をクリックします。

左メニューから「トピック」をクリックし、画面右上の「トピックの作成」をクリックします。

「トピックの作成」画面が表示されます。
以下を入力してください。
・タイプ:スタンダード
・名前:任意の名前を入力してください。通知グループの名称となります
・表示名 – オプション:任意の名前を入力してください。メールの送付元の名前として利用されます。
その他の項目は任意で入力してください。入力が終わったら、「トピックを作成」をクリックしてください。

作成したトピックの画面が表示されます。「サブスクリプションの作成」をクリックします。

「サブスクリプションの作成」画面が表示されます。
以下を入力してください。
・プロトコル:Eメール
・エンドポイント:通知先のメールアドレス(メーリングリストも登録可能)
その他の項目は任意で設定してください。入力が終わったら、「サブスクリプションの作成」をクリックします。

しばらくすると、指定したメールアドレスに「AWS Notification – Subscription Confirmation」という件名でメールが通知されます。
注意)Confirm subscriptionのリンクはクリックしないでください。詳細は以下を確認してください。
SNS メーリングリストの受信者により、メーリングリストのサブスクリプションが解除されないようにする | AWS re:Post

Confirm subscriptionのリンクを右クリックしURLをコピーしてください。

作成したSNSトピックの画面に戻ります。
作成したサブスクリプションを選択し、「サブスクリプションの確認」をクリックしてください。

先ほどメールに記載されていたリンクを貼り付けて、「サブスクリプションの確認」をクリックします。

ステータスが「確認済み」となります。

設定後、SNSトピックのARNをコピーします。IAMロール/Lambda関数の設定で利用します。

Lambda関数用のIAMロールの作成

Lambda関数に紐づける権限の設定をします。

上部の検索画面で「IAM」と入力し、検索されたサービスから「IAM」をクリックします。

IAMの画面が表示されたら、左メニューから「ポリシー」をクリックし、画面右上の「ポリシーの作成」をクリックしてください。

ポリシーエディタが表示されます。表示形式を「JSON」に切り替えてください。

以下のポリシーを入力してください。【作成したSNSトピックのARN】はSNSトピック作成時にコピーしたARNに置き換えてください。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    },
    { 
      "Effect": "Allow",
      "Action": [
        "sns:Publish"
      ],
      "Resource": "【作成したSNSトピックのARN】"
    },
    {
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel"
      ],
      "Resource": "*"
    }
  ]
}

入力が完了したら、「次へ」をクリックしてください。

ポリシー名を任意の名前で入力し、「ポリシーの作成」をクリックしてください。

Lambda関数に紐づけるIAMロールを作成します。左メニューから「ロール」をクリックし、「ロールを作成」をクリックしてください。

以下を選択し、「次へ」をクリックしてください。
・信頼されたエンティティタイプ:AWSのサービス
・サービスまたはユースケース:Lambda

許可を選択する画面が表示されます。前の手順で作成したポリシーを選択し、「次へ」をクリックしてください。

ロール名を任意の名前で入力し、「ロールを作成」をクリックしてください。

Lambda関数の作成・設定

アラーム検知後にアラームの内容を要約する処理をLambda関数で実装します。

上部の検索画面で「Lambda」と入力し、検索されたサービスから「Lambda」をクリックします。

左メニューから「関数」をクリックし、画面右上の「関数を作成」をクリックしてください。 

以下を選択/入力して、「関数の作成」をクリックしてください。
・以下いずれかのオプションを選択して、関数を作成します。:一から作成
・関数名:任意の名前を入力してください。
・ランタイム:Python3.13
・実行ロール:既存のロールを使用する
・既存のロール:作成したIAMロール

関数が作成されたら、「設定」タブを選択し、左メニューから「一般設定」をクリックし、「設定」をクリックしてください。

タイムアウトの時間を30秒に設定し、「保存」をクリックしてください。(3秒だと生成AIの回答を待っている最中にタイムアウトとなる可能性があるため)

CloudWatchアラームからLambdaの実行を許可するための設定を追加します。
「設定」タブを選択し、左メニューから「アクセス権限」をクリックし、リソースベースのポリシーステートメント欄から「アクセス権限の追加」をクリックしてください。

以下を設定/入力し、「保存」をクリックしてください。
・ポリシーステートメントを編集:AWS アカウント
・ステートメント名:任意の名前を入力
・プリンシパル名:lambda.alarms.cloudwatch.amazonaws.com
・アクション:lambda:InvokeFunction

リソースベースのポリシーステートメント欄に入力した内容が追加されていることを確認してください。

環境変数の設定をします。
「設定」タブを選択し、左メニューから「環境変数」をクリックし、「編集」をクリックしてください。

以下の環境変数を追加してください。追加後、「保存」をクリックしてください。
・BEDROCK_MODEL_ID:anthropic.claude-3-haiku-20240307-v1:0
・SNS_TOPIC_ARN:作成したSNSトピックのARN

ソースコードの反映をします。
「コード」タブを選択し、以下のソースコードで「lambda_function.py」を書き換えてください。書き換え後、「Deploy」をクリックしてください。

ソースコード:

# lambda_function.py (Python 3.13)
import os
import json
import boto3
from datetime import datetime, timezone

SNS_TOPIC_ARN = os.environ["SNS_TOPIC_ARN"]
BEDROCK_MODEL_ID = os.environ.get("BEDROCK_MODEL_ID", "anthropic.claude-3-haiku-20240307-v1:0")

sns = boto3.client("sns")
bedrock_rt = boto3.client("bedrock-runtime")


def iso_now() -> str:
    return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


def build_bullet_mail(detected_title: str, detected_at: str, raw_text: str, what=None, impact=None, nxt=None) -> tuple[str, str]:
    """SNS.Email向けのプレーンテキスト本文と件名を生成"""
    what = what or []
    impact = impact or []
    nxt = nxt or []

    subject = f"[ALERT] {detected_title} - {detected_at}"
    lines = [
        f"※生成AIで原文を日本語で要約しています。生成AIの出力は必ずしも正しいとは限りません。",
        f"【検知】{detected_title}",
        f"【時刻】{detected_at}",
    ]
    if what:
        lines.append("【内容】\n- " + "\n- ".join(what))
    if impact:
        lines.append("【影響】\n- " + "\n- ".join(impact))
    if nxt:
        lines.append("【対応】\n- " + "\n- ".join(nxt))
    if raw_text:
        lines.append("\n原文は以下\n " + raw_text)
    body = "\n\n".join(lines)
    # SNSの件名は最大100文字程度に抑える
    return subject[:100], body


def summarize_with_bedrock(raw_text: str) -> dict:
    """
    Bedrockで“箇条書き要約”を作る(任意)。
    返り値は build_bullet_mail に差し込みやすい辞書形式。
    """
    system = (
        "あなたはSRE向けの一次報告要約者です。"
        "入力テキストから、検知内容・影響・次のアクションを日本語の箇条書きで短くまとめてください。"
        "最大各5行、固有情報(鍵・個人情報)は[MASKED]に置換してください。"
        "各出力項目について入力情報から読み取れない場合は「入力内容から出力不可」として出力してください。嘘はつかないでください。"
        "出力項目の詳細は以下です。"
        "title: アラームの要約タイトル。日本語で出力してください。メールの件名にも利用するため、短く簡潔に件名を出力。"
        "what: 検知内容を配列で記載。"
        "impact: 影響を配列で記載。"
        "next: この後の対応アクションを配列で記載。"
    )
    user_prompt = f"""
# 入力
{raw_text}

# 出力フォーマット(JSON)
{{
  "title": "...",
  "what": ["..."],
  "impact": ["..."],
  "next": ["..."]
}}
"""

    request_body = {
        "anthropic_version": "bedrock-2023-05-31",
        "system": system,
        "messages": [{"role": "user", "content": [{"type": "text", "text": user_prompt}]}],
        "max_tokens": 600,
        "temperature": 0.2,
    }

    res = bedrock_rt.invoke_model(
        modelId=BEDROCK_MODEL_ID,
        contentType="application/json",
        accept="application/json",
        body=json.dumps(request_body).encode("utf-8"),
    )
    payload = json.loads(res["body"].read().decode("utf-8"))
    text = payload.get("content", [{}])[0].get("text", "").strip()

    # 生成文からJSON部分を素直に抽出(簡易):JSONだけ返すようにプロンプト設計している前提
    try:
        parsed = json.loads(text)
    except json.JSONDecodeError:
        # JSONで返らない場合は安全にフォールバック
        parsed = {
            "title": "要約",
            "what": [text[:300]] if text else [],
            "impact": [],
            "next": [],
        }
    return parsed


def event_to_raw_text(event) -> str:
    """
    受けとったeventから“要約にかける原文”を作る。
    - CloudWatch Alarm
    - SNS経由
    - 任意のアプリイベント(JSON)
    などに対応するため、まずは丸ごとJSON文字列化。
    必要に応じてここで抜粋・整形を追加してください。
    """
    # CloudWatch Alarm の構造なら詳細を拾って拡張してもOK
    try:
        if "Records" in event and event["Records"][0].get("Sns"):
            # SNSトリガー(他サービス→SNS→このLambda の場合)
            msg = event["Records"][0]["Sns"]["Message"]
            return msg if isinstance(msg, str) else json.dumps(msg, ensure_ascii=False)
    except Exception:
        pass

    return json.dumps(event, ensure_ascii=False, indent=3)


def lambda_handler(event, context):
    print(event)
    detected_at = iso_now()

    raw_text = event_to_raw_text(event)
    summarized = summarize_with_bedrock(raw_text)
    title = summarized.get("title") or "検知イベント"
    what = summarized.get("what") or []
    impact = summarized.get("impact") or []
    nxt = summarized.get("next") or []
    subject, body = build_bullet_mail(title, detected_at, raw_text, what, impact, nxt)

    # SNSへPublish(Email購読者へ送信される)
    try:
        sns.publish(
            TopicArn=SNS_TOPIC_ARN,
            Subject=subject,
            Message=body,
        )
        return {"statusCode": 200, "subject": subject}
    except Exception as e:
        print(f"SNS publish failed: {e}")
        raise

CloudWatchアラームの設定変更・EventBridgeのトリガー設定

それぞれの利用ケースに合わせて①・②を設定してください。①②両方とも登録・複数登録が可能です。

①CloudWatchアラームから呼び出す場合

CloudWatchアラームをトリガーとしてLambdaを呼び出す設定をします。

上部の検索画面で「CloudWatch」と入力し、検索されたサービスから「CloudWatch」をクリックします。

左メニューから「すべてのアラーム」をクリックし、要約したいアラームを選択、画面右上の「アクション」>「編集」をクリックします。

アラームの編集画面が表示されたら、左メニューから「アクションの設定」をクリックしてください。

Lambdaアクション欄の「Lambdaアクション」の追加をクリックします。

以下を設定します。
・アラーム状態のトリガー:通知したい状態を選択してください。(例では「アラーム状態」を指定)
・関数を選択してください:Lambda関数の作成・設定で作成したLambda関数名を選択してください。
設定後、「プレビューと更新」画面でアラーム設定情報を更新してください。

②EventBridgeから呼び出す場合

AWS内の特定イベントをトリガーとしてLambdaを呼び出す設定をします。

上部の検索画面で「EventBridge」と入力し、検索されたサービスから「Amazon EventBridge」をクリックします。

左メニューから「ルール」をクリックし、要約したいルールを選択、画面右上の「編集」をクリックします。

左メニューの「ターゲットを選択」をクリックしてください。

ターゲットの設定に以下を追加します。
・ターゲットタイプ:AWSのサービス
・ターゲットを選択:Lambda関数
・ターゲットの場所:このアカウントのターゲット
・関数:Lambda関数の作成・設定で作成したLambda関数名を選択してください。
追加後、「確認と更新にスキップ」をクリックし、ルールを更新してください。

Bedrockモデルの有効化

以下を参考に、「Claude 3 Haiku」を有効化してください。
Amazon Bedrockの基盤モデルを有効化して使ってみる

動作確認

アラーム発生やイベント検知をトリガーにLambda関数を起動してみます。

CloudWatchアラーム発生後の通知メール

アラーム発生後の通知は以下となりました。
例):一定期間内に複数回の管理コンソールのログイン失敗を検知

※生成AIで原文を日本語で要約しています。生成AIの出力は必ずしも正しいとは限りません。

【検知】管理コンソールへのログイン失敗アラーム

【時刻】2025-09-27T08:51:05Z

【内容】
- 管理コンソールへのログイン失敗が一定の閾値を超えたことを検知しました。
- アラーム名: LoginFailuresAlarm
- アラーム状態: ALARM

【影響】
- 管理コンソールへの不正アクセスの可能性があります。
- セキュリティ上の懸念が生じています。

【対応】
- ログ分析を行い、不審な活動の有無を確認する。
- 必要に応じて、アカウントのロックや監視強化などの対応を検討する。
- 関係者への通知と、原因究明および再発防止策の検討を行う。


原文は以下
 {
   "source": "aws.cloudwatch",
   "alarmArn": "arn:aws:cloudwatch:ap-northeast-1:
123456789012:alarm:LoginFailuresAlarm",
   "accountId": "123456789012",
   "time": "2025-09-27T07:38:29.086+0000",
   "region": "ap-northeast-1",
   "alarmData": {
      "alarmName": "LoginFailuresAlarm",
      "state": {
         "value": "ALARM",
         "reason": "Threshold Crossed: 1 out of the last 1 datapoints [6.0 (27/09/25 07:23:00)] was greater than or equal to the threshold (5.0) (minimum 1 datapoint for OK -> ALARM transition).",
         "reasonData": "{\"version\":\"1.0\",\"queryDate\":\"2025-09-27T07:38:29.085+0000\",\"startDate\":\"2025-09-27T07:23:00.000+0000\",\"statistic\":\"Sum\",\"period\":900,\"recentDatapoints\":[6.0],\"threshold\":5.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2025-09-27T07:23:00.000+0000\",\"sampleCount\":6.0,\"value\":6.0}]}",
         "timestamp": "2025-09-27T07:38:29.086+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\":\"2025-09-27T07:26:29.083+0000\",\"statistic\":\"Sum\",\"period\":900,\"recentDatapoints\":[],\"threshold\":5.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2025-09-27T07:11:00.000+0000\"}]}",
         "timestamp": "2025-09-27T07:26:29.085+0000"
      },
      "configuration": {
         "description": "特定の期間内で管理コンソールへのアクセス失敗が複数回確認されたときにアラーム状態になります。",
         "metrics": [
            {
               "id": "32ccbabb-24ba-2793-c752-23498692cb7a",
               "metricStat": {
                  "metric": {
                     "namespace": "LoginFailuresMetric",
                     "name": "LoginFailuresMetric",
                     "dimensions": {}
                  },
                  "period": 900,
                  "stat": "Sum"
               },
               "returnData": true
            }
         ]
      }
   }
}

原文からも発生した内容はなんとなくは分かりますが、影響や対応方法を提示してくれるので、初動対応までの時間が早くなりそうです。

特定イベント発生後の通知メール

特定イベント発生後の通知は以下となりました。
例):S3バケットのパブリックアクセスブロックが解除された

※生成AIで原文を日本語で要約しています。生成AIの出力は必ずしも正しいとは限りません。

【検知】S3バケットの公開アクセスブロック設定変更

【時刻】2025-09-27T14:30:19Z

【内容】
- ユーザー[MASKED]がS3バケット「xxxxxxxxxxxxxxxxxxxxxx」の公開アクセスブロック設定を変更した

【影響】
- バケットの公開アクセスが制限されなくなった可能性がある

【対応】
- バケットの公開アクセス設定を確認し、必要に応じて適切な設定に変更する
- ユーザーの行動を確認し、不審な活動がないかモニタリングする


原文は以下
 {
   "version": "0",
   "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
   "detail-type": "AWS API Call via CloudTrail",
   "source": "aws.s3",
   "account": "123456789012",
   "time": "2025-09-27T14:30:11Z",
   "region": "ap-northeast-1",
   "resources": [],
   "detail": {
      "eventVersion": "1.11",
      "userIdentity": {
         "type": "IAMUser",
         "principalId": "123456789012",
         "arn": "arn:aws:iam::123456789012:xxxxxxxx",
         "accountId": "123456789012",
         "accessKeyId": "XXXXXXXXXXXXXXXXXXXX",
         "sessionContext": {
            "attributes": {
               "creationDate": "2025-09-27T06:35:24Z",
               "mfaAuthenticated": "true"
            }
         }
      },
      "eventTime": "2025-09-27T14:30:11Z",
      "eventSource": "s3.amazonaws.com",
      "eventName": "PutBucketPublicAccessBlock",
      "awsRegion": "ap-northeast-1",
      "sourceIPAddress": "XXXX.XXX.XXX.XXX",
      "userAgent": "XXXXXXXX",
      "requestParameters": {
         "publicAccessBlock": "",
         "bucketName": "xxxxxxxxxxxxxxxxxxxxxx",
         "PublicAccessBlockConfiguration": {
            "xmlns": "http://s3.amazonaws.com/doc/2006-03-01/",
            "RestrictPublicBuckets": false,
            "BlockPublicPolicy": false,
            "BlockPublicAcls": false,
            "IgnorePublicAcls": false
         },
         "Host": "s3.ap-northeast-1.amazonaws.com"
      },
      "responseElements": null,
      "additionalEventData": {
         "SignatureVersion": "SigV4",
         "CipherSuite": "TLS_AES_128_GCM_SHA256",
         "bytesTransferredIn": 291,
         "AuthenticationMethod": "AuthHeader",
         "x-amz-id-2": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
         "bytesTransferredOut": 0
      },
      "requestID": "XXXXXXXXXXXXXXXX",
      "eventID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "readOnly": false,
      "resources": [
         {
            "accountId": "123456789012",
            "type": "AWS::S3::Bucket",
            "ARN": "arn:aws:s3:::xxxxxxxxxxxxxxxxxxxxxx"
         }
      ],
      "eventType": "AwsApiCall",
      "managementEvent": true,
      "recipientAccountId": "123456789012",
      "eventCategory": "Management",
      "tlsDetails": {
         "tlsVersion": "TLSv1.3",
         "cipherSuite": "TLS_AES_128_GCM_SHA256",
         "clientProvidedHostHeader": "s3.ap-northeast-1.amazonaws.com"
      }
   }
}

特定イベントの通知は原文だけでは状況把握に時間がかかるため、発生事象をまとめてくれるのはありがたいですね。
こちらも初動対応が早くなりますし、生成AIを利用するのは効果的ですね。

参考)CloudWatchログの保管期間の設定

Lambda関数の実行結果はCloudWatchログに出力されます。
初期設定だと保持期間が無制限となっています。ちりつもですが、長期間利用すると想定外の課金につながる可能性があるため、保持期間を設定しておきましょう。
本設定はLambda関数の初回実行後(厳密に言うとロググループ作成後)に可能です。

作成したLambda関数を開きます。「モニタリング」タブを選択し、「CloudWatchログを表示」をクリックしてください。

Lambda関数のログが保管されるロググループが表示されます。

右上の「アクション」>「保持期間を編集」を選択します。

ログを保持しておきたい期間を指定し、「保存」をクリックしてください。

設定が反映されます。

ハンズオンの感想

ハンズオンをしてみて、よかったこと、改善ポイントをあげてみました。
純粋にコストパフォーマンスはいいかなと思いました。
AIの回答を鵜呑みにしすぎない、サンプルのプログラム/プロンプトを改善して精度を上げるといったことは必要です。

よかったこと

  • 初動対応が早くなる
    • 英語が苦手な人でも日本語にしてくれる
    • 影響や対応内容も記載してくれる
  • コスパがよい
    • 初動対応までの調査の時間が削減できる上、コストがそこまでかからない

改善ポイント

  • たまにAIがもっともらしい誤情報(ハルシネーション)を提示する場合がある
    • 参考にする程度がよさそう。最終確認は実物確認をする。
  • 一部英語となる場合がある
    • プロンプトを改善したり、複数回生成AIとやり取りしてブラッシュアップする

おわりに

本記事では、Amazon SNS の通知が読みづらいという課題に対し、AWS の生成 AI サービスである Amazon Bedrock を用いて通知内容を要約し、分かりやすく伝える方法をハンズオン形式で紹介しました。

要約により「何が起きたか/どんな影響があり得るか/次に何をすべきか」を即座に把握でき、トラブル発生時の初動対応を素早く進められます。コストも小さく、コストパフォーマンスに優れます。

一方で、生成 AI の特性上、もっともらしい誤情報が出る場合があります。以下の対策でリスクを抑えましょう。

  • プロンプトを継続的に調整し、必要に応じて複数回生成して内容をブラッシュアップする
  • 通知内容を鵜呑みにせず、原文や関連ログで最終確認する

まずは小さく導入し、自分たちの運用に合わせてブラッシュアップしていくことをおすすめします。

自分たちの運用に合わせてブラッシュアップするには、要約プロンプト設計・モデル選定・コスト最適化といった生成AIの基礎が欠かせません。
短時間で体系的に身につけたい方は、実例が豊富な Udemyの生成AIコースが役立ちます。
今回の要約ワークフローにも直結する内容が多いので、まずは自分の課題に合う講座をチェックしてみてください。

Udemyの生成AIコース一覧を見る

タイトルとURLをコピーしました