GuardDuty の検出結果を Security Hub および EventBridge 経由で通知する構成を AWS CDK で実装する
こんにちは、製造ビジネステクノロジー部の若槻です。
AWS の脅威検出サービスである Amazon GuardDuty は、Security Hub と統合することで、GuardDuty の検出結果を Security Hub に送信することが可能です。
今回は、GuardDuty と Security Hub を統合し、さらに GuardDuty の検出結果を EventBridge を利用して通知する構成を AWS CDK で実装してみました。
CDK コード
GuardDuty および Security Hub を有効化し、EventBridge ルールを作成する AWS CDK のコード実装は以下の通りです。
import * as securityhub from "aws-cdk-lib/aws-securityhub";
import * as events from "aws-cdk-lib/aws-events";
import * as guardDuty from "aws-cdk-lib/aws-guardduty";
import { Construct } from "constructs";
export class NotificationConstruct extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
// GuardDuty を有効化
new guardDuty.CfnDetector(this, "Default", {
enable: true,
});
// Security Hub を有効化
new securityhub.CfnHub(this, "SecurityHub", {
enableDefaultStandards: false,
});
// Security Hub 検出結果イベントを対象とした EventBridge ルールを作成
new events.Rule(this, "EventRule", {
eventPattern: {
source: ["aws.securityhub"],
detailType: ["Security Hub Findings - Imported"],
//
detail: {
findings: {
// ProductName: ["GuardDuty"], // GuardDuty の検出結果をフィルタリングする場合はプロダクト名を指定
Severity: {
Label: ["MEDIUM", "CRITICAL", "HIGH"], // MEDIUM 未満の重要度のイベントを除外
},
Workflow: {
Status: ["NEW", "NOTIFIED", "RESOLVED"], // SUPPRESSED 状態を除外
},
},
},
},
});
}
}
上記コードを見てもらうとわかる通り、GuardDuty と Security Hub の統合を明示的に設定しているわけではありません。
しかしデプロイを行うと自動的に統合が有効化されます。
動作確認
GuardDuty と Security Hub の統合による通知動作を確認してみます。GuardDuty の検出テストは、サンプル検出結果の作成機能が便利です。
今回は下記を参考に AWS CLI でサンプル検出結果を作成してみました。
GuardDuty で低・中・高の重要度のサンプル検出結果を下記コマンドで作成してみます。
DETECTOR_ID=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text)
# 重要度「低」のサンプル検出結果を作成
aws guardduty create-sample-findings \
--detector-id ${DETECTOR_ID} \
--finding-types "Discovery:IAMUser/AnomalousBehavior"
# 重要度「中」のサンプル検出結果を作成
aws guardduty create-sample-findings \
--detector-id ${DETECTOR_ID} \
--finding-types "Backdoor:EC2/Spambot"
# 重要度「高」のサンプル検出結果を作成
aws guardduty create-sample-findings \
--detector-id ${DETECTOR_ID} \
--finding-types "Backdoor:EC2/DenialOfService.Dns"
するとコマンド実行後間も無く、GuardDuty の検出結果一覧にそれぞれの検出結果が作成されました。
さらに少し待つと、Security Hub の検出結果一覧にもそれぞれの検出結果が作成されました。
ちなみにドキュメントにある通り GuardDuty に新しい検出結果が作成されてから Security Hub に送信されるまで最大 5 分掛かります。
そして EventBridge ルールにより、GuardDuty の検出結果が通知先に送信されます。参考までに、送信された検出結果の JSON は下記のようになりました。EventBridhe ルールのフィルターにより重要度「低」の検出結果は除外されています。
検出結果詳細 (MEDIUM)
2025-05-22T12:40:11.262Z ee631507-0346-4bf3-a86d-853ec6005132 INFO {
"version": "0",
"id": "25b75006-95c9-eaef-a6df-edad225ebfd5",
"detail-type": "Security Hub Findings - Imported",
"source": "aws.securityhub",
"account": "XXXXXXXXXXXX",
"time": "2025-05-22T12:40:10Z",
"region": "ap-northeast-1",
"resources": [
"arn:aws:securityhub:ap-northeast-1::product/aws/guardduty/arn:aws:guardduty:ap-northeast-1:XXXXXXXXXXXX:detector/f0cacef1499171af60c0b999321b9514/finding/eb5cee0358bd443f98ccefd9e6daeab0"
],
"detail": {
"findings": [
{
"ProductArn": "arn:aws:securityhub:ap-northeast-1::product/aws/guardduty",
"Types": [
"TTPs/Command and Control/Backdoor:EC2-Spambot",
"Unusual Behaviors/VM/Backdoor:EC2-Spambot"
],
"SourceUrl": "https://ap-northeast-1.console.aws.amazon.com/guardduty/home?region=ap-northeast-1#/findings?macros=current&fId=eb5cee0358bd443f98ccefd9e6daeab0",
"Action": {
"ActionType": "NETWORK_CONNECTION",
"NetworkConnectionAction": {
"LocalPortDetails": {
"Port": 2000,
"PortName": "Unknown"
},
"RemoteIpDetails": {
"IpAddressV4": "198.51.100.0",
"Organization": {
"Org": "GeneratedFindingORG",
"Isp": "GeneratedFindingISP",
"AsnOrg": "GeneratedFindingASNOrg"
},
"Country": {
"CountryName": "GeneratedFindingCountryName"
},
"City": {
"CityName": "GeneratedFindingCityName"
},
"GeoLocation": {
"Lon": 0,
"Lat": 0
}
},
"Protocol": "TCP",
"Blocked": false,
"ConnectionDirection": "OUTBOUND",
"RemotePortDetails": {
"Port": 25,
"PortName": "SMTP"
}
}
},
"Description": "The EC2 instance i-99999999 is communicating on an unusual port 25 with a remote host. This port is commonly used to send email.",
"ProductName": "GuardDuty",
"FirstObservedAt": "2025-05-22T12:38:48.000Z",
"CreatedAt": "2025-05-22T12:38:48.693Z",
"LastObservedAt": "2025-05-22T12:38:48.000Z",
"CompanyName": "Amazon",
"FindingProviderFields": {
"Types": [
"TTPs/Command and Control/Backdoor:EC2-Spambot",
"Unusual Behaviors/VM/Backdoor:EC2-Spambot"
],
"Severity": {
"Normalized": 50,
"Label": "MEDIUM",
"Product": 5
}
},
"ProductFields": {
"aws/guardduty/service/action/networkConnectionAction/remotePortDetails/portName": "SMTP",
"aws/guardduty/service/additionalInfo/threatListName": "GeneratedFindingThreatListName",
"aws/guardduty/service/archived": "false",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/organization/asnOrg": "GeneratedFindingASNOrg",
"aws/guardduty/service/additionalInfo/value": "{\"unusualProtocol\":\"UDP\",\"threatListName\":\"GeneratedFindingThreatListName\",\"sample\":true}",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/geoLocation/lat": "0",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/ipAddressV4": "198.51.100.0",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/ipAddressV6": "1234:5678:90ab:cdef:1234:5678:90ab:cde0",
"aws/guardduty/service/action/networkConnectionAction/localIpDetails/ipAddressV6": "1234:5678:90ab:cdef:1234:5678:90ab:cde1",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/geoLocation/lon": "0",
"aws/guardduty/service/action/networkConnectionAction/remotePortDetails/port": "25",
"aws/guardduty/service/action/networkConnectionAction/blocked": "false",
"aws/guardduty/service/serviceName": "guardduty",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/country/countryName": "GeneratedFindingCountryName",
"aws/guardduty/service/action/networkConnectionAction/localIpDetails/ipAddressV4": "10.0.0.23",
"aws/guardduty/service/additionalInfo/unusualProtocol": "UDP",
"aws/guardduty/service/detectorId": "f0cacef1499171af60c0b999321b9514",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/organization/org": "GeneratedFindingORG",
"aws/guardduty/service/action/networkConnectionAction/connectionDirection": "OUTBOUND",
"aws/guardduty/service/eventFirstSeen": "2025-05-22T12:38:48.000Z",
"aws/guardduty/service/action/networkConnectionAction/localPortDetails/portName": "Unknown",
"aws/guardduty/service/eventLastSeen": "2025-05-22T12:38:48.000Z",
"aws/guardduty/service/action/actionType": "NETWORK_CONNECTION",
"aws/guardduty/service/action/networkConnectionAction/localNetworkInterface": "eni-abcdef00",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/city/cityName": "GeneratedFindingCityName",
"aws/guardduty/service/action/networkConnectionAction/localPortDetails/port": "2000",
"aws/guardduty/service/resourceRole": "TARGET",
"aws/guardduty/service/action/networkConnectionAction/protocol": "TCP",
"aws/guardduty/service/count": "1",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/organization/asn": "-1",
"aws/guardduty/service/additionalInfo/sample": "true",
"aws/guardduty/service/additionalInfo/type": "default",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/organization/isp": "GeneratedFindingISP",
"aws/securityhub/FindingId": "arn:aws:securityhub:ap-northeast-1::product/aws/guardduty/arn:aws:guardduty:ap-northeast-1:XXXXXXXXXXXX:detector/f0cacef1499171af60c0b999321b9514/finding/eb5cee0358bd443f98ccefd9e6daeab0",
"aws/securityhub/ProductName": "GuardDuty",
"aws/securityhub/CompanyName": "Amazon"
},
"SchemaVersion": "2018-10-08",
"GeneratorId": "arn:aws:guardduty:ap-northeast-1:XXXXXXXXXXXX:detector/f0cacef1499171af60c0b999321b9514",
"Sample": true,
"RecordState": "ACTIVE",
"Title": "Unusual outbound communication on port 25 from EC2 instance i-99999999.",
"Workflow": {
"Status": "NEW"
},
"Severity": {
"Normalized": 50,
"Label": "MEDIUM",
"Product": 5
},
"UpdatedAt": "2025-05-22T12:38:48.693Z",
"WorkflowState": "NEW",
"AwsAccountId": "XXXXXXXXXXXX",
"Region": "ap-northeast-1",
"Id": "arn:aws:guardduty:ap-northeast-1:XXXXXXXXXXXX:detector/f0cacef1499171af60c0b999321b9514/finding/eb5cee0358bd443f98ccefd9e6daeab0",
"Resources": [
{
"Partition": "aws",
"Type": "AwsEc2Instance",
"Details": {
"AwsEc2Instance": {
"Type": "m3.xlarge",
"VpcId": "vpc-generatedvpcid1",
"ImageId": "ami-99999999",
"IpV4Addresses": [
"198.51.100.1",
"198.51.100.2",
"198.51.100.3",
"198.51.100.4",
"10.0.0.4",
"10.0.0.3",
"10.0.0.2",
"10.0.0.1"
],
"SubnetId": "GeneratedFindingSubnetId1",
"LaunchedAt": "2016-08-02T02:05:06.000Z",
"IamInstanceProfileArn": "arn:aws:iam::XXXXXXXXXXXX:instance-profile/generated"
}
},
"Region": "ap-northeast-1",
"Id": "arn:aws:ec2:ap-northeast-1:XXXXXXXXXXXX:instance/i-99999999",
"Tags": {
"GeneratedFindingInstanceTag1": "GeneratedFindingInstanceValue1",
"GeneratedFindingInstanceTag2": "GeneratedFindingInstanceTagValue2",
"GeneratedFindingInstanceTag3": "GeneratedFindingInstanceTagValue3",
"GeneratedFindingInstanceTag4": "GeneratedFindingInstanceTagValue4",
"GeneratedFindingInstanceTag5": "GeneratedFindingInstanceTagValue5",
"GeneratedFindingInstanceTag6": "GeneratedFindingInstanceTagValue6",
"GeneratedFindingInstanceTag7": "GeneratedFindingInstanceTagValue7",
"GeneratedFindingInstanceTag8": "GeneratedFindingInstanceTagValue8",
"GeneratedFindingInstanceTag9": "GeneratedFindingInstanceTagValue9"
}
}
],
"ProcessedAt": "2025-05-22T12:40:04.963Z"
}
]
}
}
検出結果詳細 (HIGH)
2025-05-22T12:41:32.326Z 4b280474-ce60-4b6d-9b46-e6172d194ed9 INFO {
"version": "0",
"id": "348a9a14-cc1a-8912-00b6-355629778d4c",
"detail-type": "Security Hub Findings - Imported",
"source": "aws.securityhub",
"account": "XXXXXXXXXXXX",
"time": "2025-05-22T12:40:32Z",
"region": "ap-northeast-1",
"resources": [
"arn:aws:securityhub:ap-northeast-1::product/aws/guardduty/arn:aws:guardduty:ap-northeast-1:XXXXXXXXXXXX:detector/f0cacef1499171af60c0b999321b9514/finding/42d45dd42eba4440b84aa973786b418c"
],
"detail": {
"findings": [
{
"ProductArn": "arn:aws:securityhub:ap-northeast-1::product/aws/guardduty",
"Types": [
"TTPs/Command and Control/Backdoor:EC2-DenialOfService.Dns"
],
"SourceUrl": "https://ap-northeast-1.console.aws.amazon.com/guardduty/home?region=ap-northeast-1#/findings?macros=current&fId=42d45dd42eba4440b84aa973786b418c",
"Action": {
"ActionType": "NETWORK_CONNECTION",
"NetworkConnectionAction": {
"LocalPortDetails": {
"Port": 24198,
"PortName": "Unknown"
},
"RemoteIpDetails": {
"IpAddressV4": "198.51.100.0",
"Organization": {
"Org": "GeneratedFindingORG",
"Isp": "GeneratedFindingISP",
"AsnOrg": "GeneratedFindingASNOrg"
},
"Country": {
"CountryName": "GeneratedFindingCountryName"
},
"City": {
"CityName": "GeneratedFindingCityName"
},
"GeoLocation": {
"Lon": 0,
"Lat": 0
}
},
"Protocol": "UDP",
"Blocked": false,
"ConnectionDirection": "OUTBOUND",
"RemotePortDetails": {
"Port": 53,
"PortName": "DNS"
}
}
},
"Description": "The EC2 instance i-99999999 is behaving in a manner that may indicate it is being used to perform a Denial of Service (DoS) attack using the DNS protocol.",
"ProductName": "GuardDuty",
"FirstObservedAt": "2025-05-22T12:38:53.000Z",
"CreatedAt": "2025-05-22T12:38:53.860Z",
"LastObservedAt": "2025-05-22T12:38:53.000Z",
"CompanyName": "Amazon",
"FindingProviderFields": {
"Types": [
"TTPs/Command and Control/Backdoor:EC2-DenialOfService.Dns"
],
"Severity": {
"Normalized": 75,
"Label": "HIGH",
"Product": 8
}
},
"ProductFields": {
"aws/guardduty/service/action/networkConnectionAction/remotePortDetails/portName": "DNS",
"aws/guardduty/service/archived": "false",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/organization/asnOrg": "GeneratedFindingASNOrg",
"aws/guardduty/service/additionalInfo/value": "{\"sample\":true}",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/geoLocation/lat": "0",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/ipAddressV4": "198.51.100.0",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/ipAddressV6": "1234:5678:90ab:cdef:1234:5678:90ab:cde0",
"aws/guardduty/service/action/networkConnectionAction/localIpDetails/ipAddressV6": "1234:5678:90ab:cdef:1234:5678:90ab:cde1",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/geoLocation/lon": "0",
"aws/guardduty/service/action/networkConnectionAction/remotePortDetails/port": "53",
"aws/guardduty/service/action/networkConnectionAction/blocked": "false",
"aws/guardduty/service/serviceName": "guardduty",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/country/countryName": "GeneratedFindingCountryName",
"aws/guardduty/service/action/networkConnectionAction/localIpDetails/ipAddressV4": "10.0.0.23",
"aws/guardduty/service/detectorId": "f0cacef1499171af60c0b999321b9514",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/organization/org": "GeneratedFindingORG",
"aws/guardduty/service/action/networkConnectionAction/connectionDirection": "OUTBOUND",
"aws/guardduty/service/eventFirstSeen": "2025-05-22T12:38:53.000Z",
"aws/guardduty/service/action/networkConnectionAction/localPortDetails/portName": "Unknown",
"aws/guardduty/service/eventLastSeen": "2025-05-22T12:38:53.000Z",
"aws/guardduty/service/action/actionType": "NETWORK_CONNECTION",
"aws/guardduty/service/action/networkConnectionAction/localNetworkInterface": "eni-abcdef00",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/city/cityName": "GeneratedFindingCityName",
"aws/guardduty/service/action/networkConnectionAction/localPortDetails/port": "24198",
"aws/guardduty/service/resourceRole": "ACTOR",
"aws/guardduty/service/action/networkConnectionAction/protocol": "UDP",
"aws/guardduty/service/count": "1",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/organization/asn": "-1",
"aws/guardduty/service/additionalInfo/sample": "true",
"aws/guardduty/service/additionalInfo/type": "default",
"aws/guardduty/service/action/networkConnectionAction/remoteIpDetails/organization/isp": "GeneratedFindingISP",
"aws/securityhub/FindingId": "arn:aws:securityhub:ap-northeast-1::product/aws/guardduty/arn:aws:guardduty:ap-northeast-1:XXXXXXXXXXXX:detector/f0cacef1499171af60c0b999321b9514/finding/42d45dd42eba4440b84aa973786b418c",
"aws/securityhub/ProductName": "GuardDuty",
"aws/securityhub/CompanyName": "Amazon"
},
"SchemaVersion": "2018-10-08",
"GeneratorId": "arn:aws:guardduty:ap-northeast-1:XXXXXXXXXXXX:detector/f0cacef1499171af60c0b999321b9514",
"Sample": true,
"RecordState": "ACTIVE",
"Title": "The EC2 instance i-99999999 is behaving in a manner that may indicate it is being used to perform a Denial of Service (DoS) attack using the DNS protocol.",
"Workflow": {
"Status": "NEW"
},
"Severity": {
"Normalized": 75,
"Label": "HIGH",
"Product": 8
},
"UpdatedAt": "2025-05-22T12:38:53.860Z",
"WorkflowState": "NEW",
"AwsAccountId": "XXXXXXXXXXXX",
"Region": "ap-northeast-1",
"Id": "arn:aws:guardduty:ap-northeast-1:XXXXXXXXXXXX:detector/f0cacef1499171af60c0b999321b9514/finding/42d45dd42eba4440b84aa973786b418c",
"Resources": [
{
"Partition": "aws",
"Type": "AwsEc2Instance",
"Details": {
"AwsEc2Instance": {
"Type": "m3.xlarge",
"VpcId": "vpc-generatedvpcid1",
"ImageId": "ami-99999999",
"IpV4Addresses": [
"198.51.100.1",
"198.51.100.2",
"198.51.100.3",
"198.51.100.4",
"10.0.0.4",
"10.0.0.3",
"10.0.0.2",
"10.0.0.1"
],
"SubnetId": "GeneratedFindingSubnetId1",
"LaunchedAt": "2016-08-02T02:05:06.000Z",
"IamInstanceProfileArn": "arn:aws:iam::XXXXXXXXXXXX:instance-profile/generated"
}
},
"Region": "ap-northeast-1",
"Id": "arn:aws:ec2:ap-northeast-1:XXXXXXXXXXXX:instance/i-99999999",
"Tags": {
"GeneratedFindingInstanceTag1": "GeneratedFindingInstanceValue1",
"GeneratedFindingInstanceTag2": "GeneratedFindingInstanceTagValue2",
"GeneratedFindingInstanceTag3": "GeneratedFindingInstanceTagValue3",
"GeneratedFindingInstanceTag4": "GeneratedFindingInstanceTagValue4",
"GeneratedFindingInstanceTag5": "GeneratedFindingInstanceTagValue5",
"GeneratedFindingInstanceTag6": "GeneratedFindingInstanceTagValue6",
"GeneratedFindingInstanceTag7": "GeneratedFindingInstanceTagValue7",
"GeneratedFindingInstanceTag8": "GeneratedFindingInstanceTagValue8",
"GeneratedFindingInstanceTag9": "GeneratedFindingInstanceTagValue9"
}
}
],
"ProcessedAt": "2025-05-22T12:40:24.918Z"
}
]
}
}
GuardDuty 検出結果の後片付け
今回作成した GuardDuty のサンプル検出結果により継続して通知が行われないように、忘れずにアーカイブしておきましょう。
ちなみにドキュメントによると、GuardDuty 側で検出結果をアーカイブまたはアーカイブ解除したときに、その検出結果が Security Hub に送信されることは無いとのことです。
よって、対応する検出結果の Security Hub 側での抑制も忘れずに行いましょう。
おわりに
GuardDuty の検出結果を Security Hub および EventBridge 経由で通知する構成 を AWS CDK で実装してみました。
最近「GuardDuty の通知ってどこで設定されてるんだっけ?」となったので、統合設定によりちゃんと行われていることを確認できて良かったです。
ちなみに EventBridge ルールのさらに送信先の通知の仕組みの実装については下記も参考にしてみてください。
以上