🐬

【Bedrock×GuardDuty】脅威検出結果から日本語訳+対応方法をメール通知

2024/11/21に公開

概要

以下のGuardDuty検出結果タイプのドキュメントをもとに、AWS GuardDutyの脅威検出結果(英語)をBedrock(RAG)で、日本語訳 + 対応方法をメール通知します

https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-ec2.html

※本記事で紹介する ドキュメントとチャット(Chat with your document) は、Embeddingをしない? ため精度が低いようですが、使用方法は他のRAGと同じで、コストが小さいため、使用しています

背景

  • AWS GuardDutyの脅威検出結果が英語である
  • 対応方法が記載されていない

コンソール画面では、情報 をクリックすると、右側に日本語訳および対応方法が表示されますが、メール通知ではその情報がありません

余談

https://aws.amazon.com/jp/builders-flash/202409/dify-bedrock-automate-security-operation/

AWS公式サイトで、Difyを使用した例も公開されているため、参考になさってください
ただし、EC2等のリソースはコストがかかることに注意してください

本ブログでは、マネージドサービスのみを使用するため、コストが小さい ことがメリットです!!

Health Eventの場合の実装例は、以下をご覧ください

https://zenn.dev/metalmental/articles/20241117_aws-bedrock-stepfunctions

前提

  • オレゴンリージョンであること
  • Bedrockでモデルアクセスが有効になっていること
    ※Claude 3 Sonnetを利用します

構築

GuardDuty

GuardDutyを有効化します



SNS

トピックを スタンダード で作成します

サブスクリプションを作成します

任意の宛先メールアドレスを入力してください

宛先メールアドレスにサブスクリプション確認用のメールが届くため、リンクを右クリックしてコピーします

サブスクリプションの確認 をクリックします

コピーしたURLを入力し、サブスクリプションの確認 をクリックします

サブスクリプションが 確認済み になりました

S3

GuardDutyの対応方法が記載されたドキュメントをS3 Bucketにアップロードします

https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/knowledge-base-chatdoc.html

以下のGuardDutyの対応方法(EC2)が記載されたドキュメントをPDFでダウンロードします
※正確性を重視して、英語のドキュメントをダウンロードします

https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-ec2.html

上記サイトにて、右クリック した後、印刷 をクリックします
PDF をクリックしてもダウンロードできますが、全対応方法が記載されていてファイルサイズが大きいため、PDFファイルの内容をEC2のみに分割する必要があります

PDFファイルを圧縮して小さくします
※以下のサイトを利用してPDFファイルを圧縮します

https://www.ilovepdf.com/ja/compress_pdf




S3 Bucketを作成し、圧縮したPDFファイルをアップロードします





S3 URI をコピーしておきます

ドキュメントとチャット(Chat with your document) の動作確認

Bedrock に移動し、ナレッジベース から、ドキュメントとチャット(Chat with your document) を選択します
モデル を選択し、最大長4096 にします

チャットプロンプトのテンプレート を編集します

以下のプロンプトテンプレートを入力します

あなたはAWS GuardDutyの脅威検出結果を分析するエージェントです。
AWS GuardDutyの脅威検出結果を提供するので、対応方法の番号付きリストを使用して、脅威検出結果についての対応方法が分かるように、日本語に翻訳したうえで、原因と対応方法を簡潔に回答してください。

以下は対応方法の番号付きリストです:
$search_results$

以下がAWS GuardDutyの脅威検出結果です:
$output_format_instructions$

$search_results$ には、S3 BucketにアップロードしたPDFファイルの内容と、ユーザのプロンプト内容をもとに、検索結果が入ります
$output_format_instructions$ には、ユーザのプロンプト内容が入ります

S3 の URI を入力した後、以下のプロンプトを入力して実行します
※プロンプトテンプレート修正後に、最大長4096 になっていることを確認してください

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 TCP protocol.

上記画像のように、原因と対応方法が日本語で回答されていれば、動作確認は完了です

※補足
対応するドキュメントがなく、検索できなかった場合は、以下のように回答されました

Sorry, I am unable to assist you with this request.

Step Functions

Sample Event

GuardDutyのEvent例
{
    "version": "0",
    "id": "70a2eca2-a15c-3d73-ce50-fe831aecbeae",
    "detail-type": "GuardDuty Finding",
    "source": "aws.guardduty",
    "account": "247574246160",
    "time": "2024-11-19T18:15:08Z",
    "region": "us-west-2",
    "resources": [],
    "detail": {
        "schemaVersion": "2.0",
        "accountId": "247574246160",
        "region": "us-west-2",
        "partition": "aws",
        "id": "9b2373d85dcf4e429cce481fa2d8a84b",
        "arn": "arn:aws:guardduty:us-west-2:247574246160:detector/eac9a2b82f6b4aa20600211ff0790627/finding/9b2373d85dcf4e429cce481fa2d8a84b",
        "type": "Backdoor:EC2/DenialOfService.Tcp",
        "resource": {
            "resourceType": "Instance",
            "instanceDetails": {
                "instanceId": "i-99999999",
                "instanceType": "m3.xlarge",
                "outpostArn": "arn:aws:outposts:us-west-2:123456789000:outpost/op-0fbc006e9abbc73c3",
                "launchTime": "2016-08-02T02:05:06.000Z",
                "platform": null,
                "productCodes": [
                    {
                        "productCodeId": "GeneratedFindingProductCodeId1",
                        "productCodeType": "GeneratedFindingProductCodeType1"
                    },
                    {
                        "productCodeId": "GeneratedFindingProductCodeId2",
                        "productCodeType": "GeneratedFindingProductCodeType2"
                    },
                    {
                        "productCodeId": "GeneratedFindingProductCodeId3",
                        "productCodeType": "GeneratedFindingProductCodeType3"
                    },
                    {
                        "productCodeId": "GeneratedFindingProductCodeId4",
                        "productCodeType": "GeneratedFindingProductCodeType4"
                    },
                    {
                        "productCodeId": "GeneratedFindingProductCodeId5",
                        "productCodeType": "GeneratedFindingProductCodeType5"
                    }
                ],
                "iamInstanceProfile": {
                    "arn": "arn:aws:iam::247574246160:example/instance/profile",
                    "id": "GeneratedFindingInstanceProfileId"
                },
                "networkInterfaces": [
                    {
                        "ipv6Addresses": [],
                        "networkInterfaceId": "eni-abcdef00",
                        "privateDnsName": "GeneratedFindingPrivateDnsName1",
                        "privateIpAddress": "10.0.0.1",
                        "privateIpAddresses": [
                            {
                                "privateDnsName": "GeneratedFindingPrivateName1",
                                "privateIpAddress": "10.0.0.1"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName2",
                                "privateIpAddress": "10.0.0.2"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName3",
                                "privateIpAddress": "10.0.0.3"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName4",
                                "privateIpAddress": "10.0.0.4"
                            }
                        ],
                        "subnetId": "GeneratedFindingSubnetId1",
                        "vpcId": "vpc-generatedvpcid1",
                        "securityGroups": [
                            {
                                "groupName": "GeneratedFindingSecurityGroupName1",
                                "groupId": "GeneratedFindingSecurityId1"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName2",
                                "groupId": "GeneratedFindingSecurityId2"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName3",
                                "groupId": "GeneratedFindingSecurityId3"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName4",
                                "groupId": "GeneratedFindingSecurityId4"
                            }
                        ],
                        "publicDnsName": "GeneratedFindingPublicDNSName1",
                        "publicIp": "198.51.100.1"
                    },
                    {
                        "ipv6Addresses": [],
                        "networkInterfaceId": "eni-abcdef01",
                        "privateDnsName": "GeneratedFindingPrivateDnsName2",
                        "privateIpAddress": "10.0.0.2",
                        "privateIpAddresses": [
                            {
                                "privateDnsName": "GeneratedFindingPrivateName1",
                                "privateIpAddress": "10.0.0.1"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName2",
                                "privateIpAddress": "10.0.0.2"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName3",
                                "privateIpAddress": "10.0.0.3"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName4",
                                "privateIpAddress": "10.0.0.4"
                            }
                        ],
                        "subnetId": "GeneratedFindingSubnetId2",
                        "vpcId": "vpc-generatedvpcid2",
                        "securityGroups": [
                            {
                                "groupName": "GeneratedFindingSecurityGroupName1",
                                "groupId": "GeneratedFindingSecurityId1"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName2",
                                "groupId": "GeneratedFindingSecurityId2"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName3",
                                "groupId": "GeneratedFindingSecurityId3"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName4",
                                "groupId": "GeneratedFindingSecurityId4"
                            }
                        ],
                        "publicDnsName": "GeneratedFindingPublicDNSName2",
                        "publicIp": "198.51.100.2"
                    },
                    {
                        "ipv6Addresses": [],
                        "networkInterfaceId": "eni-abcdef02",
                        "privateDnsName": "GeneratedFindingPrivateDnsName3",
                        "privateIpAddress": "10.0.0.3",
                        "privateIpAddresses": [
                            {
                                "privateDnsName": "GeneratedFindingPrivateName1",
                                "privateIpAddress": "10.0.0.1"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName2",
                                "privateIpAddress": "10.0.0.2"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName3",
                                "privateIpAddress": "10.0.0.3"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName4",
                                "privateIpAddress": "10.0.0.4"
                            }
                        ],
                        "subnetId": "GeneratedFindingSubnetId3",
                        "vpcId": "vpc-generatedvpcid3",
                        "securityGroups": [
                            {
                                "groupName": "GeneratedFindingSecurityGroupName1",
                                "groupId": "GeneratedFindingSecurityId1"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName2",
                                "groupId": "GeneratedFindingSecurityId2"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName3",
                                "groupId": "GeneratedFindingSecurityId3"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName4",
                                "groupId": "GeneratedFindingSecurityId4"
                            }
                        ],
                        "publicDnsName": "GeneratedFindingPublicDNSName3",
                        "publicIp": "198.51.100.3"
                    },
                    {
                        "ipv6Addresses": [],
                        "networkInterfaceId": "eni-abcdef03",
                        "privateDnsName": "GeneratedFindingPrivateDnsName4",
                        "privateIpAddress": "10.0.0.4",
                        "privateIpAddresses": [
                            {
                                "privateDnsName": "GeneratedFindingPrivateName1",
                                "privateIpAddress": "10.0.0.1"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName2",
                                "privateIpAddress": "10.0.0.2"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName3",
                                "privateIpAddress": "10.0.0.3"
                            },
                            {
                                "privateDnsName": "GeneratedFindingPrivateName4",
                                "privateIpAddress": "10.0.0.4"
                            }
                        ],
                        "subnetId": "GeneratedFindingSubnetId4",
                        "vpcId": "vpc-generatedvpcid4",
                        "securityGroups": [
                            {
                                "groupName": "GeneratedFindingSecurityGroupName1",
                                "groupId": "GeneratedFindingSecurityId1"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName2",
                                "groupId": "GeneratedFindingSecurityId2"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName3",
                                "groupId": "GeneratedFindingSecurityId3"
                            },
                            {
                                "groupName": "GeneratedFindingSecurityGroupName4",
                                "groupId": "GeneratedFindingSecurityId4"
                            }
                        ],
                        "publicDnsName": "GeneratedFindingPublicDNSName4",
                        "publicIp": "198.51.100.4"
                    }
                ],
                "tags": [
                    {
                        "key": "GeneratedFindingInstanceTag1",
                        "value": "GeneratedFindingInstanceValue1"
                    },
                    {
                        "key": "GeneratedFindingInstanceTag2",
                        "value": "GeneratedFindingInstanceTagValue2"
                    },
                    {
                        "key": "GeneratedFindingInstanceTag3",
                        "value": "GeneratedFindingInstanceTagValue3"
                    },
                    {
                        "key": "GeneratedFindingInstanceTag4",
                        "value": "GeneratedFindingInstanceTagValue4"
                    },
                    {
                        "key": "GeneratedFindingInstanceTag5",
                        "value": "GeneratedFindingInstanceTagValue5"
                    },
                    {
                        "key": "GeneratedFindingInstanceTag6",
                        "value": "GeneratedFindingInstanceTagValue6"
                    },
                    {
                        "key": "GeneratedFindingInstanceTag7",
                        "value": "GeneratedFindingInstanceTagValue7"
                    },
                    {
                        "key": "GeneratedFindingInstanceTag8",
                        "value": "GeneratedFindingInstanceTagValue8"
                    },
                    {
                        "key": "GeneratedFindingInstanceTag9",
                        "value": "GeneratedFindingInstanceTagValue9"
                    }
                ],
                "instanceState": "running",
                "availabilityZone": "generated-az-1a",
                "imageId": "ami-99999999",
                "imageDescription": "GeneratedFindingInstanceImageDescription"
            }
        },
        "service": {
            "serviceName": "guardduty",
            "detectorId": "eac9a2b82f6b4aa20600211ff0790627",
            "action": {
                "actionType": "NETWORK_CONNECTION",
                "networkConnectionAction": {
                    "connectionDirection": "OUTBOUND",
                    "localIpDetails": {
                        "ipAddressV4": "10.0.0.23",
                        "ipAddressV6": "1234:5678:90ab:cdef:1234:5678:90ab:cde1"
                    },
                    "remoteIpDetails": {
                        "ipAddressV4": "198.51.100.0",
                        "organization": {
                            "asn": "-1",
                            "asnOrg": "GeneratedFindingASNOrg",
                            "isp": "GeneratedFindingISP",
                            "org": "GeneratedFindingORG"
                        },
                        "country": {
                            "countryName": "GeneratedFindingCountryName"
                        },
                        "city": {
                            "cityName": "GeneratedFindingCityName"
                        },
                        "geoLocation": {
                            "lat": 0,
                            "lon": 0
                        },
                        "ipAddressV6": "1234:5678:90ab:cdef:1234:5678:90ab:cde0"
                    },
                    "remotePortDetails": {
                        "port": 80,
                        "portName": "HTTP"
                    },
                    "localPortDetails": {
                        "port": 24198,
                        "portName": "Unknown"
                    },
                    "localNetworkInterface": "eni-abcdef00",
                    "protocol": "TCP",
                    "blocked": false
                }
            },
            "resourceRole": "ACTOR",
            "additionalInfo": {
                "sample": true,
                "value": "{\"sample\":true}",
                "type": "default"
            },
            "eventFirstSeen": "2024-11-19T18:12:05.000Z",
            "eventLastSeen": "2024-11-19T18:13:42.000Z",
            "archived": false,
            "count": 2
        },
        "severity": 8,
        "createdAt": "2024-11-19T18:12:05.011Z",
        "updatedAt": "2024-11-19T18:13:42.246Z",
        "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 TCP protocol.",
        "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 TCP protocol."
    }
}

上記、GuardDutyのEvent例をもとに、Bedrockのドキュメントとチャット(Chat with your document)を実行するStep Functionsを作成します

{
    "Comment": "Translate GuardDuty threat detection findings into Japanese, provide remediation steps, and send them via email notifications.",
    "StartAt": "RetrieveAndGenerate",
    "States": {
        "RetrieveAndGenerate": {
            "Type": "Task",
            "Parameters": {
                "Input": {
                    "Text.$": "States.Format('あなたはAWS GuardDutyの脅威検出結果を分析するエージェントです。\nAWS GuardDutyの脅威検出結果を提供するので、対応方法の番号付きリストを使用して、脅威検出結果についての対応方法が分かるように、日本語に翻訳したうえで、原因と対応方法を簡潔に回答してください。\n\n以下がAWS GuardDutyの脅威検出結果です:\n{}', $.detail.description)"
                },
                "RetrieveAndGenerateConfiguration": {
                    "Type": "EXTERNAL_SOURCES",
                    "ExternalSourcesConfiguration": {
                        "ModelArn": "arn:aws:bedrock:us-west-2::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0",
                        "Sources": [
                            {
                                "SourceType": "S3",
                                "S3Location": {
                                    "Uri": "S3のURI"
                                }
                            }
                        ]
                    }
                }
            },
            "Resource": "arn:aws:states:::aws-sdk:bedrockagentruntime:retrieveAndGenerate",
            "ResultPath": "$.result",
            "ResultSelector": {
                "translate.$": "$.Output.Text"
            },
            "Retry": [
                {
                    "ErrorEquals": [
                        "States.ALL"
                    ],
                    "BackoffRate": 2,
                    "IntervalSeconds": 5,
                    "MaxAttempts": 5
                }
            ],
            "Next": "Send Email"
        },
        "Send Email": {
            "Type": "Task",
            "Resource": "arn:aws:states:::aws-sdk:sns:publish",
            "Parameters": {
                "Subject.$": "$.['detail-type']",
                "Message.$": "States.Format('日本語:\n{}\n\n\naccount: {}\ntype: {}\ntime: {}\nregion: {}\nresources: {}\nseverity: {}\n英語:\n{}', $.result.translate, $.account, $.detail.type, $.time, $.region, $.resources, $.detail.severity, $.detail.description)",
                "TopicArn": "SNSのトピックARN"
            },
            "End": true
        }
    }
}

コード を選択して、上記コードをコピペし、SNSのトピックARNS3のURI を修正します


設定 を選択して、ステートマシン名 を入力して作成します

自動で作成されるIAMロールの権限が足りないため、AmazonBedrockFullAccessAmazonS3FullAccess のIAMポリシーを追加します




Step Functionsのテスト

Step Functionsの動作確認を行います
デザイン から RetrieveAndGenerateのフロー を選択して、テスト状態 を選択します

状態の入力 に、前述したGuardDutyのEvent例を入力し、テストを開始 を選択します
成功し、日本語の結果が出力されていればOKです

EventBridge

トリガーとしてEventBridgeのルールを作成します

イベントパターン に以下を入力します

{
  "source": ["aws.guardduty"],
  "detail-type": ["GuardDuty Finding"],
  "detail": {
    "severity": [{
      "numeric": [">=", 7]
    }]
  }
}



テスト

CloudShell で、以下のコマンドを実行して、サンプルのGuardDutyの脅威検出結果を作成します

aws guardduty create-sample-findings --detector-id $(aws guardduty list-detectors --query 'DetectorIds' --output text) --finding-types Backdoor:EC2/DenialOfService.Tcp



※脅威検出結果がEventBridgeに流れて、メール送信されるまで最大5分程度かかります

東京リージョンで実装する場合

以下3つが考えられると思います

  • OpenSearch ServerlessやAuroraでベクトルデータベースを作成する
  • 東京リージョンのEventBridgeからオレゴンリージョンのEventBridgeにEventを転送する
  • 東京リージョンのEventBridge -> Lambda -> オレゴンリージョンのStep Functionsを実行 という流れにする

※EventBridgeのリージョン間転送については以下の記事が参考になります

https://dev.classmethod.jp/articles/eventbridge-cross-region-expands/

最後に

今後は、生成AIの画像読み取り機能も活用していきたいと感じました
先日紹介したPython Jinjaのようなテンプレートエンジンと組み合わせると、より便利になるのではないかと思いました

https://zenn.dev/metalmental/articles/20241103_jinja-cloudformation

GitHubで編集を提案

Discussion