GuardDuty Findings を Bedrock で要約して SES でメール通知する AWS サンプルを試してみた
はじめに
GuardDuty の検出を Bedrock を使っていい感じに通知したいなーと考えていたんですが、aws-samples にちょうどいいサンプルを見つけました。
CloudFormation テンプレート 1 本でデプロイできるシンプルな構成だったので、実際に動かして雰囲気を確認してみました。
サンプルの構成
このサンプルは GuardDuty Finding が発生したら EventBridge → SQS → Lambda という流れで処理する構成です。
Lambda の中で Bedrock の Claude にプロンプトを投げて要約させ、整形した HTML メールを SES で送ります。

参考:GitHub - aws-samples/analyze-aws-guardduty-findings-with-bedrock · GitHub
リソースとしては以下のものが CloudFormation でまとめて作られます。
| リソース | 役割 |
|---|---|
| EventBridge Rule | GuardDuty Finding を SQS に転送 |
| SQS Queue (Main + DLQ) | Findings のバッファリングと失敗時の退避 |
| Lambda Function | Bedrock 呼び出しと SES 送信(Python 3.12) |
| IAM Role | Lambda 実行用のロール |
DLQ も用意されており、maxReceiveCount: 3 で失敗時の退避先も確保されているのが良いですね。
前提条件
試すにあたって以下の準備が必要です。
- GuardDuty が有効化されている
- SES で送信元・宛先メールアドレスが検証済み(サンドボックスの場合は受信側も要検証)
- 利用リージョンで Bedrock の Claude Sonnet 4.6 モデルアクセスが許可されている
私はサンドボックスのまま試したので、送信元と受信先の両方を SES の検証済み ID に登録しました。
やってみる
デプロイ
リポジトリをクローンして CloudFormation でデプロイします。
test@example.comは任意の値に書き換えてください。同一アドレスでテストするだけなら 1 回の検証で済みます。
> git clone https://github.com/aws-samples/analyze-aws-guardduty-findings-with-bedrock
> cd analyze-aws-guardduty-findings-with-bedrock
> aws cloudformation deploy \
--template-file guardduty_findings_analyzer_ses.yml \
--stack-name guardduty-analyzer \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
SenderEmail=test@example.com \
ReceiverEmail=test@example.com
Successfully created/updated stack が出たらデプロイ完了です。
リソース数も少ないので 1 〜 2 分程度で終わりました。
以下コマンド実行で SES の検証メールが届くので、リンクをクリックして検証を完了させてください。
> aws ses verify-email-identity --email-address test@example.com
サンプルコードの修正
実はこのサンプル、デプロイしたあとに Lambda を動かすとそのままではエラーになります。
サンプル公開時から Bedrock 側の仕様が変わっていることが原因なので、Lambda コードを少し直す必要がありました。
発生したエラー
まず最初に出るのが、旧モデルを on-demand 呼び出しできないというエラーです。
Error processing GuardDuty finding: An error occurred (ValidationException) when
calling the InvokeModel operation: Invocation of model ID
anthropic.claude-3-sonnet-20240229-v1:0 with on-demand throughput isn't supported.
Retry your request with the ID or ARN of an inference profile that contains this model.
サンプルが指定している Claude 3 Sonnet は、現在では推論プロファイル経由でしか呼び出せなくなっています。
せっかくなので新しい Claude Sonnet 4.6 へ乗り換えることにしました。
modelId を差し替えて再デプロイすると、今度は別のエラーが出ます。
Error processing GuardDuty finding: An error occurred (ValidationException) when
calling the InvokeModel operation: `temperature` and `top_p` cannot both be
specified for this model. Please use only one.
新しい Claude モデルでは temperature と top_p の同時指定はサポートされていません。
修正内容
index.py と guardduty_findings_analyzer_ses.yml 内 ZipFile セクションの bedrock.invoke_model を以下のように差し替えました。
logger.info("Invoking Bedrock with Claude 3.5 Sonnet model")
response = bedrock.invoke_model(
modelId='anthropic.claude-3-sonnet-20240229-v1:0',
body=json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 1000,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.1,
"top_p": 1,
"top_k": 250
})
)
logger.info("Invoking Bedrock with Claude Sonnet 4.6 model")
response = bedrock.invoke_model(
modelId='jp.anthropic.claude-sonnet-4-6',
body=json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 1000,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.1
})
)
変更点は以下の通りです。
| 項目 | Before | After |
|---|---|---|
| modelId | anthropic.claude-3-sonnet-20240229-v1:0 |
jp.anthropic.claude-sonnet-4-6 |
| 呼び出し方式 | on-demand(直接モデル指定) | Cross-Region Inference Profile(JP) |
top_p |
1 |
削除 |
top_k |
250 |
削除 |
jp. プレフィックスは日本国内(東京・大阪)に限定してルーティングする推論プロファイルです。データレジデンシーを日本に揃えたかったので JP プロファイルを採用しました。グローバルに広げたい場合は global.anthropic.claude-sonnet-4-6 も選択できます。
利用可能なプロファイル ID は以下のコマンドで確認できます。
> aws bedrock list-inference-profiles --region ap-northeast-1 \
--query 'inferenceProfileSummaries[?contains(inferenceProfileId, `sonnet-4-6`)].[inferenceProfileId,inferenceProfileName]' \
--output table
修正後にもう一度 aws cloudformation deploy を実行すれば反映されます。
サンプル Finding の生成
GuardDuty には動作確認用にサンプル Findings を生成する機能があるので、これを使って Lambda が動くかを確認します。
> aws guardduty create-sample-findings \
--detector-id $(aws guardduty list-detectors --query 'DetectorIds[0]' --output text) \
--finding-types "Recon:EC2/PortProbeUnprotectedPort"
コマンドを実行すると、すぐに EventBridge を経由して SQS にメッセージが入り、Lambda が起動します。
メールの確認
しばらく待つと指定したメールアドレスに通知が届きます。
Severity に応じて赤・橙・黄でヘッダーの色が変わるようになっており、一目で重要度を把握できます。



メール本文には以下の情報が含まれていました。
- ヘッダー:Severity ラベル(HIGH / MEDIUM / LOW)と数値
- AWS アカウント、Finding ID、リージョン、リソースタイプ
- Finding のタイトルと説明
- インスタンス ID、インスタンスタイプ
- 接続方向、リモート IP、ポート、プロトコル
- Bedrock による AI 分析結果
- 検知時刻(First Seen / Last Seen)
なお Network Details の項目は、今回のサンプル Finding(PortProbe 系)ではすべて N/A 表示になりました。
これは Lambda コードが networkConnectionAction のみを参照しているためです。PortProbe 系 Finding が使う portProbeAction には対応していません。
一方で AI 分析パートはプロンプトに Finding 全体の JSON を渡しているため、ポート情報も含めて Markdown 形式で構造化された分析結果を生成してくれています。
CloudWatch Logs での動作確認
Lambda の実行ログを見ると、Bedrock の呼び出しから SES の送信まで一連の流れがログ出力されています。

ちゃんと Invoking Bedrock with Claude Sonnet 4.6 model や Sending summary via SES のログが出ていれば期待通り動いている状態です。
気になった点
動かしてみて気づいた点をいくつか挙げておきます。
あくまでサンプルなので、本番投入する場合は手を入れたいところです。
- Bedrock のモデル指定がそのままだと動かないため修正が必要
- 通知チャネルが SES のみなので、Slack や Teams を使っている場合は SNS や Chatbot 経由に拡張したくなる
- プロンプトが英語なので、日本語の運用チームで使うなら日本語での要約に切り替えたい
このあたりは README にも特に注記はないので、そのまま使うのではなく「叩き台」として認識しておくのが良さそうです。
まとめ
GuardDuty Findings を Bedrock で要約して SES でメール通知する AWS サンプルを試してみました。
CloudFormation 1 本でサクッと動かせるので、Bedrock を使った Findings 一次対応の感触をつかむには非常に良い題材だなと感じました。
そのまま本番に使うにはモデルや IAM 周りで手を入れたい部分はありますが、社内検証や PoC のスタート地点としてはおすすめできます。
こうした 「Findings の一次調査が地味に手間だな」と感じることがあれば、とりあえずこのサンプルを動かしてみましょう。
運用改善のヒントが見つかるはずです。
以上、鈴木純がお送りしました。







