Skip to content

Commit cea5fe1

Browse files
feat(core): Config Rules Remediation (#536)
* feat(core): Config Rules Remediation * Adding remediation for S3PutEncryption with KMS Key Alias * Prettier * Updating configuration for "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED" Config rule
1 parent 47cd70b commit cea5fe1

File tree

4 files changed

+112
-42
lines changed

4 files changed

+112
-42
lines changed

reference-artifacts/config.example.json

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,11 @@
491491
"name": "SSM-ELB-Enable-Logging",
492492
"description": "Calls the AWS CLI to enable access logs on a specified ELB.",
493493
"template": "ssm-elb-enable-logging.yaml"
494+
},
495+
{
496+
"name": "Put-S3-Encryption",
497+
"description": "Enables S3 encryption using KMS",
498+
"template": "s3-encryption.yaml"
494499
}
495500
]
496501
}
@@ -515,6 +520,14 @@
515520
"LoadBalancerArn": "RESOURCE_ID",
516521
"LogDestination": "${SEA::LogArchiveAesBucket}"
517522
}
523+
},
524+
{
525+
"name": "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED",
526+
"remediation-action": "Put-S3-Encryption",
527+
"remediation-params": {
528+
"BucketName": "RESOURCE_ID",
529+
"KMSMasterKey": "${SEA::S3BucketEncryptionKey}"
530+
}
518531
}
519532
]
520533
}
@@ -1658,13 +1671,13 @@
16581671
{
16591672
"account": "operations",
16601673
"regions": ["ca-central-1"],
1661-
"documents": ["SSM-ELB-Enable-Logging"]
1674+
"documents": ["SSM-ELB-Enable-Logging", "Put-S3-Encryption"]
16621675
}
16631676
],
16641677
"aws-config": [
16651678
{
16661679
"excl-regions": [],
1667-
"rules": ["ELB_LOGGING_ENABLED"],
1680+
"rules": ["ELB_LOGGING_ENABLED", "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"],
16681681
"remediate-regions": ["ca-central-1"]
16691682
}
16701683
]
@@ -2118,13 +2131,13 @@
21182131
{
21192132
"account": "operations",
21202133
"regions": ["ca-central-1"],
2121-
"documents": ["SSM-ELB-Enable-Logging"]
2134+
"documents": ["SSM-ELB-Enable-Logging", "Put-S3-Encryption"]
21222135
}
21232136
],
21242137
"aws-config": [
21252138
{
21262139
"excl-regions": [],
2127-
"rules": ["ELB_LOGGING_ENABLED"],
2140+
"rules": ["ELB_LOGGING_ENABLED", "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"],
21282141
"remediate-regions": ["ca-central-1"]
21292142
}
21302143
]
@@ -2605,13 +2618,13 @@
26052618
{
26062619
"account": "operations",
26072620
"regions": ["ca-central-1"],
2608-
"documents": ["SSM-ELB-Enable-Logging"]
2621+
"documents": ["SSM-ELB-Enable-Logging", "Put-S3-Encryption"]
26092622
}
26102623
],
26112624
"aws-config": [
26122625
{
26132626
"excl-regions": [],
2614-
"rules": ["ELB_LOGGING_ENABLED"],
2627+
"rules": ["ELB_LOGGING_ENABLED", "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"],
26152628
"remediate-regions": ["ca-central-1"]
26162629
}
26172630
]
@@ -3092,13 +3105,13 @@
30923105
{
30933106
"account": "operations",
30943107
"regions": ["ca-central-1"],
3095-
"documents": ["SSM-ELB-Enable-Logging"]
3108+
"documents": ["SSM-ELB-Enable-Logging", "Put-S3-Encryption"]
30963109
}
30973110
],
30983111
"aws-config": [
30993112
{
31003113
"excl-regions": [],
3101-
"rules": ["ELB_LOGGING_ENABLED"],
3114+
"rules": ["ELB_LOGGING_ENABLED", "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"],
31023115
"remediate-regions": ["ca-central-1"]
31033116
}
31043117
]
@@ -3579,13 +3592,13 @@
35793592
{
35803593
"account": "operations",
35813594
"regions": ["ca-central-1"],
3582-
"documents": ["SSM-ELB-Enable-Logging"]
3595+
"documents": ["SSM-ELB-Enable-Logging", "Put-S3-Encryption"]
35833596
}
35843597
],
35853598
"aws-config": [
35863599
{
35873600
"excl-regions": [],
3588-
"rules": ["ELB_LOGGING_ENABLED"],
3601+
"rules": ["ELB_LOGGING_ENABLED", "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"],
35893602
"remediate-regions": ["ca-central-1"]
35903603
}
35913604
]
@@ -4033,13 +4046,13 @@
40334046
{
40344047
"account": "operations",
40354048
"regions": ["ca-central-1"],
4036-
"documents": ["SSM-ELB-Enable-Logging"]
4049+
"documents": ["SSM-ELB-Enable-Logging", "Put-S3-Encryption"]
40374050
}
40384051
],
40394052
"aws-config": [
40404053
{
40414054
"excl-regions": [],
4042-
"rules": ["ELB_LOGGING_ENABLED"],
4055+
"rules": ["ELB_LOGGING_ENABLED", "S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"],
40434056
"remediate-regions": ["ca-central-1"]
40444057
}
40454058
]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
description: Enables Encryption on S3 Bucket
2+
schemaVersion: "0.3"
3+
assumeRole: "{{ AutomationAssumeRole }}"
4+
parameters:
5+
BucketName:
6+
type: String
7+
description: (Required) The name of the S3 Bucket whose content will be encrypted.
8+
KMSMasterKey:
9+
type: String
10+
description: (Optional) AWS Key Management Service (KMS) customer master key ARN to use for the default encryption.
11+
AutomationAssumeRole:
12+
type: String
13+
description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
14+
default: ""
15+
mainSteps:
16+
- name: PutBucketEncryption
17+
action: aws:executeAwsApi
18+
inputs:
19+
Service: s3
20+
Api: PutBucketEncryption
21+
Bucket: "{{BucketName}}"
22+
ServerSideEncryptionConfiguration:
23+
Rules:
24+
-
25+
ApplyServerSideEncryptionByDefault:
26+
SSEAlgorithm: "aws:kms"
27+
KMSMasterKeyID: "{{KMSMasterKey}}"
28+
isEnd: true

src/deployments/cdk/src/apps/phase-3.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,10 @@ export async function deploy({ acceleratorConfig, accountStacks, accounts, conte
130130

131131
await awsConfig.createRule({
132132
acceleratorExecutionRoleName: context.acceleratorExecutionRoleName,
133-
centralAccountId: '',
134-
centralBucketName: centralBucket.bucketName,
135133
config: acceleratorConfig,
136134
accountStacks,
137135
accounts,
138136
outputs,
137+
defaultRegion: context.defaultRegion,
139138
});
140139
}

src/deployments/cdk/src/deployments/config/create.ts

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,24 @@ import { createName } from '@aws-accelerator/cdk-accelerator/src/core/accelerato
55
import * as awsConfig from '@aws-cdk/aws-config';
66
import { Account, getAccountId } from '../../utils/accounts';
77
import { StackOutput } from '@aws-accelerator/common-outputs/src/stack-output';
8-
import { LogBucketOutput } from '../defaults/outputs';
8+
import { LogBucketOutput, AccountBucketOutputFinder } from '../defaults/outputs';
99

1010
export interface CreateRuleProps {
1111
acceleratorExecutionRoleName: string;
12-
centralBucketName: string;
13-
centralAccountId: string;
1412
config: c.AcceleratorConfig;
1513
accountStacks: AccountStacks;
1614
accounts: Account[];
1715
outputs: StackOutput[];
16+
defaultRegion: string;
1817
}
1918

2019
export async function createRule(props: CreateRuleProps) {
21-
const {
22-
acceleratorExecutionRoleName,
23-
config,
24-
centralAccountId,
25-
centralBucketName,
26-
accountStacks,
27-
accounts,
28-
outputs,
29-
} = props;
20+
const { acceleratorExecutionRoleName, config, accountStacks, accounts, outputs, defaultRegion } = props;
3021
const awsConfigConf = config['global-options']['aws-config'];
3122
if (!awsConfigConf) {
3223
return;
3324
}
25+
3426
const configRules = awsConfigConf['managed-rules'].rules;
3527
const configRuleDefaults = awsConfigConf['managed-rules'].defaults;
3628

@@ -82,6 +74,8 @@ export async function createRule(props: CreateRuleProps) {
8274
ruleParams: awsConfigRule.parameters,
8375
config,
8476
outputs,
77+
accountKey,
78+
defaultRegion,
8579
});
8680
const configRule = new awsConfig.ManagedRule(accountStack, `ConfigRule-${ruleName}`, {
8781
identifier: ruleName,
@@ -126,8 +120,12 @@ export async function createRule(props: CreateRuleProps) {
126120
accounts,
127121
ssmDocInOu.account,
128122
)}:document/${remediationActionName}`;
123+
} else if (config['global-options']['default-ssm-documents'].includes(remediationAction)) {
124+
targetId = remediationAction;
129125
} else {
130-
console.warn(`No Remediation is Created in account "${accountKey}" and region "${region}"`);
126+
console.warn(
127+
`No Remediation "${remediationAction}"is Created in account "${accountKey}" and region "${region}"`,
128+
);
131129
continue;
132130
}
133131
}
@@ -147,6 +145,8 @@ export async function createRule(props: CreateRuleProps) {
147145
remediationParams: awsConfigRule['remediation-params'],
148146
roleName: acceleratorExecutionRoleName,
149147
config,
148+
accountKey,
149+
defaultRegion,
150150
});
151151

152152
new awsConfig.CfnRemediationConfiguration(accountStack, `ConfigRuleRemediation-${ruleName}`, {
@@ -181,19 +181,18 @@ export function getRemediationParameters(params: {
181181
roleName: string;
182182
outputs: StackOutput[];
183183
config: c.AcceleratorConfig;
184+
accountKey: string;
185+
defaultRegion: string;
184186
}): RemediationParameters {
185187
const reutrnParams: RemediationParameters = {};
186-
const { outputs, remediationParams, roleName, config } = params;
187-
if (!remediationParams.AutomationAssumeRole) {
188-
reutrnParams.AutomationAssumeRole = {
189-
StaticValue: {
190-
Values: [`arn:aws:iam::${cdk.Aws.ACCOUNT_ID}:role/${roleName}`],
191-
},
192-
};
193-
}
188+
const { outputs, remediationParams, roleName, config, accountKey, defaultRegion } = params;
189+
reutrnParams.AutomationAssumeRole = {
190+
StaticValue: {
191+
Values: [`arn:aws:iam::${cdk.Aws.ACCOUNT_ID}:role/${remediationParams.AutomationAssumeRole || roleName}`],
192+
},
193+
};
194194

195195
Object.keys(remediationParams).map(key => {
196-
console.log(remediationParams[key], remediationParams[key].startsWith('${SEA::'));
197196
if (remediationParams[key] === 'RESOURCE_ID') {
198197
reutrnParams[key] = {
199198
ResourceValue: {
@@ -212,11 +211,19 @@ export function getRemediationParameters(params: {
212211
const replaceKey = remediationParams[key].match('{SEA::(.*)}')?.[1]!;
213212
reutrnParams[key] = {
214213
StaticValue: {
215-
Values: [getParameterValue(replaceKey, outputs, config)],
214+
Values: [
215+
getParameterValue({
216+
paramKey: replaceKey,
217+
outputs,
218+
config,
219+
accountKey,
220+
defaultRegion,
221+
}),
222+
],
216223
},
217224
};
218225
} else {
219-
reutrnParams.AutomationAssumeRole = {
226+
reutrnParams[key] = {
220227
StaticValue: {
221228
Values: [remediationParams[key]],
222229
},
@@ -232,23 +239,46 @@ export function getConfigRuleParameters(params: {
232239
ruleParams: { [key: string]: string };
233240
outputs: StackOutput[];
234241
config: c.AcceleratorConfig;
242+
accountKey: string;
243+
defaultRegion: string;
235244
}): { [key: string]: string } {
236-
const { config, outputs, ruleParams } = params;
245+
const { config, outputs, ruleParams, accountKey, defaultRegion } = params;
237246
Object.keys(ruleParams).map(key => {
238247
if (ruleParams[key].startsWith('${SEA::')) {
239248
const replaceKey = ruleParams[key].match('{SEA::(.*)}')?.[1]!;
240-
ruleParams[key] = getParameterValue(replaceKey, outputs, config);
249+
ruleParams[key] = getParameterValue({
250+
paramKey: replaceKey,
251+
outputs,
252+
config,
253+
accountKey,
254+
defaultRegion,
255+
});
241256
}
242257
});
243258
return ruleParams;
244259
}
245260

246-
export function getParameterValue(input: string, outputs: StackOutput[], config: c.AcceleratorConfig): string {
247-
if (input === 'LogArchiveAesBucket') {
261+
export function getParameterValue(props: {
262+
paramKey: string;
263+
outputs: StackOutput[];
264+
config: c.AcceleratorConfig;
265+
accountKey: string;
266+
defaultRegion: string;
267+
}): string {
268+
const { accountKey, config, outputs, paramKey, defaultRegion } = props;
269+
if (paramKey === 'LogArchiveAesBucket') {
248270
return LogBucketOutput.getBucketDetails({
249271
config,
250272
outputs,
251273
}).name;
252274
}
275+
if (paramKey === 'S3BucketEncryptionKey') {
276+
const accountBucket = AccountBucketOutputFinder.tryFindOne({
277+
outputs,
278+
accountKey,
279+
region: defaultRegion,
280+
});
281+
return `arn:aws:kms:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:alias/${accountBucket?.encryptionKeyName}`;
282+
}
253283
return '';
254284
}

0 commit comments

Comments
 (0)