複数アカウントのGuardDutyの通知を一つのアカウントにまとめる構成を実装してみた

GuardDutyを複数アカウントまとめてSNSで通知するようにする設定をCloudFormationStackSetsを利用して一括で設定する方法についてまとめています。ぜひご活用ください。
2018.06.28

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

こんにちは、臼田です。

前回GuardDutyを全リージョンに展開する方法を紹介しました。

一発でGuardDutyを全リージョン有効化して通知設定するテンプレート作った

今回はこれを応用してマルチアカウントに展開して、通知を一つのアカウントで受け取る構成を、同じくCloudFormationでやってみたいと思います。

GuardDutyのマルチアカウントをまとめる手法について

GuardDutyでは自身をマスターアカウントに設定し、他のAWSアカウントをメンバーアカウントとして招待することにより通知を1つのアカウントで受け取る機能があります。

詳細は下記をご確認ください。

GuardDutyを設定してメンバーアカウントを招待してみた #reinvent

これを利用するためには下記情報が必要になります。

  • メンバーアカウントにするAWSアカウントのID
  • 上記アカウントのrootユーザのメールアドレス

CloudFormation StackSetsの利用準備

前回と同様にCloudFormation StackSetsを利用します。

このStackSetsを利用するには事前に実行する側とされる側でそれぞれIAM Roleが必要になります。

前提条件: スタックセットオペレーションのアクセス権限の付与 - AWS CloudFormation

これを簡単に設定する方法は下記にまとめました。今回は管理側は実行する側とされる側両方になり、クライアント側アカウントは実行される側なので、それぞれのIAM Roleを作成してください。

StackSets用IAM Roleのクイック作成リンク作ってみた

管理側は「AWSCloudFormationStackSetAdministrationRole」と「AWSCloudFormationStackSetExecutionRole」の2つが、管理される側は後者が作成されれば準備完了です。

GuardDutyの展開

テンプレートの準備

マルチアカウント利用時のGuardDuty + SNS通知の有効化の管理側CloudFormationテンプレート案を下記に用意しました。

AWSTemplateFormatVersion: 2010-09-09
Description:
  'enable guardduty, invite member and set alert'
# add your member accounts
Mappings:
  GuardDutyMembers:
    Member01:
      Email: mail@example.com
      AccountID: "000000000000"
    Member02: 
      Email: mail@example.com
      AccountID: "111111111111"
    Member03:
      Email: mail@example.com
      AccountID: "222222222222"
    Member04:
      Email: mail@example.com
      AccountID: "333333333333"

Parameters:
  MailAddress:
    Description: Enter email address to send notification.
    Type: String
Resources:
  GDD:
    Type: 'AWS::GuardDuty::Detector'
    Properties:
      Enable: true
  SNST:
    Type: 'AWS::SNS::Topic'
    DependsOn: GDM01
    Properties:
      TopicName: GuardDutyTopic
  SNSS:
    Type: "AWS::SNS::Subscription"
    Properties:
      Endpoint: !Ref MailAddress
      Protocol: email
      TopicArn: !Ref SNST
  ER:
    Type: 'AWS::Events::Rule'
    Properties:
      Name: AlertGuardDutyFindings
      Description: 'Alert to SNS topic when find threats by GuardDuty'
      EventPattern: {
                      "source": [
                        "aws.guardduty"
                      ],
                      "detail-type": [
                        "GuardDuty Finding"
                      ]
                    }
      Targets:
        - Arn: !Ref SNST
          Id: Id123
# copy and incriment the following
  GDM01:
    Type: "AWS::GuardDuty::Member"
    Properties:
      Status: Invited
      MemberId: !FindInMap
        - GuardDutyMembers
        - Member01
        - AccountID
      Email:  !FindInMap
        - GuardDutyMembers
        - Member01
        - Email
      Message: "invite this account to guardduty"
      DetectorId: !Ref GDD
      DisableEmailNotification: True
  GDM02:
    Type: "AWS::GuardDuty::Member"
    Properties:
      Status: Invited
      MemberId: !FindInMap
        - GuardDutyMembers
        - Member02
        - AccountID
      Email:  !FindInMap
        - GuardDutyMembers
        - Member02
        - Email
      Message: "invite this account to guardduty"
      DetectorId: !Ref GDD
      DisableEmailNotification: True
  GDM03:
    Type: "AWS::GuardDuty::Member"
    Properties:
      Status: Invited
      MemberId: !FindInMap
        - GuardDutyMembers
        - Member03
        - AccountID
      Email:  !FindInMap
        - GuardDutyMembers
        - Member03
        - Email
      Message: "invite this account to guardduty"
      DetectorId: !Ref GDD
      DisableEmailNotification: True
  GDM04:
    Type: "AWS::GuardDuty::Member"
    Properties:
      Status: Invited
      MemberId: !FindInMap
        - GuardDutyMembers
        - Member04
        - AccountID
      Email:  !FindInMap
        - GuardDutyMembers
        - Member04
        - Email
      Message: "invite this account to guardduty"
      DetectorId: !Ref GDD
      DisableEmailNotification: True

実は、GuardDutyで複数アカウントをまとめる際にはAWS::GuardDuty::Memberというタイプで上記に上げたアカウントIDとrootのメールアドレスが必要になります。

そのため、それをテンプレートに記載しておく必要があります。テンプレート中のMappingとResourceのGDM01等を必要な数だけ増やして適切に設定してください。

作成したテンプレートを保存して、アップロードできる状態にしておきます。

管理側スタックセットの作成

まず作成したテンプレートを利用してGuardDutyの管理側をスタックセットで作成します。CloudFormationのページ左上からStackSetsを選択し、「スタックセットの作成」を押します。

適当なスタック名を入れ、パラメータのメールアドレスにSNSの通知先に設定するメールアドレスを入力して「次へ」を押します。

「スタックをアカウントにデプロイ」を選択して管理側のアカウントIDを入力します。 適用するリージョンを選択します。

権限はStackSets用のRoleが選択されていることを確認して「次へ」を押します。

確認画面で「作成」を押して完了です。

作成後は詳細画面が表示されます。少し時間はかかりますが、全てCURRENTとなりステータスが「SUCCEEDED」となればCloudFormationの適用が完了です。

これで管理側は完了です。SNSの登録メールが飛んでいるため、必要に応じて前回の下記記事の下部にあるunsubscribeを無効にする方法でconfirmしてください。

一発でGuardDutyを全リージョン有効化して通知設定するテンプレート作った

クライアント側作成

クライアント側はAWSでテンプレートが用意されてるのでそれを利用します。

「スタックセットの作成」から「以下のテンプレートからサンプルテンプレートを選択」を選び、「AWS GuardDutyの有効化」を選択して「次へ」を押します。

適当なスタックセット名を入力して、パラメータには管理側のAWSアカウントIDを入力します。

「スタックをアカウントにデプロイ」でクライアント側全てのアカウントIDを入力します。カンマ区切りで入力します。

必要なリージョンを指定します。

確認画面で「作成」を押して完了です。

作成後は詳細画面が表示されます。同じく少し時間はかかりますが、全てCURRENTとなりステータスが「SUCCEEDED」となればCloudFormationの適用が完了です。

以上で管理側とクライアント側双方のGuardDuty有効化と連携が完了になります。

まとめ

複数のアカウントにまたがってGuardDutyを連携する方法についてまとめました。

少しであれば手動で行ってもいいですが、全リージョン多数のアカウントに関して適用することを考えると、StackSetsを利用したほうが効率的です。

ぜひご利用ください!