Skip to content

Commit f1722c0

Browse files
committed
Update to version v1.3.1
1 parent 106eae4 commit f1722c0

File tree

12 files changed

+298
-60
lines changed

12 files changed

+298
-60
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [1.3.1] - 2021-09-10
8+
9+
### Changed
10+
- CreateLogMetricFilterAndAlarm.py changed to make Actions active, add SNS notification to SO0111-SHARR-LocalAlarmNotification
11+
- Change CIS 2.8 remediation to match new finding data format
12+
713
## [1.3.0] - 2021-08-30
814

915
### Added

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ v1.0.0.
5252

5353
### Architecture Diagram
5454

55-
![](SHARR_v1.2.jpg)
55+
![](./SHARR_v1.2.jpg)
5656

5757
<a name="aws-solutions-constructs"></a>
5858

source/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aws-security-hub-automated-response-and-remediation",
3-
"version": "1.3.0",
3+
"version": "1.3.1",
44
"description": "Automated remediation for AWS Security Hub (SO0111)",
55
"bin": {
66
"solution_deploy": "bin/solution_deploy.js"

source/playbooks/CIS120/ssmdocs/CIS_2.8.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ mainSteps:
3333
action: 'aws:executeScript'
3434
outputs:
3535
- Name: KMSKeyId
36-
Selector: $.Payload.resource_id
36+
Selector: $.Payload.details.AwsKmsKey.KeyId
3737
Type: String
3838
- Name: FindingId
3939
Selector: $.Payload.finding_id
@@ -47,7 +47,7 @@ mainSteps:
4747
inputs:
4848
InputPayload:
4949
Finding: '{{Finding}}'
50-
parse_id_pattern: '^AWS::KMS::Key:([a-f0-9-]{8}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{12})$'
50+
parse_id_pattern: ''
5151
expected_control_id: '2.8'
5252
Runtime: python3.7
5353
Handler: parse_event

source/playbooks/CIS120/ssmdocs/CIS_3.1.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ parameters:
6666
type: String
6767
default: 'LogMetrics'
6868
description: The name of the metric namespace where the metrics will be logged
69+
KMSKeyArn:
70+
type: String
71+
default: >-
72+
{{ssm:/Solutions/SO0111/CMK_REMEDIATION_ARN}}
73+
description: The ARN of the KMS key created by SHARR for remediations
74+
allowedPattern: '^arn:(?:aws|aws-us-gov|aws-cn):kms:(?:[a-z]{2}(?:-gov)?-[a-z]+-\d):\d{12}:(?:(?:alias/[A-Za-z0-9/-_])|(?:key/(?i:[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})))$'
75+
6976
mainSteps:
7077
- name: ParseInput
7178
action: 'aws:executeScript'
@@ -144,6 +151,8 @@ mainSteps:
144151
AlarmDesc: '{{ GetMetricFilterAndAlarmInputValue.AlarmDesc }}'
145152
AlarmThreshold: '{{ GetMetricFilterAndAlarmInputValue.AlarmThreshold }}'
146153
LogGroupName: '{{ LogGroupName }}'
154+
SNSTopicName: 'SO0111-SHARR-LocalAlarmNotification'
155+
KMSKeyArn: '{{KMSKeyArn}}'
147156

148157
- name: UpdateFinding
149158
action: 'aws:executeAwsApi'
@@ -154,7 +163,7 @@ mainSteps:
154163
- Id: '{{ParseInput.FindingId}}'
155164
ProductArn: '{{ParseInput.ProductArn}}'
156165
Note:
157-
Text: 'Added metric filter to the log group to monitor unauthorized API calls.'
166+
Text: 'Added metric filter to the log group and notifications to SNS topic SO0111-SHARR-LocalAlarmNotification.'
158167
UpdatedBy: 'SHARR-CIS_1.2.0_3.1'
159168
Workflow:
160169
Status: RESOLVED

source/remediation_runbooks/CreateLogMetricFilterAndAlarm.yaml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,33 @@ parameters:
4444
AlarmThreshold:
4545
type: Integer
4646
description: Threshold value for the alarm
47+
KMSKeyArn:
48+
type: String
49+
description: The ARN of a KMS key to use for encryption of the SNS Topic and Config bucket
50+
allowedPattern: '^arn:(?:aws|aws-us-gov|aws-cn):kms:(?:[a-z]{2}(?:-gov)?-[a-z]+-\d):\d{12}:(?:(?:alias/[A-Za-z0-9/-_])|(?:key/(?i:[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})))$'
51+
SNSTopicName:
52+
type: String
53+
allowedPattern: ^[a-zA-Z0-9][a-zA-Z0-9-_]{0,255}$
54+
4755
mainSteps:
48-
- name: CreateMetricFilerAndAlarm
56+
-
57+
name: CreateTopic
58+
action: 'aws:executeScript'
59+
outputs:
60+
- Name: TopicArn
61+
Selector: $.Payload.topic_arn
62+
Type: String
63+
inputs:
64+
InputPayload:
65+
kms_key_arn: '{{KMSKeyArn}}'
66+
topic_name: '{{SNSTopicName}}'
67+
Runtime: python3.7
68+
Handler: create_encrypted_topic
69+
Script: |-
70+
%%SCRIPT=CreateLogMetricFilterAndAlarm_createtopic.py%%
71+
72+
-
73+
name: CreateMetricFilerAndAlarm
4974
action: 'aws:executeScript'
5075
outputs:
5176
- Name: Output
@@ -62,6 +87,7 @@ mainSteps:
6287
AlarmName: '{{AlarmName}}'
6388
AlarmDesc: '{{AlarmDesc}}'
6489
AlarmThreshold: '{{AlarmThreshold}}'
90+
TopicArn: '{{CreateTopic.TopicArn}}'
6591
Runtime: python3.7
6692
Handler: verify
6793
Script: |-

source/remediation_runbooks/scripts/CreateLogMetricFilterAndAlarm.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def put_metric_filter(cw_log_group, filter_name, filter_pattern, metric_name, me
7272
log.debug("Successfully added the metric filter.")
7373

7474

75-
def put_metric_alarm(alarm_name, alarm_desc, alarm_threshold, metric_name, metric_namespace):
75+
def put_metric_alarm(alarm_name, alarm_desc, alarm_threshold, metric_name, metric_namespace, topic_arn):
7676
"""
7777
Puts the metric alarm for the metric name with provided values
7878
:param alarm_name: Name for the alarm
@@ -88,7 +88,13 @@ def put_metric_alarm(alarm_name, alarm_desc, alarm_threshold, metric_name, metri
8888
cw_client.put_metric_alarm(
8989
AlarmName=alarm_name,
9090
AlarmDescription=alarm_desc,
91-
ActionsEnabled=False,
91+
ActionsEnabled=True,
92+
OKActions=[
93+
topic_arn
94+
],
95+
AlarmActions=[
96+
topic_arn
97+
],
9298
MetricName=metric_name,
9399
Namespace=metric_namespace,
94100
Statistic='Sum',
@@ -117,9 +123,10 @@ def verify(event, context):
117123
alarm_desc = event['AlarmDesc']
118124
alarm_threshold = event['AlarmThreshold']
119125
cw_log_group = event['LogGroupName']
126+
topic_arn = event['TopicArn']
120127

121128
put_metric_filter(cw_log_group, filter_name, filter_pattern, metric_name, metric_namespace, metric_value)
122-
put_metric_alarm(alarm_name, alarm_desc, alarm_threshold, metric_name, metric_namespace)
129+
put_metric_alarm(alarm_name, alarm_desc, alarm_threshold, metric_name, metric_namespace, topic_arn)
123130
return {
124131
"response": {
125132
"message": f'Created filter {event["FilterName"]} for metric {event["MetricName"]}, and alarm {event["AlarmName"]}',

source/remediation_runbooks/scripts/test/test_createlogmetricfilterandalarm.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ def test_verify(mocker):
3838
'AlarmName': 'test_alarm',
3939
'AlarmDesc': 'alarm_desc',
4040
'AlarmThreshold': 'alarm_threshold',
41-
'LogGroupName': 'test_log'
41+
'LogGroupName': 'test_log',
42+
'TopicArn': 'arn:aws:sns:us-east-1:111111111111:test-topic-name'
4243
}
4344
context = {}
4445
mocker.patch('CreateLogMetricFilterAndAlarm.put_metric_filter')
@@ -47,7 +48,7 @@ def test_verify(mocker):
4748
metric_alarm_spy = mocker.spy(logMetricAlarm, 'put_metric_alarm')
4849
logMetricAlarm.verify(event, context)
4950
metric_filter_spy.assert_called_once_with('test_log', 'test_filter', 'test_pattern', 'test_metric', 'test_metricnamespace', 'test_metric_value')
50-
metric_alarm_spy.assert_called_once_with('test_alarm', 'alarm_desc', 'alarm_threshold', 'test_metric', 'test_metricnamespace')
51+
metric_alarm_spy.assert_called_once_with('test_alarm', 'alarm_desc', 'alarm_threshold', 'test_metric', 'test_metricnamespace', 'arn:aws:sns:us-east-1:111111111111:test-topic-name')
5152

5253

5354
def test_put_metric_filter_pass(mocker):
@@ -60,7 +61,8 @@ def test_put_metric_filter_pass(mocker):
6061
'AlarmName': 'test_alarm',
6162
'AlarmDesc': 'alarm_desc',
6263
'AlarmThreshold': 'alarm_threshold',
63-
'LogGroupName': 'test_log'
64+
'LogGroupName': 'test_log',
65+
'TopicArn': 'arn:aws:sns:us-east-1:111111111111:test-topic-name'
6466
}
6567

6668
BOTO_CONFIG = Config(
@@ -109,7 +111,8 @@ def test_put_metric_filter_error(mocker):
109111
'AlarmName': 'test_alarm',
110112
'AlarmDesc': 'alarm_desc',
111113
'AlarmThreshold': 'alarm_threshold',
112-
'LogGroupName': 'test_log'
114+
'LogGroupName': 'test_log',
115+
'TopicArn': 'arn:aws:sns:us-east-1:111111111111:test-topic-name'
113116
}
114117

115118
BOTO_CONFIG = Config(
@@ -146,7 +149,8 @@ def test_put_metric_alarm(mocker):
146149
'AlarmName': 'test_alarm',
147150
'AlarmDesc': 'alarm_desc',
148151
'AlarmThreshold': 1,
149-
'LogGroupName': 'test_log'
152+
'LogGroupName': 'test_log',
153+
'TopicArn': 'arn:aws:sns:us-east-1:111111111111:test-topic-name'
150154
}
151155

152156
BOTO_CONFIG = Config(
@@ -164,7 +168,13 @@ def test_put_metric_alarm(mocker):
164168
{
165169
'AlarmName': event['AlarmName'],
166170
'AlarmDescription': event['AlarmDesc'],
167-
'ActionsEnabled': False,
171+
'ActionsEnabled': True,
172+
'OKActions': [
173+
'arn:aws:sns:us-east-1:111111111111:test-topic-name'
174+
],
175+
'AlarmActions': [
176+
'arn:aws:sns:us-east-1:111111111111:test-topic-name'
177+
],
168178
'MetricName': event['MetricName'],
169179
'Namespace': event['MetricNamespace'],
170180
'Statistic': 'Sum',
@@ -179,7 +189,7 @@ def test_put_metric_alarm(mocker):
179189
mocker.patch('CreateLogMetricFilterAndAlarm.get_service_client', return_value=cloudwatch)
180190
logMetricAlarm.put_metric_alarm(
181191
event['AlarmName'], event['AlarmDesc'], event['AlarmThreshold'],
182-
event['MetricName'], event['MetricNamespace']
192+
event['MetricName'], event['MetricNamespace'], event['TopicArn']
183193
)
184194
assert cloudwatch_stubber.assert_no_pending_responses() is None
185195
cloudwatch_stubber.deactivate()
@@ -195,7 +205,8 @@ def test_put_metric_alarm_error(mocker):
195205
'AlarmName': 'test_alarm',
196206
'AlarmDesc': 'alarm_desc',
197207
'AlarmThreshold': 1,
198-
'LogGroupName': 'test_log'
208+
'LogGroupName': 'test_log',
209+
'TopicArn': 'arn:aws:sns:us-east-1:111111111111:test-topic-name'
199210
}
200211

201212
BOTO_CONFIG = Config(
@@ -217,7 +228,7 @@ def test_put_metric_alarm_error(mocker):
217228
with pytest.raises(SystemExit) as pytest_wrapped_exception:
218229
logMetricAlarm.put_metric_alarm(
219230
event['AlarmName'], event['AlarmDesc'], event['AlarmThreshold'],
220-
event['MetricName'], event['MetricNamespace']
231+
event['MetricName'], event['MetricNamespace'], event['TopicArn']
221232
)
222233
assert pytest_wrapped_exception.type == SystemExit
223234
cloudwatch_stubber.deactivate()

source/solution_deploy/lib/remediation_runbook-stack.ts

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,54 @@ export class RemediationRunbookStack extends cdk.Stack {
127127
}
128128
}
129129
//-----------------------
130+
// CreateLogMetricAndAlarm
131+
//
132+
{
133+
const remediationName = 'CreateLogMetricFilterAndAlarm'
134+
const inlinePolicy = new Policy(this, `SHARR-Remediation-Policy-${remediationName}`);
135+
136+
const remediationPolicy = new PolicyStatement();
137+
remediationPolicy.addActions(
138+
"logs:PutMetricFilter",
139+
"cloudwatch:PutMetricAlarm"
140+
)
141+
remediationPolicy.effect = Effect.ALLOW
142+
remediationPolicy.addResources(`arn:${this.partition}:logs:*:${this.account}:log-group:*`);
143+
remediationPolicy.addResources(`arn:${this.partition}:cloudwatch:*:${this.account}:alarm:*`);
144+
145+
inlinePolicy.addStatements(remediationPolicy)
146+
147+
{
148+
var snsPerms = new PolicyStatement();
149+
snsPerms.addActions(
150+
"sns:CreateTopic",
151+
"sns:SetTopicAttributes"
152+
)
153+
snsPerms.effect = Effect.ALLOW
154+
snsPerms.addResources(
155+
`arn:${this.partition}:sns:${this.region}:${this.account}:SO0111-SHARR-LocalAlarmNotification`
156+
);
157+
inlinePolicy.addStatements(snsPerms)
158+
}
159+
160+
new SsmRole(this, 'RemediationRole ' + remediationName, {
161+
solutionId: props.solutionId,
162+
ssmDocName: remediationName,
163+
adminAccountNumber: adminAccount.adminAccountNumber.valueAsString,
164+
remediationPolicy: inlinePolicy,
165+
remediationRoleName: `${remediationRoleNameBase}${remediationName}_${this.region}`
166+
})
167+
168+
new SsmRemediationRunbook(this, 'SHARR '+ remediationName, {
169+
ssmDocName: remediationName,
170+
ssmDocPath: ssmdocs,
171+
ssmDocFileName: `${remediationName}.yaml`,
172+
scriptPath: `${ssmdocs}/scripts`,
173+
solutionVersion: props.solutionVersion,
174+
solutionDistBucket: props.solutionDistBucket
175+
})
176+
}
177+
//-----------------------
130178
// EnableAutoScalingGroupELBHealthCheck
131179
//
132180
{
@@ -1298,42 +1346,5 @@ export class RemediationRunbookStack extends cdk.Stack {
12981346
}
12991347
}
13001348

1301-
//****
1302-
//Create remediation books for CIS findings 3.1 through 3.14
1303-
//
1304-
1305-
{
1306-
const remediationName = 'CreateLogMetricFilterAndAlarm'
1307-
const inlinePolicy = new Policy(this, `SHARR-Remediation-Policy-${remediationName}`);
1308-
1309-
const remediationPolicy = new PolicyStatement();
1310-
remediationPolicy.addActions(
1311-
"logs:PutMetricFilter",
1312-
"cloudwatch:PutMetricAlarm"
1313-
)
1314-
remediationPolicy.effect = Effect.ALLOW
1315-
remediationPolicy.addResources(`arn:${this.partition}:logs:*:${this.account}:log-group:*`);
1316-
remediationPolicy.addResources(`arn:${this.partition}:cloudwatch:*:${this.account}:alarm:*`);
1317-
1318-
inlinePolicy.addStatements(remediationPolicy)
1319-
1320-
new SsmRole(this, 'RemediationRole ' + remediationName, {
1321-
solutionId: props.solutionId,
1322-
ssmDocName: remediationName,
1323-
adminAccountNumber: adminAccount.adminAccountNumber.valueAsString,
1324-
remediationPolicy: inlinePolicy,
1325-
remediationRoleName: `${remediationRoleNameBase}${remediationName}_${this.region}`
1326-
})
1327-
1328-
new SsmRemediationRunbook(this, 'SHARR '+ remediationName, {
1329-
ssmDocName: remediationName,
1330-
ssmDocPath: ssmdocs,
1331-
ssmDocFileName: `${remediationName}.yaml`,
1332-
scriptPath: `${ssmdocs}/scripts`,
1333-
solutionVersion: props.solutionVersion,
1334-
solutionDistBucket: props.solutionDistBucket
1335-
})
1336-
}
1337-
13381349
}
13391350
}

source/solution_deploy/lib/sharr_member-stack.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ export class MemberStack extends cdk.Stack {
218218
const logGroupName = new cdk.CfnParameter(this, "LogGroupName",
219219
{
220220
type: "String",
221-
description: "Name of the log group to be used to create metric filters and cloudwatch alarms"
221+
description: "Name of the log group to be used to create metric filters and cloudwatch alarms. You must use a Log Group that is the the logging destination of a multi-region CloudTrail"
222222
});
223223

224224
/********************

0 commit comments

Comments
 (0)