この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、臼田です。
GuardDutyはAWS上の脅威を検知してくれるマネージドサービスで、本来ならいろんなログの収集や検知の仕組みづくり、分析とかやらなければいけないところをまるっとやってくれる控えめに言ってサイコーなサービスです。
GuardDutyを有効化することは非常に簡単なのですが、全リージョンやったり、おまけに通知の設定までやろうとすると少し面倒なのでCloudFormationのStackSetの機能を利用して全リージョンで有効化してメール通知の設定まで入れるテンプレートを作ったので共有します。
とりあえずテンプレート
まず、1つのリージョンだけでいい人用に一発起動ボタンを置いておきます。
テンプレートは公開していますのでこちらのファイルを取得していただくのが早いですが、一応コードも載せておきます。
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をリージョンやアカウントをまたがって設定ができる機能です。詳細は下記をご確認ください。
このStackSetsを利用するには事前に実行する側とされる側でそれぞれIAM Roleが必要になります。
前提条件: スタックセットオペレーションのアクセス権限の付与 - AWS CloudFormation
これを簡単に設定する方法は下記にまとめました。今回は実行する側とされる側が同じアカウントなので、1つのアカウント上にそれぞれの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しないようにこれを無効化します。
おまけですが自分で作った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や上記テンプレートなどをご利用ください。