この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
GuardDutyまじ優秀を定期的につぶやいているAWS事業本部 梶原@新福岡オフィスです。
完全に 「一発でGuardDutyを全リージョン有効化して通知設定するテンプレート作った」
とほぼ内容被ってますが、リージョンごとにSNSを作りたくない。リージョンをまたぐ際の呼び出しコストなどは認識しているけど、まぁ、大丈夫という構成の場合に使用してください。
構成はこんな感じです。
AWS構成図
CloudFormationテンプレートの実行
1つのリージョンだけで、GuardDutyを有効にする場合はSNSのトピックを作成して、下記テンプレートを実行してください。 さくっとGuardDutyを有効にまた通知を作成できるかと思います。
テンプレートはS3に置いてますので、ログイン後に以下ボタンをポチっとしてください。
※IAMの権限(AWS Lambda用のIAM Roleを作成します)の確認がありますので、AWS CloudFormation によって IAM リソースが作成される場合があることを承認します。
にチェックをして進めてください。
パラメータ
- EnableGuardDutyDetector: は実行するリージョンで有効にする場合はtrueを選択して下さい(すでに有効にしている場合はfalse)
- MinSeverity: 通知するSeverityを指定します(デフォルトでは5以上を指定していますがすべて通知する場合は0を選択)
- SnsTopicArn: 通知先のSNSのARNを指定してください。
※複数のリージョンで構成する場合は、Stacksetsを作成して、各リージョンにテンプレートを展開、リソースを作成してください。
StackSetsの作成方法などは
をご参考ください
S3ののテンプレートURLは https://pub-devio-blog-vtuisp2o.s3.amazonaws.com/template/guardduty-sns-withroll.yml になります
SNS通知
脅威を検知した場合、SNSへ通知が送られます。 通知内容は下記のような通知になります(サンプルです)
Subject:[GuardDuty Finding] EC2 instance i-99999999 is communicating with a Drop Point.
GuardDuty Finding
------------------------------
schemaVersion: 2.0
accountId: XXXXXXXXXXXX
region: ap-southeast-2
partition: aws
id: 9ab66955e7b313cf77fbdbe7d164cc13
arn: arn:aws:guardduty:ap-southeast-2:XXXXXXXXXXXX:detector/c0b66941518c08d9fe004f6de4168aeb/finding/9ab66955e7b313cf77fbdbe7d164cc13
type: Trojan:EC2/DropPoint
severity: 5
createdAt: 2019-08-27T10:42:50.854Z
updatedAt: 2019-08-27T10:42:50.854Z
title: EC2 instance i-99999999 is communicating with a Drop Point.
description: EC2 instance i-99999999 is communicating with a remote host 198.51.100.0 that is known to hold credentials and other stolen data captured by malware.
------------------------------
For details, please refer to the following URL:https://ap-southeast-2.console.aws.amazon.com/guardduty/home?region=ap-southeast-2#/findings?fId=9ab66955e7b313cf77fbdbe7d164cc13
------------------------------
というような内容で通知されますので、文中のURLのリンクに飛ぶと、GuardDutyのコンソールで該当の脅威を表示するようにしています。 (こちらは現時点のコンソールのリンクとなりますので、今後も動作するかどうは未定です。Lambda中で編集をおこなってますので、適時Lambdaを修正してください)
テンプレート
テンプレートを置いておきますので、ご自由にご編集ください。
AWSTemplateFormatVersion: 2010-09-09
Description:
"enable guardduty and create SnsPublishLambda"
Parameters:
EnableGuardDutyDetector:
Type: String
Default: no
AllowedValues: [yes, no]
SnsTopicArn:
Description: Enter SNS Topic Arn
Type: String
MinSeverity:
Description: Enter Min publish Severity
Type: Number
Default: 5
Conditions:
EnableGuardDutyDetector: !Equals [ !Ref EnableGuardDutyDetector, yes ]
Resources:
GuardDutyDetector:
Condition: EnableGuardDutyDetector
Type: "AWS::GuardDuty::Detector"
Properties:
Enable: true
GuardDutyFindingsEventsRule:
Type: "AWS::Events::Rule"
Properties:
Name: GuardDutyFindingsEventsRule
Description: "Alert to Lambda when find threats by GuardDuty"
EventPattern:
source:
- aws.guardduty
detail-type:
- GuardDuty Finding
Targets:
- Id: GuardDutyFindingsTargets1
Arn: !GetAtt SnsPublishFunction.Arn
SnsPublishFunction:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Environment:
Variables:
SNS_TOPIC_ARN: !Ref SnsTopicArn
MIN_SEVERTIY: !Ref MinSeverity
Code:
ZipFile: !Sub |
var SNS_TOPIC_ARN = process.env.SNS_TOPIC_ARN;
var MIN_SEVERTIY = process.env.MIN_SEVERTIY;
var AWS = require('aws-sdk');
exports.handler = async(event) => {
var severity = event.detail.severity;
if(severity < MIN_SEVERTIY) {
return;
}
var message = `${!event["detail-type"]}\n`;
message += "------------------------------\n";
for (const key in event.detail) {
if (typeof(event.detail[key]) != 'object')
message += `${!key}: ${!event.detail[key]}\n`;
}
message += "------------------------------\n";
var url = `https://${!event.region}.console.aws.amazon.com/guardduty/home?region=${!event.region}#/findings?fId=${!event.detail.id}`;
message += `For details, please refer to the following URL:${!url}\n`;
message += "------------------------------\n";
var subject = `[${!event["detail-type"]}] ${!event.detail.title}`;
subject = subject.replace(/[\u{0080}-\u{FFFF}]/gu,"") // remove not ASCII
.replace(/\r?\n/g, "") // remove return
.slice(0, 100);
// SNS Publish
var params = {
Message: message,
Subject: subject,
TopicArn: SNS_TOPIC_ARN
};
var SNS_REGION = SNS_TOPIC_ARN.split(":")[3];
var sns = new AWS.SNS({region: SNS_REGION});
var result = await sns.publish(params).promise();
return result;
}
Runtime: nodejs12.x
Timeout: 30
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Path: "/"
Policies:
- PolicyName: LambdaExecutionRole-SnsPublishPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sns:Publish
Resource: !Ref SnsTopicArn
LambdaInvokePermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt SnsPublishFunction.Arn
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt GuardDutyFindingsEventsRule.Arn
まとめ
先行する小ネタ2つに引っかかりましたが、GuardDuty有効にしたいけど、SNSのトピックあまりつくりたくないんだよねーという要望にはまると幸いです。 Lambda部分などは最適化余地がたくさんあるかとおもうんで、ぜひいい感じの通知内容ができたら教えてください。 StacksSetsの部分はカスタムリソースなどをつくってホントの一撃をしたいなと思ったんですが、要望があればがんばりますので、応援してください。
参考URL
一発でGuardDutyを全リージョン有効化して通知設定するテンプレート作った
[新機能] CloudFormation StackSetsを試してみた