GuardDutyの検出結果通知をCloudFormationで設定してみた

2022.10.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

GuardDutyの検出結果をEventBridgeとSNSを利用して通知することが可能ですが、手作業だと結構手順が必要なため一回で終わるようなCloudFormationテンプレートを作ってみました。
手作業の場合は以下のドキュメントを参考にすると設定できます。

作成したテンプレート

以下のリポジトリに入れてあります。

AWSTemplateFormatVersion: "2010-09-09"

Description: GuardDuty Stack

Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------# 
  MailAddress:
    Type: String

Resources:
# ------------------------------------------------------------#
# SNS
# ------------------------------------------------------------# 
  SnsTopic:
    Type: AWS::SNS::Topic
    Properties: 
      Subscription:
        - Endpoint: !Ref MailAddress
          Protocol: email
      TopicName: sns-guardduty

  SnsTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties: 
      PolicyDocument:
        Version: '2012-10-17'
        Id: __default_policy_ID
        Statement:
          - Sid: __default_statement_ID
            Effect: Allow
            Principal: 
              AWS: '*'
            Action: 
              - 'SNS:GetTopicAttributes'
              - 'SNS:SetTopicAttributes'
              - 'SNS:AddPermission'
              - 'SNS:RemovePermission'
              - 'SNS:DeleteTopic'
              - 'SNS:Subscribe'
              - 'SNS:ListSubscriptionsByTopic'
              - 'SNS:Publish'
            Resource: !Ref SnsTopic
            Condition: 
              StringEquals: 
                'AWS:SourceOwner': !Sub ${AWS::AccountId}
          - Sid: AWSEvents_guardduty
            Effect: Allow
            Principal: 
              Service: events.amazonaws.com
            Action: 'sns:Publish'
            Resource: !Ref SnsTopic
      Topics:
        - !Ref SnsTopic

# ------------------------------------------------------------#
# GuardDuty
# ------------------------------------------------------------# 
  GuardDuty:
    Type: AWS::GuardDuty::Detector
    Properties: 
      Enable: true

# ------------------------------------------------------------#
# EventBridge
# ------------------------------------------------------------# 
  EventBridge:
    Type: AWS::Events::Rule
    Properties: 
      EventPattern: 
        source: 
          - aws.guardduty
        detail-type: 
          - 'GuardDuty Finding'
        detail: 
          severity:
            - 7
            - 7.0
            - 7.1
            - 7.2
            - 7.3
            - 7.4
            - 7.5
            - 7.6
            - 7.7
            - 7.8
            - 7.9
            - 8
            - 8.0
            - 8.1
            - 8.2
            - 8.3
            - 8.4
            - 8.5
            - 8.6
            - 8.7
            - 8.8
            - 8.9
      Name: guardduty-event
      State: ENABLED
      Targets: 
        - Arn: !Ref SnsTopic
          Id: guardduty-event
          InputTransformer: 
            InputPathsMap: 
              'severity': '$.detail.severity'
              'Account_ID': '$.detail.accountId'
              'Finding_ID': '$.detail.id'
              'Finding_Type': '$.detail.type'
              'region': '$.region'
              'time': '$.time'
              'Finding_description': '$.detail.description'
            InputTemplate: |
              "AWSアカウント:<Account_ID> で重要度:<severity> のイベントが検出されました。"
              "検出時間:<time>"
              "検出タイプ:<Finding_Type>"
              "リージョン:<region>"
              "検出タイプ説明:<Finding_description>."
              "マネジメントコンソールから詳細をご確認ください。https://console.aws.amazon.com/guardduty/home?region=<region>#/findings?search=id=<Finding_ID>"

テンプレート説明

上記のテンプレートで設定しているのはSNSトピックの作成、GuardDutyの有効化、EventBridgeの設定です。
それぞれ見ていきます。

SNSトピックの作成

SNSトピックのエンドポイントはパラメータでメールアドレスが入るようにしています。
EventBridgeがSNSを利用できるように「sns:Publish」権限を与えています。
この権限が無いとメールが送られてこなくなります。

# ------------------------------------------------------------#
# SNS
# ------------------------------------------------------------# 
  SnsTopic:
    Type: AWS::SNS::Topic
    Properties: 
      Subscription:
        - Endpoint: !Ref MailAddress
          Protocol: email
      TopicName: sns-guardduty

  SnsTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties: 
      PolicyDocument:
        Version: '2012-10-17'
        Id: __default_policy_ID
        Statement:
          - Sid: __default_statement_ID
            Effect: Allow
            Principal: 
              AWS: '*'
            Action: 
              - 'SNS:GetTopicAttributes'
              - 'SNS:SetTopicAttributes'
              - 'SNS:AddPermission'
              - 'SNS:RemovePermission'
              - 'SNS:DeleteTopic'
              - 'SNS:Subscribe'
              - 'SNS:ListSubscriptionsByTopic'
              - 'SNS:Publish'
            Resource: !Ref SnsTopic
            Condition: 
              StringEquals: 
                'AWS:SourceOwner': !Sub ${AWS::AccountId}
          - Sid: AWSEvents_guardduty
            Effect: Allow
            Principal: 
              Service: events.amazonaws.com
            Action: 'sns:Publish'
            Resource: !Ref SnsTopic
      Topics:
        - !Ref SnsTopic

SNSのCloudFormationドキュメント

GuardDutyの有効化

GuardDutyを有効化するだけだと数行で設定ができます。

# ------------------------------------------------------------#
# GuardDuty
# ------------------------------------------------------------# 
  GuardDuty:
    Type: AWS::GuardDuty::Detector
    Properties: 
      Enable: true

GuardDutyのCloudFormationドキュメント

EventBridgeの設定

GuardDutyの検出結果が重要度高(8.9~7.0)のものだけを通知するように設定しています。
またインプットトランスフォーマーの設定で通知する内容を編集しています。
イベントの中身は以下のドキュメントをご確認ください。

# ------------------------------------------------------------#
# EventBridge
# ------------------------------------------------------------# 
  EventBridge:
    Type: AWS::Events::Rule
    Properties: 
      EventPattern: 
        source: 
          - aws.guardduty
        detail-type: 
          - 'GuardDuty Finding'
        detail: 
          severity:
            - 7
            - 7.0
            - 7.1
            - 7.2
            - 7.3
            - 7.4
            - 7.5
            - 7.6
            - 7.7
            - 7.8
            - 7.9
            - 8
            - 8.0
            - 8.1
            - 8.2
            - 8.3
            - 8.4
            - 8.5
            - 8.6
            - 8.7
            - 8.8
            - 8.9
      Name: guardduty-event
      State: ENABLED
      Targets: 
        - Arn: !Ref SnsTopic
          Id: guardduty-event
          InputTransformer: 
            InputPathsMap: 
              'severity': '$.detail.severity'
              'Account_ID': '$.detail.accountId'
              'Finding_ID': '$.detail.id'
              'Finding_Type': '$.detail.type'
              'region': '$.region'
              'time': '$.time'
              'Finding_description': '$.detail.description'
            InputTemplate: |
              "AWSアカウント:<Account_ID> で重要度:<severity> のイベントが検出されました。"
              "検出時間:<time>"
              "検出タイプ:<Finding_Type>"
              "リージョン:<region>"
              "検出タイプ説明:<Finding_description>."
              "マネジメントコンソールから詳細をご確認ください。https://console.aws.amazon.com/guardduty/home?region=<region>#/findings?search=id=<Finding_ID>"

EventBridgeのCloudFormationドキュメント

デプロイ

今回はAWS CLIを使用してCloudFormationを実行します。
AWS CLIのインストールは以下のブログを参考にしてください。

AWS CLIがインストールできたら以下のコマンドを実行します。

aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=MailAddress,ParameterValue=通知するメールアドレス

もし実行時に以下のエラーが出たらテンプレートファイルの文字コードをShift JISに変更してください

Error parsing parameter '--template-body': Unable to load paramfile (GuardDuty.yml), text contents could not be decoded.  If this is a binary file, please use the fileb:// prefix instead of the file:// prefix.

CloudFormationの実行が完了するとパラメータに入力したメールアドレス宛に「AWS Notification - Subscription Confirmation」という件名でメールが届いています。
そちらのメールを開いて「Confirm subscription」をクリックするとSNSの承認が完了します。
承認完了後、マネジメントコンソール→GuardDuty→設定を開きます。
「検出結果サンプルの生成」をクリックして数分待つとメールに重要度高の検出結果サンプルが届きます。

さいごに

今回はGuardDutyの通知設定までCloudFormationで作成してみました。
内容は簡単ですがマネジメントコンソールからの設定だと面倒なこともあったので今回作成したものを今後も利用できたらと思っています。