Skip to content

Commit d2ea344

Browse files
committed
Imported guardduty_slack from 0.11
1 parent 0a75ad8 commit d2ea344

23 files changed

+568
-0
lines changed

guardduty_slack/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# guardduty_slack
2+
3+
This module setups:
4+
5+
- AWS GuardDuty
6+
- S3 bucket to store "trusted IP address" list
7+
- GuardDuty won't raise alert for trusted IPs.
8+
- Slack notification (AWS lambda)
9+
10+
## Prerequisite
11+
12+
1. Create slack channel to notify
13+
2. Issue slack webhook URL to post notification
14+
15+
## Variables
16+
17+
See [variables.tf](variables.tf) for parameters.

guardduty_slack/aws_region.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data "aws_region" "current" {}

guardduty_slack/aws_s3_bucket.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
resource "aws_s3_bucket" "main" {
2+
bucket_prefix = "${var.s3_bucket_name}-"
3+
4+
acl = "private"
5+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
locals {
2+
ipset_location = "https://s3-${data.aws_region.current.name}.amazonaws.com/${aws_s3_bucket_object.trusted_ipset.bucket}/${aws_s3_bucket_object.trusted_ipset.key}"
3+
trusted_ipset_content = "${join("\n", var.trusted_ip_cidr_blocks)}"
4+
}
5+
6+
resource "aws_s3_bucket_object" "trusted_ipset" {
7+
acl = "public-read"
8+
9+
bucket = "${aws_s3_bucket.main.id}"
10+
key = "ipset-${sha1(local.trusted_ipset_content)}"
11+
12+
etag = "${md5(local.trusted_ipset_content)}"
13+
content = "${local.trusted_ipset_content}"
14+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module "lambda_sns_to_slack" {
2+
source = "./lambda_sns_to_slack"
3+
4+
basename = "guardduty-sns-to-slack-${var.envname}"
5+
guardduty_slack_webhook_url = "${var.guardduty_slack_webhook_url}"
6+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
resource "aws_iam_role" "lambda_role" {
2+
name = "${var.basename}"
3+
4+
assume_role_policy = "${data.aws_iam_policy_document.lambda_edge_assume_role.json}"
5+
}
6+
7+
data "aws_iam_policy_document" "lambda_edge_assume_role" {
8+
statement {
9+
actions = ["sts:AssumeRole"]
10+
11+
principals {
12+
type = "Service"
13+
identifiers = ["lambda.amazonaws.com", "edgelambda.amazonaws.com"]
14+
}
15+
}
16+
}
17+
18+
resource "aws_iam_role_policy_attachment" "viewer_request_lambda_execution" {
19+
role = "${aws_iam_role.lambda_role.name}"
20+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
21+
}
22+
23+
resource "aws_iam_role_policy_attachment" "viewer_request_cloudwatch_logs" {
24+
role = "${aws_iam_role.lambda_role.name}"
25+
policy_arn = "${aws_iam_policy.lambda_cloudwatch_logs.arn}"
26+
}
27+
28+
resource "aws_iam_policy" "lambda_cloudwatch_logs" {
29+
name = "${var.basename}-logs"
30+
path = "/"
31+
description = "IAM policy for logging from a lambda"
32+
33+
policy = <<EOF
34+
{
35+
"Version": "2012-10-17",
36+
"Statement": [
37+
{
38+
"Action": [
39+
"logs:CreateLogGroup",
40+
"logs:CreateLogStream",
41+
"logs:PutLogEvents"
42+
],
43+
"Resource": "arn:aws:logs:*:*:*",
44+
"Effect": "Allow"
45+
}
46+
]
47+
}
48+
EOF
49+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
output "lambda_arn" {
2+
value = "${aws_lambda_function.lambda.arn}"
3+
}
4+
5+
resource "aws_lambda_function" "lambda" {
6+
publish = true
7+
function_name = "${var.basename}"
8+
9+
filename = "${substr(data.archive_file.lambda.output_path, length(path.cwd) + 1, -1)}"
10+
handler = "index.lambda_hander"
11+
source_code_hash = "${data.archive_file.lambda.output_base64sha256}"
12+
13+
role = "${aws_iam_role.lambda_role.arn}"
14+
15+
runtime = "python3.6"
16+
memory_size = 128
17+
timeout = 30
18+
19+
environment {
20+
variables = {
21+
slack = "${var.guardduty_slack_webhook_url}"
22+
}
23+
}
24+
25+
lifecycle {
26+
ignore_changes = ["last_modified"]
27+
}
28+
}
29+
30+
data "archive_file" "lambda" {
31+
type = "zip"
32+
source_dir = "${path.module}/src"
33+
output_path = "${path.module}/temp/${var.basename}-dist.zip"
34+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/python
2+
3+
from botocore.vendored import requests # https://stackoverflow.com/a/48495770
4+
import json
5+
import os
6+
import logging
7+
8+
webhook_url = os.environ['slack']
9+
logger = logging.getLogger()
10+
logger.setLevel(logging.INFO)
11+
12+
def lambda_hander(event, context):
13+
logger.info(json.dumps(event))
14+
15+
for record in event['Records']:
16+
process_event(json.loads(record['Sns']['Message']))
17+
18+
def process_event(event):
19+
event_detail = {}
20+
if 'detail' in event:
21+
event_detail = event['detail']
22+
event_service = {}
23+
if 'service' in event_detail:
24+
event_service = event_detail['service']
25+
26+
message = "{title}\n{description}\nnseverity: {severity}\neventFirstSeen: {eventFirstSeen}\nregion: {region}".format(
27+
title = event_detail.get('title'),
28+
description = event_detail.get('description'),
29+
severity = event_detail.get('severity'),
30+
eventFirstSeen = event_service.get('eventFirstSeen'),
31+
region = event.get('region')
32+
)
33+
if event['detail']['severity'] > 3.9:
34+
requests.post(webhook_url, data = json.dumps({
35+
'text': message,
36+
'username': 'GuardDuty',
37+
'icon_emoji': ':rotating_light:',
38+
'link_names': 1,
39+
}))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.zip
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
variable "basename" {}
2+
3+
variable "guardduty_slack_webhook_url" {}

0 commit comments

Comments
 (0)