Skip to content

Commit 561e9cd

Browse files
authored
Merge pull request #214 from aws-solutions/release/v2.1.4
release/v2.1.4
2 parents 32f4774 + 76e7495 commit 561e9cd

19 files changed

+206
-13
lines changed

CHANGELOG.md

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

8+
## [2.1.4] - 2024-11-18
9+
### Changed
10+
- Upgraded python runtimes in all control runbooks from python3.8 to python3.11.
11+
- Upgrade is done at build-time temporarily, until the `cdklabs/cdk-ssm-documents` package adds support for newer python runtimes.
12+
### Security
13+
- Upgraded cross-spawn to mitigate [CVE-2024-21538](https://avd.aquasec.com/nvd/cve-2024-21538)
14+
815
## [2.1.3] - 2024-09-18
916

1017
### Fixed

deployment/build-s3-dist.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ main() {
181181
mv "$template_dist_dir"/MemberRoleStack.template "$template_dist_dir"/aws-sharr-member-roles.template
182182

183183
rm "$template_dist_dir"/*.nested.template
184+
185+
python3 $template_dir/upgrade_python_runtimes.py $template_dist_dir/playbooks
184186
}
185187

186188
main "$@"

deployment/upgrade_python_runtimes.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# !/usr/bin/env python3
5+
6+
import json
7+
import os
8+
import re
9+
import sys
10+
11+
12+
def update_python_runtimes(directory):
13+
"""
14+
The @cdklabs/cdk-ssm-documents package used to create some of the solution's control runbooks (SSM Documents)
15+
does not support python runtimes newer than python3.8 as of 11/14/2024. This function updates all member runbook templates
16+
to use python3.11 instead of python3.8 after they are synthesized.
17+
:param directory: directory where synthesized templates are located.
18+
"""
19+
for template_filename in os.listdir(directory):
20+
if re.search(r"MemberStack(\d*).template$", template_filename):
21+
file_path = os.path.join(directory, template_filename)
22+
23+
with open(file_path, "r") as file:
24+
try:
25+
data = json.load(file)
26+
except json.JSONDecodeError:
27+
print(f"Skipping {template_filename}: not a valid JSON file.")
28+
continue
29+
# Convert template JSON to string and replace "python3.8" with "python3.11"
30+
template_str = json.dumps(data)
31+
updated_template_str = template_str.replace("python3.8", "python3.11")
32+
updated_template = json.loads(updated_template_str)
33+
# Write the updated template back to the .template file
34+
with open(file_path, "w") as file:
35+
json.dump(updated_template, file, indent=1)
36+
print(
37+
f"Successfully updated python runtimes in {template_filename} from python3.8 --> python3.11"
38+
)
39+
40+
41+
if __name__ == "__main__":
42+
if len(sys.argv) != 2:
43+
print(
44+
"Invalid invocation. Script should be invoked like: python upgrade_python_runtimes.py <directory_path>"
45+
)
46+
sys.exit(1)
47+
directory_path = sys.argv[1]
48+
update_python_runtimes(directory_path)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "automated_security_response_on_aws"
3-
version = "2.1.3"
3+
version = "2.1.4"
44

55
[tool.setuptools]
66
package-dir = {"" = "source"}

solution-manifest.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
id: SO0111
22
name: security-hub-automated-response-and-remediation
3-
version: 2.1.3
3+
version: 2.1.4
44
cloudformation_templates:
55
- template: aws-sharr-deploy.template
66
main_template: true

source/lib/__snapshots__/member-stack.test.ts.snap

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,14 @@ exports[`member stack snapshot matches 1`] = `
12651265
"DependsOn": [
12661266
"WaitProviderRole83B0295F",
12671267
],
1268+
"Metadata": {
1269+
"guard": {
1270+
"SuppressedRules": [
1271+
"LAMBDA_CONCURRENCY_CHECK",
1272+
"LAMBDA_INSIDE_VPC",
1273+
],
1274+
},
1275+
},
12681276
"Properties": {
12691277
"Code": {
12701278
"S3Bucket": {
@@ -1307,6 +1315,12 @@ exports[`member stack snapshot matches 1`] = `
13071315
},
13081316
],
13091317
},
1318+
"guard": {
1319+
"SuppressedRules": [
1320+
"IAM_NO_INLINE_POLICY_CHECK",
1321+
"IAM_POLICYDOCUMENT_NO_WILDCARD_RESOURCE",
1322+
],
1323+
},
13101324
},
13111325
"Properties": {
13121326
"AssumeRolePolicyDocument": {

source/lib/cdk-helper/add-cfn-nag-suppression.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,24 @@ export function addCfnNagSuppression(resource: IConstruct, suppression: CfnNagSu
2424
};
2525
}
2626
}
27+
28+
export function addCfnGuardSuppression(resource: IConstruct, suppression: string): void {
29+
const cfnResource = resource.node.defaultChild as CfnResource;
30+
if (!cfnResource?.cfnOptions) {
31+
throw new Error(`Resource ${cfnResource?.logicalId} has no cfnOptions, unable to add CfnGuard suppression`);
32+
}
33+
const existingSuppressions: string[] = cfnResource.cfnOptions.metadata?.guard?.SuppressedRules;
34+
if (existingSuppressions) {
35+
existingSuppressions.push(suppression);
36+
} else if (cfnResource.cfnOptions.metadata) {
37+
cfnResource.cfnOptions.metadata.guard = {
38+
SuppressedRules: [suppression],
39+
};
40+
} else {
41+
cfnResource.cfnOptions.metadata = {
42+
guard: {
43+
SuppressedRules: [suppression],
44+
},
45+
};
46+
}
47+
}

source/lib/cloudwatch_metrics.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { Topic } from 'aws-cdk-lib/aws-sns';
1919
import { Key } from 'aws-cdk-lib/aws-kms';
2020
import { SnsAction } from 'aws-cdk-lib/aws-cloudwatch-actions';
2121
import { ServicePrincipal } from 'aws-cdk-lib/aws-iam';
22+
import { addCfnGuardSuppression } from './cdk-helper/add-cfn-nag-suppression';
2223

2324
export interface CloudWatchMetricsProps {
2425
solutionId: string;
@@ -195,6 +196,7 @@ export class CloudWatchMetrics {
195196
});
196197
setCondition(noRemediationErrorAlarm, isUsingCloudWatchMetricsAlarms);
197198
noRemediationErrorAlarm.addAlarmAction(new SnsAction(snsAlarmTopic));
199+
addCfnGuardSuppression(noRemediationErrorAlarm, 'CFN_NO_EXPLICIT_RESOURCE_NAMES');
198200

199201
const failedAssumeRoleAlarm = failedAssumeRoleMetric.createAlarm(scope, 'FailedAssumeRoleAlarm', {
200202
alarmName: 'ASR-RunbookAssumeRoleFailure',
@@ -210,6 +212,8 @@ export class CloudWatchMetrics {
210212
setCondition(failedAssumeRoleAlarm, isUsingCloudWatchMetricsAlarms);
211213
failedAssumeRoleAlarm.addAlarmAction(new SnsAction(snsAlarmTopic));
212214

215+
addCfnGuardSuppression(failedAssumeRoleAlarm, 'CFN_NO_EXPLICIT_RESOURCE_NAMES');
216+
213217
const stateMachineExecutionsAlarm = stateMachineExecutionsMetric.createAlarm(scope, 'StateMachineExecutions', {
214218
alarmName: 'ASR-StateMachineExecutions',
215219
evaluationPeriods: 1,
@@ -222,6 +226,7 @@ export class CloudWatchMetrics {
222226

223227
setCondition(stateMachineExecutionsAlarm, isUsingCloudWatchMetricsAlarms);
224228
stateMachineExecutionsAlarm.addAlarmAction(new SnsAction(snsAlarmTopic));
229+
addCfnGuardSuppression(stateMachineExecutionsAlarm, 'CFN_NO_EXPLICIT_RESOURCE_NAMES');
225230

226231
/// CloudWatch Dashboard
227232
const remediationDashboard = new Dashboard(scope, 'RemediationDashboard', {

source/lib/common-orchestrator-construct.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Construct } from 'constructs';
1010
import * as cdk_nag from 'cdk-nag';
1111
import { Timeout } from 'aws-cdk-lib/aws-stepfunctions';
1212
import { IQueue } from 'aws-cdk-lib/aws-sqs';
13+
import { addCfnGuardSuppression } from './cdk-helper/add-cfn-nag-suppression';
1314

1415
export interface ConstructProps {
1516
roleArn: string;
@@ -494,6 +495,7 @@ export class OrchestratorConstruct extends Construct {
494495
'CloudWatch Logs permissions require resource * except for DescribeLogGroups, except for GovCloud, which only works with resource *',
495496
},
496497
]);
498+
addCfnGuardSuppression(orchestratorRole, 'IAM_NO_INLINE_POLICY_CHECK');
497499

498500
const orchestratorStateMachine = new sfn.StateMachine(this, 'StateMachine', {
499501
definitionBody: sfn.DefinitionBody.fromChainable(extractFindings),

source/lib/orchestrator_roles-construct.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
CfnRole,
1313
} from 'aws-cdk-lib/aws-iam';
1414
import { Construct } from 'constructs';
15+
import { addCfnGuardSuppression } from './cdk-helper/add-cfn-nag-suppression';
1516

1617
export interface OrchRoleProps {
1718
solutionId: string;
@@ -142,5 +143,6 @@ export class OrchestratorMemberRole extends Construct {
142143
],
143144
},
144145
};
146+
addCfnGuardSuppression(memberRole, 'IAM_NO_INLINE_POLICY_CHECK');
145147
}
146148
}

source/lib/remediation_runbook-stack.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { SsmRole } from './ssmplaybook';
2525
import { Aspects, CfnParameter } from 'aws-cdk-lib';
2626
import { WaitProvider } from './wait-provider';
2727
import SsmDocRateLimit from './ssm-doc-rate-limit';
28+
import { addCfnGuardSuppression } from './cdk-helper/add-cfn-nag-suppression';
2829

2930
export interface MemberRoleStackProps extends cdk.StackProps {
3031
readonly solutionId: string;
@@ -419,6 +420,7 @@ export class RemediationRunbookStack extends cdk.Stack {
419420
},
420421
};
421422
}
423+
addCfnGuardSuppression(ctcw_remediation_role, 'IAM_NO_INLINE_POLICY_CHECK');
422424
}
423425
//-----------------------
424426
// EnableCloudTrailEncryption
@@ -600,6 +602,7 @@ export class RemediationRunbookStack extends cdk.Stack {
600602
],
601603
},
602604
};
605+
addCfnGuardSuppression(remediation_role, 'IAM_NO_INLINE_POLICY_CHECK');
603606

604607
new SsmRole(props.roleStack, 'RemediationRole ' + remediationName, {
605608
solutionId: props.solutionId,

source/lib/sns2-remediation-resources.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as cdk_nag from 'cdk-nag';
44
import * as cdk from 'aws-cdk-lib';
55
import { Effect, Policy, PolicyStatement, Role, ServicePrincipal, CfnRole } from 'aws-cdk-lib/aws-iam';
66
import { Construct } from 'constructs';
7+
import { addCfnGuardSuppression } from './cdk-helper/add-cfn-nag-suppression';
78

89
export interface ISNS2DeliveryStatusLoggingRole {
910
roleName: string;
@@ -66,5 +67,6 @@ export class SNS2DeliveryStatusLoggingRole extends Construct {
6667
],
6768
},
6869
};
70+
addCfnGuardSuppression(deliveryStatusLoggingRole, 'CFN_NO_EXPLICIT_RESOURCE_NAMES');
6971
}
7072
}

source/lib/solution_deploy-stack.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { OneTrigger } from './ssmplaybook';
2626
import { CloudWatchMetrics } from './cloudwatch_metrics';
2727
import { AdminPlaybook } from './admin-playbook';
2828
import { standardPlaybookProps, scPlaybookProps } from '../playbooks/playbook-index';
29+
import { addCfnGuardSuppression } from './cdk-helper/add-cfn-nag-suppression';
2930

3031
export interface SHARRStackProps extends cdk.StackProps {
3132
solutionId: string;
@@ -231,6 +232,7 @@ export class SolutionDeployStack extends cdk.Stack {
231232
},
232233
};
233234
}
235+
addCfnGuardSuppression(orchestratorRole, 'IAM_NO_INLINE_POLICY_CHECK');
234236

235237
/**
236238
* @description checkSSMDocState - get the status of an ssm document
@@ -768,6 +770,9 @@ export class SolutionDeployStack extends cdk.Stack {
768770
timeToLiveAttribute: 'TTL',
769771
});
770772

773+
addCfnGuardSuppression(schedulingTable, 'DYNAMODB_BILLING_MODE_RULE');
774+
addCfnGuardSuppression(schedulingTable, 'DYNAMODB_TABLE_ENCRYPTED_KMS');
775+
771776
const schedulingLamdbdaPolicy = new Policy(this, 'SchedulingLambdaPolicy', {
772777
policyName: RESOURCE_PREFIX + '-SHARR_Scheduling_Lambda',
773778
statements: [
@@ -825,6 +830,8 @@ export class SolutionDeployStack extends cdk.Stack {
825830
orchStateMachine.grantTaskResponse(schedulingLambdaTrigger);
826831
schedulingTable.grantReadWriteData(schedulingLambdaTrigger);
827832

833+
addCfnGuardSuppression(schedulingLambdaTrigger, 'LAMBDA_INSIDE_VPC');
834+
828835
schedulingLambdaTrigger.addEventSource(eventSource);
829836

830837
const cloudWatchMetrics = new CloudWatchMetrics(this, {
@@ -873,6 +880,9 @@ export class SolutionDeployStack extends cdk.Stack {
873880
layers: [sharrLambdaLayer],
874881
});
875882

883+
addCfnGuardSuppression(customResourceFunction, 'LAMBDA_INSIDE_VPC');
884+
addCfnGuardSuppression(customResourceFunction, 'LAMBDA_CONCURRENCY_CHECK');
885+
876886
new cdk.CustomResource(this, `ASR-DeploymentMetricsCustomResource`, {
877887
resourceType: 'Custom::DeploymentMetrics',
878888
serviceToken: customResourceFunction.functionArn,
@@ -891,6 +901,8 @@ export class SolutionDeployStack extends cdk.Stack {
891901
],
892902
true,
893903
);
904+
addCfnGuardSuppression(customResourceLambdaRole, 'IAM_NO_INLINE_POLICY_CHECK');
905+
addCfnGuardSuppression(customResourceLambdaRole, 'IAM_POLICYDOCUMENT_NO_WILDCARD_RESOURCE');
894906

895907
const sortedPlaybookNames = [...securityStandardPlaybookNames].sort();
896908

source/lib/wait-provider.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
66
import { Bucket } from 'aws-cdk-lib/aws-s3';
77
import { NagSuppressions } from 'cdk-nag';
88
import { Construct } from 'constructs';
9+
import { addCfnGuardSuppression } from './cdk-helper/add-cfn-nag-suppression';
910

1011
export interface WaitProviderProps {
1112
readonly serviceToken: string;
@@ -67,6 +68,8 @@ export class WaitProvider extends Construct {
6768
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
6869
inlinePolicies: { LambdaPolicy: policyDocument },
6970
});
71+
addCfnGuardSuppression(role, 'IAM_NO_INLINE_POLICY_CHECK');
72+
addCfnGuardSuppression(role, 'IAM_POLICYDOCUMENT_NO_WILDCARD_RESOURCE');
7073

7174
NagSuppressions.addResourceSuppressions(role, [
7275
{
@@ -87,6 +90,8 @@ export class WaitProvider extends Construct {
8790
environment: { LOG_LEVEL: 'INFO' },
8891
timeout: Duration.minutes(15),
8992
});
93+
addCfnGuardSuppression(lambdaFunction, 'LAMBDA_CONCURRENCY_CHECK');
94+
addCfnGuardSuppression(lambdaFunction, 'LAMBDA_INSIDE_VPC');
9095

9196
return new WaitProvider(scope, id, { serviceToken: lambdaFunction.functionArn });
9297
}

source/package-lock.json

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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": "2.1.3",
3+
"version": "2.1.4",
44
"description": "Automated remediation for AWS Security Hub (SO0111)",
55
"bin": {
66
"solution_deploy": "bin/solution_deploy.js"

source/test/__snapshots__/orchestrator.test.ts.snap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@ exports[`test App Orchestrator Construct 1`] = `
178178
},
179179
],
180180
},
181+
"guard": {
182+
"SuppressedRules": [
183+
"IAM_NO_INLINE_POLICY_CHECK",
184+
],
185+
},
181186
},
182187
"Properties": {
183188
"AssumeRolePolicyDocument": {

source/test/__snapshots__/runbook_stack.test.ts.snap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ exports[`Global Roles Stack 1`] = `
2525
},
2626
],
2727
},
28+
"guard": {
29+
"SuppressedRules": [
30+
"IAM_NO_INLINE_POLICY_CHECK",
31+
],
32+
},
2833
},
2934
"Properties": {
3035
"AssumeRolePolicyDocument": {

0 commit comments

Comments
 (0)