From a08ddb20f4ccfcfeb407fb3b0c16720b27d2f579 Mon Sep 17 00:00:00 2001 From: Aliaksei Ivanou Date: Wed, 15 May 2024 15:08:56 -0700 Subject: [PATCH] Moving to async buildConfigStack --- lib/security/eks-config-rules/config-setup.ts | 246 +++++++++--------- 1 file changed, 126 insertions(+), 120 deletions(-) diff --git a/lib/security/eks-config-rules/config-setup.ts b/lib/security/eks-config-rules/config-setup.ts index 69247539..c55867ef 100644 --- a/lib/security/eks-config-rules/config-setup.ts +++ b/lib/security/eks-config-rules/config-setup.ts @@ -19,132 +19,138 @@ import { export class EksConfigSetup extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); + this.buildConfigStack(); + } + async buildConfigStack() { const email = "your-email@example.com"; - const logger = blueprints.utils.logger; - - (async () => { - const currentRegion = process.env.CDK_DEFAULT_REGION!; - const configclient = new ConfigServiceClient(); - - try { - const command = new DescribeConfigurationRecordersCommand(); - const response = await configclient.send(command); - - if (response.ConfigurationRecorders && response.ConfigurationRecorders.length > 0) { - logger.info(`AWS Config is already enabled in ${currentRegion} region.`); - } else { - logger.info(`AWS Config is not enabled in ${currentRegion} region.`); - logger.info("Enabling AWS Config..."); - - // Create an AWS Config service role - const awsConfigRole = new iam.Role(this, "RoleAwsConfig", { - assumedBy: new iam.ServicePrincipal("config.amazonaws.com"), - }); - - // Attach the service role policy - awsConfigRole.addManagedPolicy( - iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWS_ConfigRole") - ); - - // Check if delivery channel is already enabled - try { - const command = new DescribeDeliveryChannelsCommand(); - const response = await configclient.send(command); - - if (response.DeliveryChannels && response.DeliveryChannels.length > 0) { - logger.info(`AWS Config delivery channel is already enabled in ${currentRegion} region.`); - } else { - logger.info(`AWS Config delivery channel is not enabled in ${currentRegion} region.`); - logger.info("Configuring AWS Config delivery channel..."); - - // Create an AWS Config delivery channel - // Setup an s3 bucket for the config recorder delivery channel - const awsConfigBucket = new s3.Bucket(this, "BucketAwsConfig", { - versioned: true, enforceSSL: true, - }); - - // Configure bucket policy statements and attach them to the s3 bucket - const policyStatement1 = new iam.PolicyStatement({ - actions: ["s3:*"], - principals: [new iam.AnyPrincipal()], - resources: [`${awsConfigBucket.bucketArn}/*`], - conditions: { Bool: { "aws:SecureTransport": false } }, - }); - - policyStatement1.effect = iam.Effect.DENY; - awsConfigBucket.addToResourcePolicy(policyStatement1); - - const policyStatement2 = new iam.PolicyStatement({ - actions: ["s3:PutObject"],// - - principals: [new iam.ServicePrincipal("config.amazonaws.com")], - resources: [`${awsConfigBucket.bucketArn}/*`], - conditions: { - StringEquals: { "s3:x-amz-acl": "bucket-owner-full-control" }, - }, - }); - - policyStatement2.effect = iam.Effect.ALLOW; - awsConfigBucket.addToResourcePolicy(policyStatement2); - - const policyStatement3 = new iam.PolicyStatement({ - actions: ["s3:GetBucketAcl"], - principals: [new iam.ServicePrincipal("config.amazonaws.com")], - resources: [awsConfigBucket.bucketArn], - }); - - policyStatement3.effect = iam.Effect.ALLOW; - awsConfigBucket.addToResourcePolicy(policyStatement3); - - // Create an SNS topic for AWS Config notifications - const configTopic = new sns.Topic(this, "ConfigNotificationTopic"); - configTopic.addSubscription(new subs.EmailSubscription(email)); - const eventRule = new events.Rule(this, "ConfigEventRule", { - eventPattern: { - source: ["aws.config"], - detailType: ["Config Rules Compliance Change"], - }, - }); - - // Format the Config notifications - eventRule.addTarget( - new eventTargets.SnsTopic(configTopic, { - message: events.RuleTargetInput.fromText( - `WARNING: AWS Config has detected a ${events.EventField.fromPath( - "$.detail.newEvaluationResult.complianceType" - )} for the rule ${events.EventField.fromPath( - "$.detail.configRuleName" - )}. The compliance status is ${events.EventField.fromPath( - "$.detail.newEvaluationResult.evaluationResult" - )}.` - ), - }) - ); - - // Create the AWS Config delivery channel with the s3 bucket and sns topic - new config.CfnDeliveryChannel(this, "DeliveryChannel", { - name: "default", - s3BucketName: awsConfigBucket.bucketName, - snsTopicArn: configTopic.topicArn, - }); - } - } catch (error) { - logger.error(error); + const currentRegion = process.env.CDK_DEFAULT_REGION!; + const configclient = new ConfigServiceClient(); + + try { + const command = new DescribeConfigurationRecordersCommand(); + const response = await configclient.send(command); + + if (response.ConfigurationRecorders && response.ConfigurationRecorders.length > 0) { + logger.info(`AWS Config is already enabled in ${currentRegion} region.`); + } else { + logger.info(`AWS Config is not enabled in ${currentRegion} region.`); + logger.info("Enabling AWS Config..."); + + // Create an AWS Config service role + const awsConfigRole = new iam.Role(this, "RoleAwsConfig", { + assumedBy: new iam.ServicePrincipal("config.amazonaws.com"), + }); + + // Attach the service role policy + awsConfigRole.addManagedPolicy( + iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWS_ConfigRole") + ); + + // Check if delivery channel is already enabled + try { + const command = new DescribeDeliveryChannelsCommand(); + const response = await configclient.send(command); + + if (response.DeliveryChannels && response.DeliveryChannels.length > 0) { + logger.info(`AWS Config delivery channel is already enabled in ${currentRegion} region.`); + } else { + logger.info(`AWS Config delivery channel is not enabled in ${currentRegion} region.`); + logger.info("Configuring AWS Config delivery channel..."); + + // Create an AWS Config delivery channel + // Setup an s3 bucket for the config recorder delivery channel + const awsConfigBucket = new s3.Bucket(this, "BucketAwsConfig", { + versioned: true, enforceSSL: true, + }); + + // Configure bucket policy statements and attach them to the s3 bucket + this.configureS3BucketPolicy(awsConfigBucket); + + // Create an SNS topic for AWS Config notifications + const configTopic = new sns.Topic(this, "ConfigNotificationTopic"); + configTopic.addSubscription(new subs.EmailSubscription(email)); + const eventRule = new events.Rule(this, "ConfigEventRule", { + eventPattern: { + source: ["aws.config"], + detailType: ["Config Rules Compliance Change"], + }, + }); + + // Format the Config notifications + this.configureEventRule(eventRule, configTopic); + + // Create the AWS Config delivery channel with the s3 bucket and sns topic + new config.CfnDeliveryChannel(this, "DeliveryChannel", { + name: "default", + s3BucketName: awsConfigBucket.bucketName, + snsTopicArn: configTopic.topicArn, + }); } + } catch (error) { + logger.error(error); + } - logger.info("Configuring AWS Config recorder..."); + logger.info("Configuring AWS Config recorder..."); - // Create the AWS Config recorder - new config.CfnConfigurationRecorder(this, "Recorder", { - name: "default", - roleArn: awsConfigRole.roleArn, - }); - } - } catch (error) { - logger.error(error); + // Create the AWS Config recorder + new config.CfnConfigurationRecorder(this, "Recorder", { + name: "default", + roleArn: awsConfigRole.roleArn, + }); } - })(); + } catch (error) { + logger.error(error); + } + } + + private configureS3BucketPolicy(awsConfigBucket: s3.Bucket) { + const policyStatement1 = new iam.PolicyStatement({ + actions: ["s3:*"], + principals: [new iam.AnyPrincipal()], + resources: [`${awsConfigBucket.bucketArn}/*`], + conditions: { Bool: { "aws:SecureTransport": false } }, + }); + + policyStatement1.effect = iam.Effect.DENY; + awsConfigBucket.addToResourcePolicy(policyStatement1); + + const policyStatement2 = new iam.PolicyStatement({ + actions: ["s3:PutObject"], + principals: [new iam.ServicePrincipal("config.amazonaws.com")], + resources: [`${awsConfigBucket.bucketArn}/*`], + conditions: { + StringEquals: { "s3:x-amz-acl": "bucket-owner-full-control" }, + }, + }); + + policyStatement2.effect = iam.Effect.ALLOW; + awsConfigBucket.addToResourcePolicy(policyStatement2); + + const policyStatement3 = new iam.PolicyStatement({ + actions: ["s3:GetBucketAcl"], + principals: [new iam.ServicePrincipal("config.amazonaws.com")], + resources: [awsConfigBucket.bucketArn], + }); + + policyStatement3.effect = iam.Effect.ALLOW; + awsConfigBucket.addToResourcePolicy(policyStatement3); + } + + private configureEventRule(eventRule: events.Rule, configTopic: sns.Topic) { + eventRule.addTarget( + new eventTargets.SnsTopic(configTopic, { + message: events.RuleTargetInput.fromText( + `WARNING: AWS Config has detected a ${events.EventField.fromPath( + "$.detail.newEvaluationResult.complianceType" + )} for the rule ${events.EventField.fromPath( + "$.detail.configRuleName" + )}. The compliance status is ${events.EventField.fromPath( + "$.detail.newEvaluationResult.evaluationResult" + )}.` + ), + }) + ); } }