Skip to content

Commit d23f8a3

Browse files
committed
feat(λ): Dynamically zip file. Add email subject
1 parent 0a1c66f commit d23f8a3

File tree

3 files changed

+152
-1
lines changed

3 files changed

+152
-1
lines changed

main.tf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,17 @@ EOF
233233
managed_policy_arns = ["arn:${data.aws_partition.this.partition}:iam::aws:policy/AWSSecurityHubReadOnlyAccess"]
234234
}
235235

236+
data "archive_file" "init" {
237+
type = "zip"
238+
source_file = "${path.module}/sec-hub-email.py"
239+
output_path = "${path.module}/sec-hub-email.zip"
240+
}
241+
236242
resource "aws_lambda_function" "sechub_summariser" {
237243
filename = "${path.module}/sec-hub-email.zip"
238244
function_name = var.name
239245
role = aws_iam_role.iam_for_lambda.arn
240-
handler = "index.lambda_handler"
246+
handler = "sec-hub-email.lambda_handler"
241247

242248
# The filebase64sha256() function is available in Terraform 0.11.12 and later
243249
# For Terraform 0.11.11 and earlier, use the base64sha256() function and the file() function:

sec-hub-email.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import boto3
2+
import os
3+
import logging
4+
5+
logger = logging.getLogger()
6+
logger.setLevel(logging.INFO)
7+
8+
SINGLE_LINE_LENGTH = 80
9+
DOUBLE_LINE_LENGTH = 47
10+
FOOTER_TEXT = os.environ['AdditionalEmailFooterText']
11+
HEADER_TEXT = 'Weekly Security Hub Report \n'
12+
FOOTER_URL = 'https://console.aws.amazon.com/securityhub/home/standards#/standards'
13+
14+
# this function will add a horizontal line to the email
15+
def add_horizontal_line(text_body, line_char, line_length):
16+
y = 0
17+
while y <= line_length:
18+
text_body += line_char
19+
y += 1
20+
text_body += '\n'
21+
22+
return text_body
23+
24+
def lambda_handler(event, context):
25+
26+
insightArns = []
27+
insightLabels = []
28+
#this is the placement number of insights that are grouped by severity, this is used for reversing the sort
29+
severityTypeInsights = [1,2,3,4]
30+
31+
#fetch arns for custom insights from lambda environment variables
32+
insightArns.append(os.environ['ARNInsight01'])
33+
insightArns.append(os.environ['ARNInsight02'])
34+
insightArns.append(os.environ['ARNInsight03'])
35+
insightArns.append(os.environ['ARNInsight04'])
36+
insightArns.append(os.environ['ARNInsight05'])
37+
insightArns.append(os.environ['ARNInsight06'])
38+
insightArns.append(os.environ['ARNInsight07'])
39+
40+
#fetch the SNS arn to send the email body to, from lambda environment variables
41+
snsTopicArn = os.environ['SNSTopic']
42+
43+
#determine region from the arns
44+
arnParsed = insightArns[0].split(':')
45+
region = arnParsed[3]
46+
47+
#create list of section labels
48+
insightLabels.append('AWS Foundational Security Best Practices security checks:')
49+
insightLabels.append('AWS Foundational Security Best Practices failed security checks by severity:')
50+
insightLabels.append('GuardDuty threat detection findings by severity:')
51+
insightLabels.append('IAM Access Analyzer findings by severity:')
52+
insightLabels.append('Unresolved findings by severity:')
53+
insightLabels.append('New findings in the last 7 days:')
54+
insightLabels.append('Top 10 Resource Types with findings:')
55+
56+
#format Email header
57+
snsBody = ''
58+
snsBody = add_horizontal_line(snsBody, '=', DOUBLE_LINE_LENGTH)
59+
snsBody += HEADER_TEXT
60+
snsBody = add_horizontal_line(snsBody, '=', DOUBLE_LINE_LENGTH)
61+
snsBody += '\n\n'
62+
63+
#create boto3 client for Security Hub API calls
64+
sec_hub_client = boto3.client('securityhub')
65+
66+
#for each custom insight get results and format for email
67+
i = 0
68+
while i < len(insightArns):
69+
70+
#call security hub api to get results for each custom insight
71+
response = sec_hub_client.get_insight_results(
72+
InsightArn=insightArns[i]
73+
)
74+
insightResults = response['InsightResults']['ResultValues']
75+
76+
#format into an email - section header
77+
snsBody += str(insightLabels[i]) + '\n'
78+
snsBody = add_horizontal_line(snsBody,'-', SINGLE_LINE_LENGTH)
79+
80+
#check for blank custom insights
81+
if len(insightResults) == 0:
82+
snsBody += 'NO RESULTS \n'
83+
84+
#determine how many rows are in this section, cap at 10
85+
totalRows = len(insightResults)
86+
if totalRows > 10:
87+
totalRows = 10
88+
89+
#determine if this is the first section to customize the label
90+
if i == 0:
91+
firstSection = True
92+
else:
93+
firstSection = False
94+
95+
#determine if this is an insight that needs an updated sort
96+
if (i in severityTypeInsights):
97+
#reverse the sort
98+
insightResults.reverse()
99+
100+
#convert the API results into rows for email formatting
101+
x = 0
102+
while x < totalRows:
103+
104+
snsBody += str(insightResults[x]['Count']) #add the value
105+
snsBody += '\t - \t' #add a divider
106+
if firstSection: #add two extra labels (TOTAL and CHECKS) to the values for the foundational summary
107+
snsBody += 'TOTAL '
108+
snsBody += str(insightResults[x]['GroupByAttributeValue']) #add the label
109+
snsBody += ' CHECKS'
110+
else:
111+
snsBody += str(insightResults[x]['GroupByAttributeValue']) #add the label
112+
113+
snsBody += '\n' #next line
114+
x += 1
115+
116+
#add table footer
117+
snsBody = add_horizontal_line(snsBody,'-', SINGLE_LINE_LENGTH)
118+
snsBody +=' \n'
119+
120+
#create and add deep link for this section
121+
insightLink = 'https://' + region + '.console.aws.amazon.com/securityhub/home?region='
122+
insightLink += region + '#/insights/' + insightArns[i]
123+
snsBody += insightLink
124+
125+
snsBody += ' \n\n'
126+
i += 1
127+
128+
#add footer text
129+
snsBody += FOOTER_TEXT
130+
snsBody += '\n'
131+
snsBody = add_horizontal_line(snsBody,'-', SINGLE_LINE_LENGTH)
132+
snsBody += FOOTER_URL
133+
134+
#send to SNS
135+
sns_client = boto3.client('sns')
136+
137+
response = sns_client.publish(
138+
TopicArn=snsTopicArn,
139+
Message=snsBody,
140+
Subject='Security Hub Summary Report'
141+
)
142+
143+
return {
144+
'statusCode': 200,
145+
}

sec-hub-email.zip

-2.13 KB
Binary file not shown.

0 commit comments

Comments
 (0)