GuardDutyは有効にしただけでは、検出結果がコンソールに溜まっていくだけです。EventBridgeのルールで検出結果を拾い、SNSのメールやSlackへ流して初めて、誰かが検出結果に気づける状態になる構成です。本記事では、GuardDutyの検出結果を重大度で絞って通知する設定と、CloudTrailが記録するAPI呼び出し(証跡の停止やIAMの変更)を拾うルールを、AWS CLIのコード付きで組み立て、IAMの操作が東京のルールに届かない理由と自動隔離の判断まで扱います。EventBridgeそのものの仕組みはAmazon EventBridgeとは?仕組み・料金とCLI・Pythonでの実装手順で整理しています。仕様は2026年10月時点の公式ドキュメントの記載です。
まとめ:GuardDutyとCloudTrailの通知はルール2系統とSNSトピック2本で組む
GuardDutyの検出結果はsourceがaws.guardduty、detail-typeがGuardDuty Findingのイベントとして、検出したリージョンのデフォルトバスに届きます。通知の起点はdetail.severityをnumeric演算子で7以上に絞るルール1本で十分です。新規の検出はほぼリアルタイムで届き、同じ検出の再発は既定で6時間ごとに1件へまとめられます。
CloudTrailのAPI呼び出しはAWS API Call via CloudTrailとして届きますが、証跡が有効なことが前提です。IAMとSTSの操作は東京ではなくus-east-1で記録されるため、そちらにもルールを置きます。送り先は、メール用に入力トランスフォーマーで整形したトピックと、Amazon Q DeveloperでSlackへ流す未変換のトピックに分けるのが扱いやすい構成です。自動隔離のLambdaは、対処が決まっている検出タイプに限って足します。
GuardDutyとCloudTrailが送るイベントの形と届く条件を確かめる
ここを読み違えると「ルールは正しいのに届かない」状態になります。
GuardDuty Findingイベントのdetail構造と通知文に載せる6項目
GuardDutyのEventBridge連携ページによると、イベントのdetailには検出結果1件分のJSONオブジェクトがそのまま入ります。配列ではないため、1イベント=1検出結果として扱う形式です。通知に載せる項目は、実務では次の6つで足ります。
detail.severity:重大度の数値(1.0〜10.0)detail.type:検出タイプ(例:UnauthorizedAccess:EC2/SSHBruteForce)detail.titleとdetail.description:人が読む概要と説明detail.accountId:検出が起きたアカウントIDregion:検出したリージョンdetail.id:検出結果ID(コンソールのURLを組むのに使う)
重大度の区分は、Critical が9.0〜10.0、High が7.0〜8.9、Medium が4.0〜6.9、Low が1.0〜3.9です。通知の閾値はこの区分の境目に合わせて決めます。
新規はほぼリアルタイム・再発は15分〜6時間で集約される送信頻度
新しい検出IDが生まれたときの通知は、ほぼリアルタイムで送られ、この頻度は変えられません。同じ検出の再発は別の扱いです。公式によると、6時間以内の後続の発生は1つのイベントにまとめて送られ、管理者アカウントであれば15分・1時間・6時間(既定)から選べます。CLIではupdate-detectorの--finding-publishing-frequencyで指定します。
DETECTOR_ID=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text)
aws guardduty update-detector --detector-id "$DETECTOR_ID" \
--finding-publishing-frequency FIFTEEN_MINUTES
再発の回数は検出結果の詳細のCountに積み上がり、Created atとUpdated atがずれていれば継続中の事象です。もう1つ見落としやすいのが抑制ルールです。抑制ルールで自動アーカイブされた検出結果は、最初の1件も含めてEventBridgeに送られません。通知が多すぎる対策で抑制ルールを広く書くと、通知も一緒に消えます。
CloudTrailのAPI Callイベントは証跡の有効化と変更系APIが前提
EventBridgeのCloudTrail連携ページでは、CloudTrailが送るdetail-typeとしてAWS API Call via CloudTrail、AWS Console Signin via CloudTrailなど6種類が挙がっています。これらを受けるには、ログ記録が有効な証跡が必要というのが、明記された前提条件です。イベントはデフォルトバスにだけ届き、カスタムバスで処理したいときはデフォルトバスのルールから転送します。
拾える範囲はルールの状態で変わります。作成・変更・削除といった変更系の管理イベントは、通常のENABLEDで拾える対象です。Describe・Get・Listなどの読み取り系は、ルールの状態をENABLED_WITH_ALL_CLOUDTRAIL_MANAGEMENT_EVENTSにしたときだけ一致します。S3のオブジェクト操作などのデータイベントは、証跡側でそのイベントを記録する設定が先に要ります。
イベントのsourceはaws.cloudtrailではなく、呼ばれたサービス側の値(EC2ならaws.ec2)になる点にも注意します。証跡の設計と料金はCloudTrailとは?証跡設計と料金実額で扱っています。
GuardDutyの検出結果を重大度7以上に絞りSNSメールへ届ける実装手順
ここからは東京リージョン(ap-northeast-1)で、High以上の検出結果をメールで受け取る構成をCLIで組みます。アカウントIDやトピック名は例です。
SNSトピックの作成とevents.amazonaws.comに発行を許すポリシーの付与
まずトピックを作り、メールの購読を登録します。EventBridgeからSNSへの発行は、IAMロールではなくトピックのリソースポリシーで許可するのが基本です。EventBridgeのリソースベースポリシーのページにある文を、既存のポリシーに足します。
aws sns create-topic --name security-alerts-mail
aws sns subscribe --topic-arn arn:aws:sns:ap-northeast-1:123456789012:security-alerts-mail \
--protocol email --notification-endpoint [email protected]
# 既定のポリシーを取得し、Statement 配列に次の文を足して set-topic-attributes で戻す
aws sns get-topic-attributes --topic-arn arn:aws:sns:ap-northeast-1:123456789012:security-alerts-mail
{
"Sid": "PublishEventsToMyTopic",
"Effect": "Allow",
"Principal": { "Service": "events.amazonaws.com" },
"Action": "sns:Publish",
"Resource": "arn:aws:sns:ap-northeast-1:123456789012:security-alerts-mail"
}
CLIやIaCで組むときにこの文を付け忘れると、ルールは一致しているのにメールが届かない状態になります。トピックと購読の考え方はAmazon SNSとは|Pub/Sub通知の仕組みにまとめています。
numeric演算子で重大度7以上だけを拾うイベントパターンとput-rule
公式の例は、重大度4以上を4、4.0、4.1…と0.1刻みで70個近く列挙しています。同じ絞り込みは比較演算子のnumericで1行に書けます。
{
"source": ["aws.guardduty"],
"detail-type": ["GuardDuty Finding"],
"detail": {
"severity": [{ "numeric": [">=", 7] }]
}
}
aws events put-rule --name guardduty-high-to-mail \
--event-pattern file://guardduty-pattern.json
列挙方式は書き漏れに気づきにくく、閾値を変えるたびに配列を書き直すことになります。数値比較なら[">=", 4, "<", 7]のように範囲で書けるため、Medium だけを別のトピックへ送るルールも同じ形で作ることが可能です。演算子の一覧とtest-event-patternでの確かめ方はEventBridge イベントパターンの書き方に譲ります。
入力トランスフォーマーで検出タイプと重大度を通知文に整形して登録
そのまま流すと、メールにはイベントのJSONが丸ごと届きます。公式は、テンプレートをmessageなどのキーで包んだ1行のJSONにし、改行は\nで書くよう注意しています。複数行のテンプレートや裸の文字列にすると、差し込んだ値で無効なJSONになり、配信に失敗することがあるためです。
[
{
"Id": "guardduty-mail",
"Arn": "arn:aws:sns:ap-northeast-1:123456789012:security-alerts-mail",
"InputTransformer": {
"InputPathsMap": {
"severity": "$.detail.severity",
"findingType": "$.detail.type",
"title": "$.detail.title",
"account": "$.detail.accountId",
"region": "$.region",
"findingId": "$.detail.id"
},
"InputTemplate": "{\"message\": \"[GuardDuty] 重大度 <severity> <findingType>\\nアカウント: <account> (<region>)\\n概要: <title>\\nhttps://console.aws.amazon.com/guardduty/home?region=<region>#/findings?search=id%3D<findingId>\"}"
}
}
]
aws events put-targets --rule guardduty-high-to-mail --targets file://guardduty-targets.json
応答のFailedEntryCountが0なら登録できています。descriptionは検出タイプによって長く、引用符を含むこともあるため、メールの本文には載せずtitleとコンソールへのURLに留めるのが安全です。引用符や予約変数の規則はEventBridge 入力トランスフォーマーの使い方で詳しく扱っています。
create-sample-findingsでサンプル検出を発生させ通知を確かめる
本物の脅威を待たずに試すには、サンプル検出結果を使います。公式は、EventBridgeのイベントやフィルタの試験に使えると案内しています。コンソールの「設定」から全タイプを一括で作れますが、通知の試験には1タイプだけ作るCLIのほうが受信箱を荒らしません。
aws guardduty create-sample-findings --detector-id "$DETECTOR_ID" \
--finding-types "<検出タイプ>"
サンプルのtitleは先頭が[SAMPLE]になり、検出結果のJSONのadditionalInfoに"sample": trueが入ります。選んだタイプの重大度が閾値未満だとルールに一致しないため、公式の検出タイプ一覧で既定の重大度がHighのタイプを選んで指定します。同じタイプでも状況で重大度が変わるものがある点に注意してください。届かないときは、ルールのメトリクスとDLQから原因を絞る手順をEventBridge ログの調べ方にまとめています。
CloudTrailのAPI呼び出しを検知するルールと東京で拾えないIAM操作
GuardDutyは「怪しい兆候」を挙げるサービスで、自社で決めた禁止操作をそのまま知らせる役には向きません。証跡の停止やセキュリティグループの変更など、起きたら必ず知りたい操作はCloudTrailのイベントで直接拾います。
StopLoggingやセキュリティグループ変更を拾うイベントパターン例
証跡を止める・消す操作と、セキュリティグループの受信ルール追加を1つのルールで拾う例です。sourceには呼ばれたサービスの値を並べます。
{
"source": ["aws.cloudtrail", "aws.ec2"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["cloudtrail.amazonaws.com", "ec2.amazonaws.com"],
"eventName": ["StopLogging", "DeleteTrail", "UpdateTrail", "AuthorizeSecurityGroupIngress"]
}
}
通知文にはdetail.eventName、detail.userIdentity.arn、detail.sourceIPAddress、detail.awsRegionを差し込めば、誰がどこから何をしたかが1行で読めます。0.0.0.0/0を開けた場合だけに絞りたいときは、detail.requestParametersの下の構造に条件を足す形です。ただし入れ子の形はAPIごとに違うため、CloudTrailのイベント履歴で実際のイベントのJSONを開き、パスを確かめてから書きます。
IAMとSTSの操作はus-east-1で記録されるためルールを置き分ける
東京リージョンに置いたルールでCreateAccessKeyを拾おうとしても一致しません。CloudTrailの概念ページによると、2021年11月22日以降、CloudFront・IAM・STSのイベントはus-east-1で記録されます。IAMの変更を見張るルールはus-east-1に作ります。
{
"source": ["aws.iam"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["iam.amazonaws.com"],
"eventName": ["CreateUser", "CreateAccessKey", "AttachUserPolicy", "PutUserPolicy"]
}
}
aws events put-rule --region us-east-1 --name iam-change-alert \
--event-pattern file://iam-pattern.json
コンソールのサインインはさらに散らばります。サインインイベントのページでは、ルートユーザーのConsoleLoginはus-east-1・us-east-2・us-west-2のいずれかに記録されるという説明です。IAMユーザーはグローバルエンドポイントかどうかとブラウザのCookieで、記録先がus-east-2・eu-north-1・ap-southeast-2に変わる場合もあります。ルートのサインインを確実に拾うなら、この3リージョンすべてにルールが要ります。
各リージョンのルールから東京のバスへ集めて通知を1か所で組む方法と、そのときのリソースポリシーはEventBridge イベントバスの使い分けで扱っています。
読み取り系APIの検知はルールの状態をCLIで切り替えて件数を絞る
「本番アカウントでListBucketsが呼ばれたら知りたい」といった読み取り系の検知は、ルールの状態を変えないと動きません。読み取り系管理イベントのページによると、この状態はAWS CLIとCloudFormationでしか設定できません。
aws events put-rule --name read-api-watch --event-bus-name default \
--state ENABLED_WITH_ALL_CLOUDTRAIL_MANAGEMENT_EVENTS \
--event-pattern file://read-pattern.json
公式は、KMSのGetKeyPolicyやDescribeKey、IAMのGetPolicyやGetRoleが変更系よりはるかに多く発生すると注意しています。eventNameを絞らずにこの状態にすると、通知が読めない量になります。別のバスへ転送する場合は、デフォルトバスの転送ルールと転送先のルールの両方をこの状態にしないと一致しません。
Slackへ届ける経路とマルチアカウント・全リージョンを集約する構成
複数アカウントを運用しているなら、どのアカウントのルールで受けるかも決めます。
Amazon Q Developerには未変換のSNSトピックを対応づけて投稿する
AWS ChatbotはAmazon Q Developer in chat applicationsに改称されています。連携サービスのページによると、Q DeveloperはGuardDutyやSecurity Hubを含む大半のAWSサービスのイベントを処理でき、EventBridgeのルールのターゲットにしたSNSトピックをSlackのチャンネルに対応づけて使います。
設計で決めておきたいのは、トピックを分けることです。メール用にmessageへ包んだ文面は、もうAWSサービスのイベントの形をしていないため、Q Developerの標準の通知としては扱えません。Slack用には変換しないイベントを流す別トピック(例:security-alerts-chat)を作り、同じルールに2つ目のターゲットとして足します。入力トランスフォーマーはターゲットごとの設定なので、1本のルールでメール用は変換あり、Slack用は変換なしにすることが可能です。文面を自分で決めたいときは、Q Developerのカスタム通知のスキーマへ変換します。
委任管理者アカウントのルール1本でメンバーの検出結果を受ける構成
AWS OrganizationsでGuardDutyの委任管理者を置いている場合、管理者アカウントのルールはメンバーアカウントの検出結果でも発火します。各メンバーにルールとトピックを配る必要はありません。特定のメンバーだけを別の宛先へ送るなら、パターンに"accountId": ["123456789012"]を足します。
再発通知の頻度は管理者の設定がメンバーにも適用され、メンバー側では変えられません。GuardDutyの検出器はリージョンごとにあるため、有効化しているリージョンの数だけルールが要る点は変わりません。リージョンをまたいで1か所へ集める場合、別アカウントのバスへの配信は料金ページの例で100万件あたり1.00ドル、リージョン間はデータ転送料も別にかかります。
Security Hub経由で集約したときに変わるdetail-typeと判別の注意
AWS Security Hubを有効にしていると、GuardDutyの検出結果はSecurity Hubにも取り込まれます。Security HubのEventBridge連携では、新しい検出結果と既存の検出結果の更新のたびにSecurity Hub Findings - Importedが送られ、集約リージョンには連携先リージョンの分も届きます。
1本のルールで全体を受けられる反面、detail-typeが変わるためGuardDuty用のパターンは使えず、更新のたびに通知が飛びます。Security Hubを運用中ならこちらに寄せ、使っていないならGuardDutyのイベントを直接受ける構成で十分です。
GuardDutyの通知で止める範囲と自動隔離・調査ツールへ進む判断の基準
通知を組んだ後に迷うのは、どこまで自動化するかです。結論から言うと、最初は通知だけで始め、自動化は対処の決まった検出タイプに限ります。
High以上だけ即時通知しMediumは日次確認に回す閾値の決め方
即時に通知するのはHigh(7.0以上)とCriticalに限ります。公式の説明でHighは「リソースが侵害され不正に使われている」状態を示し、すぐに対応が必要な段階です。Medium(4.0〜6.9)は「通常と異なる不審な動き」で、承認済みの作業による誤検出も混ざるため、Slackのチャンネルを分けるか、日次でコンソールを確認する運用で足ります。Lowはポートスキャンなどの未遂が中心で、通知は不要です。
Mediumまで同じチャンネルに流すと、本当に動くべきHighが埋もれます。最初の2週間はHigh以上だけを通知し、Mediumの件数をコンソールで数えてから扱いを決める方針です。検出結果の前後関係を追う段階になったら、Amazon Detectiveで調査する流れを用意します。
Lambdaで自動隔離まで組む場面と誤検出で本番を止める失敗
Lambdaで自動対処まで組んでよいのは、検出タイプと対処が1対1で決まり、誤って実行しても業務が止まらない場合です。開発環境のインスタンスを隔離用のセキュリティグループへ移す処理などが、この条件に収まります。
本番のインスタンス停止やアクセスキーの無効化を、重大度だけを条件に自動で実行するのは見送ります。正規のバッチや監視ツールの通信が検出されることがあり、誤検出で本番を止めれば、攻撃より大きな障害を自分で起こす結果になりかねません。自動化するなら、検出タイプとリソースのタグで対象を絞り、まずは「隔離してよいか」をSlackで人が承認する形から始めます。GuardDutyの通知を含む監視基盤の設計や見直しは、インフラ構築(AWS・Google Cloud・Azure)でご相談いただけます。
よくある質問
GuardDutyやCloudTrailの通知をEventBridgeで組むときによく出る疑問に、公式ドキュメントの記載をもとに答えます。
GuardDutyの通知にEventBridgeの料金はかかりますか?
同じアカウント内で通知する限り、EventBridge側の料金はほぼかかりません。料金ページでは、AWSの管理イベントの取り込みは無料で、同じアカウントのサービスへの配信は100万件あたり0ドルの例が示されています。かかるのはSNSの配信やLambdaの実行など送り先のサービスの料金と、GuardDuty自体の料金です。GuardDutyの請求の内訳はAmazon GuardDutyの料金で整理しています。別アカウントのバスへ送る場合は100万件あたり1.00ドルがかかります。
CloudTrailのイベント履歴だけでEventBridgeに届きますか?
公式のCloudTrail連携ページは、CloudTrailのdetail-typeのイベントを受けるにはログ記録が有効な証跡が必要と書いています。コンソールの「イベント履歴」で90日分を見られることと、ルールに届くことは別です。StopLoggingを検知するルールを置いておけば、通知が止まる事態にも気づけます。
通知が届かないときはどこから確認すればよいですか?
まずルールを置いたリージョンが、イベントの記録されるリージョンと一致しているかを見ます。IAMやサインインのイベントを東京のルールで待っているのは、よくある原因です。次に、ルールのMatchedEventsとFailedInvocationsのメトリクスで、一致しているのに配信で失敗しているのかを分けます。配信で失敗しているなら、SNSトピックのポリシーにevents.amazonaws.comの許可があるかが確認対象です。GuardDutyの場合は、抑制ルールで自動アーカイブされた検出結果は送られない点も疑います。
AWS User NotificationsとEventBridgeのルールはどちらを使うべきですか?
CloudTrailのドキュメントによると、AWS User Notificationsはメール・チャット・モバイルアプリへ通知でき、通知の集約にも対応しています。少数の通知をコンソール操作だけで受けるならこちらが手早く、文面の整形やLambdaでの自動対処、DLQまで組むならEventBridgeのルールが向いています。
サンプル検出結果を本番の通知から除外できますか?
サンプルも本物と同じGuardDuty Findingとして送られ、ルールに一致すれば通知されます。除外の設定を足すより、試験はCLIで1タイプだけ作り、終わったらその検出結果をアーカイブする運用が手軽です。[SAMPLE]で始まる通知は試験によるものだと、受け取る側に周知しておきます。
関連記事
- Amazon EventBridgeとは?仕組み・料金とCLI・Pythonでの実装手順、新Custom Event Busとの違いを解説【2026年版】:バス・ルール・ターゲットの全体像と最小構成。
- Amazon GuardDutyの料金:東京リージョンの実額とMalware Protectionの追加課金を検証:通知の元になるGuardDutyの保護プランと請求の内訳。
- CloudTrailとは?証跡設計と料金実額・Lake新規受付終了後の構成をCLIで解説:API呼び出しの通知の前提になる証跡の作り方。
- EventBridge 入力トランスフォーマーの使い方:InputTemplateでSNS・Slack通知を整形する:通知文の整形と引用符の規則。
- AWS Security Hubとは?CSPMとの違い・料金と有効化手順を実装者目線で解説:検出結果を複数サービス・複数アカウントで集約する次の段階。