話題の記事

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

GuardDutyを全リージョンで有効化・通知の設定までやろうとすると少し面倒なのでCloudFormationのStackSetの機能を利用して全リージョンで有効化してメール通知の設定まで入れるテンプレートを作ったので共有します。
2018.06.25

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

こんにちは、臼田です。

GuardDutyはAWS上の脅威を検知してくれるマネージドサービスで、本来ならいろんなログの収集や検知の仕組みづくり、分析とかやらなければいけないところをまるっとやってくれる控えめに言ってサイコーなサービスです。

GuardDutyを有効化することは非常に簡単なのですが、全リージョンやったり、おまけに通知の設定までやろうとすると少し面倒なのでCloudFormationのStackSetの機能を利用して全リージョンで有効化してメール通知の設定まで入れるテンプレートを作ったので共有します。

とりあえずテンプレート

まず、1つのリージョンだけでいい人用に一発起動ボタンを置いておきます。

GuardDutyと通知設定テンプレート起動

テンプレートは公開していますのでこちらのファイルを取得していただくのが早いですが、一応コードも載せておきます。

AWSTemplateFormatVersion: 2010-09-09
Description:
  "enable guardduty and set alert"
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"
    Properties:
      TopicName: GuardDutyTopic
  SNSS:
    Type: "AWS::SNS::Subscription"
    Properties:
      Endpoint: !Ref MailAddress
      Protocol: email
      TopicArn: !Ref SNST
  SNSTP:
    Type: "AWS::SNS::TopicPolicy"
    Properties:
      PolicyDocument:
        Id: default_policy_ID
        Version: "2012-10-17"
        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"
            - "SNS:Receive"
          Resource: !Ref SNST
          Condition:
            StringEquals:
              "AWS:SourceOwner": !Ref "AWS::AccountId"
        - Sid: AWSEvents_AlertGuardDutyFindings_Id123
          Effect: Allow
          Principal:
            Service:
            - "events.amazonaws.com"
          Action: "sns:Publish"
          Resource: !Ref SNST
      Topics:
      - !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

2019/05/28 SNS Topic Policyをテンプレートに追記しました

これを利用することにより、下記設定が可能です。

  • GuardDutyの有効化
  • SNSトピック作成
  • SNSの通知先メールアドレスの登録(メールの承認は手動です)
  • CloudWatch Event RuleにてGuardDutyで検知したらSNSで通知するように設定

StackSetsによる全リージョン一括有効化

さて、ここからが本題です。ちなみに今回の内容はこちらの記事にインスパイアされて書いています、感謝。

StackSetsの利用準備

CloudFormationのStackSetsは、普段は単一リージョンに対してしか利用できないStackをリージョンやアカウントをまたがって設定ができる機能です。詳細は下記をご確認ください。

[新機能] CloudFormation StackSetsを試してみた

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

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

これを簡単に設定する方法は下記にまとめました。今回は実行する側とされる側が同じアカウントなので、1つのアカウント上にそれぞれのIAM Roleを作成してください。

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

「AWSCloudFormationStackSetAdministrationRole」と「AWSCloudFormationStackSetExecutionRole」の2つが作成されれば準備完了です。

StackSetsの実行

まずCloudFormation StackSetsの画面を開きます。CloudFormationの画面の左上でStackSetsを選択します。

「スタックセットの作成」を押します。

「Amazon S3 テンプレート URL の指定」を選択して、「場所を指定」で下記を入力して「次へ」を押します。

https://s3-ap-northeast-1.amazonaws.com/pub-codes-9nvushbw/templates/guardduty-sns.template

スタックセット名を任意の名前に記入し、SNSの通知先メールアドレスをパラメータのMailAddressに入れて「次へ」を押します。

オプションの設定では展開するアカウントとリージョンを指定します。アカウントに自身のアカウントを記入します。リージョンの指定は「すべて追加」で追加して、すでに設定されているリージョンなどがあれば除いてください。今回私は東京リージョンが設定済みだったので除いています。「次へ」を押します。

タグや権限のオプションはデフォルトの状態で大丈夫です。「次へ」を押します。

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

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

各リージョンでGuardDutyが有効化され、通知が有効となります。

合わせて、SNSでトピックにメールアドレスを登録しているので、「AWS Notification - Subscription Confirmation」のメールが各リージョン分(今回は14通)届いています。

こればっかりは仕方ないので一個ずつ登録します。

全リージョンの通知を1箇所にまとめて通知してもいいのですが、その場合はLambdaでこねこねしないといけないのと、Lambda及びリージョン跨ぎの通信で費用が余計にかかるので、今回はシンプルに全リージョンでSNSを用意しています。

なお、そのまま届いたリンクをクリックしてもいいですが、異常を検知した際に届くメールにunsubscribe用のリンクも付いてくるため、下記手法でうっかりunsubscribeしないようにこれを無効化します。

Amazon SNS メール通知の「unsubscribe」リンクを無効化する

おまけですが自分で作ったconfirmのURLを貼り付けるとunsubscribeを無効化した状態で登録してくれるpythonスクリプトを置いておきます。必要な回数URL貼り付けれるようにループするようにしてあります。python3でご利用ください。

import re
import boto3

snsurl_pattern = re.compile(r'https://sns\.(.*?)\..*TopicArn=(.*?)&.*Token=([0-9,a-f]*)&.*')


print('please enter "Confirm subscription" Link URL. (e.g. https://sns.us-east-1.amazonaws.com/confirmation.html?TopicArn=...)')
while True:
	input_url = input('(if you want to stop, please enter "end") enter url: ')
	if input_url == "end": break
	m = snsurl_pattern.match(input_url)
	if m is None:
		print('input is wrong. please enter "Confirm subscription" Link URL.')
		continue
	region = m.group(1)
	topicarn = m.group(2)
	token = m.group(3)
	sns = boto3.client('sns', region_name=region)
	r = sns.confirm_subscription(
		TopicArn=topicarn,
		Token=token,
		AuthenticateOnUnsubscribe='true'
	)
	print(r)

confirmしたら全て完了になります。

まとめ

GuardDutyを全リージョンで有効化して通知設定を入れる手法を簡単にして提供してみました。

手動でやろうと思うと面倒なので、ぜひStackSetsや上記テンプレートなどをご利用ください。