From c1883c9e624dacabc4ec347db50d9b860a6d4f40 Mon Sep 17 00:00:00 2001 From: Milan Gyalai Date: Mon, 13 May 2024 20:37:57 +0200 Subject: [PATCH] feat: allow disabling resource providers --- .../src/code-pipeline/AppStage.ts | 2 +- .../resource-providers/DisabledProvider.ts | 14 +++++++++ .../src/resource-providers/VPCProvider.ts | 2 +- .../src/stacks/PipelineBlueprint.ts | 7 +++++ .../src/stacks/PipelineStack.ts | 2 +- .../cdk-cicd-wrapper/src/stacks/VPCStack.ts | 4 +-- .../cdk-cicd-wrapper/src/utils/aspects.ts | 6 ++-- .../stacks/PipelineBlueprintStack.test.ts | 31 ++++++++++++++++++- 8 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 packages/@cdklabs/cdk-cicd-wrapper/src/resource-providers/DisabledProvider.ts diff --git a/packages/@cdklabs/cdk-cicd-wrapper/src/code-pipeline/AppStage.ts b/packages/@cdklabs/cdk-cicd-wrapper/src/code-pipeline/AppStage.ts index d5ed0d5..96355ad 100644 --- a/packages/@cdklabs/cdk-cicd-wrapper/src/code-pipeline/AppStage.ts +++ b/packages/@cdklabs/cdk-cicd-wrapper/src/code-pipeline/AppStage.ts @@ -46,7 +46,7 @@ export class AppStage extends cdk.Stage { const stage = context.stage; context._scoped(this, () => { - const complianceLogBucketName = context.get(GlobalResources.COMPLIANCE_BUCKET)!.bucketName; + const complianceLogBucketName = context.get(GlobalResources.COMPLIANCE_BUCKET)?.bucketName; const encryptionStack = context.get(GlobalResources.ENCRYPTION)!; diff --git a/packages/@cdklabs/cdk-cicd-wrapper/src/resource-providers/DisabledProvider.ts b/packages/@cdklabs/cdk-cicd-wrapper/src/resource-providers/DisabledProvider.ts new file mode 100644 index 0000000..88fed46 --- /dev/null +++ b/packages/@cdklabs/cdk-cicd-wrapper/src/resource-providers/DisabledProvider.ts @@ -0,0 +1,14 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { ResourceContext, IResourceProvider } from '../common'; + +export class DisabledProvider implements IResourceProvider { + constructor(readonly name: string) {} + + provide(_: ResourceContext): any { + console.warn(`The resource provider ${this.name} is disabled.`); + + return undefined; + } +} diff --git a/packages/@cdklabs/cdk-cicd-wrapper/src/resource-providers/VPCProvider.ts b/packages/@cdklabs/cdk-cicd-wrapper/src/resource-providers/VPCProvider.ts index f37e6a9..f1e7aab 100644 --- a/packages/@cdklabs/cdk-cicd-wrapper/src/resource-providers/VPCProvider.ts +++ b/packages/@cdklabs/cdk-cicd-wrapper/src/resource-providers/VPCProvider.ts @@ -90,7 +90,7 @@ export class VPCProvider implements IResourceProvider { return new VPCStack(scope, `${blueprintProps.applicationName}VPCStack`, { env: environment, vpcConfig: this.vpc, - flowLogsBucketName: context.get(GlobalResources.COMPLIANCE_BUCKET)!.bucketName, + flowLogsBucketName: context.get(GlobalResources.COMPLIANCE_BUCKET)?.bucketName, useProxy: context.has(GlobalResources.PROXY), }); } diff --git a/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/PipelineBlueprint.ts b/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/PipelineBlueprint.ts index b41c1ad..f162828 100644 --- a/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/PipelineBlueprint.ts +++ b/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/PipelineBlueprint.ts @@ -25,6 +25,7 @@ import { } from '../common'; import { CodeBuildFactoryProvider } from '../resource-providers/CodeBuildFactoryProvider'; import { ComplianceBucketConfigProvider } from '../resource-providers/ComplianceBucketProvider'; +import { DisabledProvider } from '../resource-providers/DisabledProvider'; import { EncryptionProvider } from '../resource-providers/EncryptionProvider'; import { ParameterProvider } from '../resource-providers/ParameterProvider'; import { PhaseCommandProvider, PhaseCommands } from '../resource-providers/PhaseCommandProvider'; @@ -224,6 +225,12 @@ export class PipelineBlueprintBuilder { return this; } + public disable(name: string): this { + this.props.resourceProviders![name] = new DisabledProvider(name); + + return this; + } + /** * Defines the stages for the Pipeline Blueprint. * @param stageDefinition An array of stage definitions or stage names. diff --git a/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/PipelineStack.ts b/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/PipelineStack.ts index b97a344..e13955a 100644 --- a/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/PipelineStack.ts +++ b/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/PipelineStack.ts @@ -36,7 +36,7 @@ export class PipelineStack extends PipelineBlueprintBase { this.resourceContext.get(GlobalResources.ENCRYPTION)!.kmsKey, Stage.RES, config.logRetentionInDays, - this.resourceContext.get(GlobalResources.COMPLIANCE_BUCKET)!.bucketName, + this.resourceContext.get(GlobalResources.COMPLIANCE_BUCKET)?.bucketName, ), ); diff --git a/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/VPCStack.ts b/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/VPCStack.ts index 6b889d8..3511208 100644 --- a/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/VPCStack.ts +++ b/packages/@cdklabs/cdk-cicd-wrapper/src/stacks/VPCStack.ts @@ -26,7 +26,7 @@ export interface VPCStackProps extends cdk.StackProps { /** * The name of the S3 bucket for VPC flow logs. */ - readonly flowLogsBucketName: string; + readonly flowLogsBucketName?: string; } /** @@ -60,7 +60,7 @@ export class VPCStack extends cdk.Stack { const vpcFlowLogsDestinationS3 = aws_s3.Bucket.fromBucketName( this, 'VpcFlowLogsBucket', - props.flowLogsBucketName, + props.flowLogsBucketName!, ); this.vpc.addFlowLog('vpcFlowLogs', { destination: ec2.FlowLogDestination.toS3(vpcFlowLogsDestinationS3), diff --git a/packages/@cdklabs/cdk-cicd-wrapper/src/utils/aspects.ts b/packages/@cdklabs/cdk-cicd-wrapper/src/utils/aspects.ts index 0001c58..651d82f 100644 --- a/packages/@cdklabs/cdk-cicd-wrapper/src/utils/aspects.ts +++ b/packages/@cdklabs/cdk-cicd-wrapper/src/utils/aspects.ts @@ -18,7 +18,7 @@ export class SecurityControls implements IAspect { private encryptionKey: aws_kms.Key; private readonly stage: string; private readonly logRetentionInDays: string; - private readonly complianceLogBucketName: string; + private readonly complianceLogBucketName?: string; /** * Constructs a new instance of SecurityControls. @@ -28,7 +28,7 @@ export class SecurityControls implements IAspect { * @param logRetentionInDays The number of days to retain logs. * @param complianceLogBucketName The name of the S3 bucket for compliance logs. */ - constructor(kmsKey: aws_kms.Key, stage: string, logRetentionInDays: string, complianceLogBucketName: string) { + constructor(kmsKey: aws_kms.Key, stage: string, logRetentionInDays: string, complianceLogBucketName?: string) { this.encryptionKey = kmsKey; this.stage = stage; this.logRetentionInDays = logRetentionInDays; @@ -47,7 +47,7 @@ export class SecurityControls implements IAspect { node.retentionInDays = Number(this.logRetentionInDays); node.kmsKeyId = this.encryptionKey.keyArn; } - } else if (node instanceof CfnBucket) { + } else if (node instanceof CfnBucket && this.complianceLogBucketName) { // Configure S3 bucket logging node.loggingConfiguration = { destinationBucketName: this.complianceLogBucketName, diff --git a/packages/@cdklabs/cdk-cicd-wrapper/test/stacks/PipelineBlueprintStack.test.ts b/packages/@cdklabs/cdk-cicd-wrapper/test/stacks/PipelineBlueprintStack.test.ts index 0236f25..64e1661 100644 --- a/packages/@cdklabs/cdk-cicd-wrapper/test/stacks/PipelineBlueprintStack.test.ts +++ b/packages/@cdklabs/cdk-cicd-wrapper/test/stacks/PipelineBlueprintStack.test.ts @@ -4,7 +4,7 @@ import * as cdk from 'aws-cdk-lib'; import { Annotations, Match, Template } from 'aws-cdk-lib/assertions'; import { AwsSolutionsChecks } from 'cdk-nag'; -import { Stage, PipelinePhases } from '../../src/common'; +import { Stage, PipelinePhases, GlobalResources } from '../../src/common'; import { BasicRepositoryProvider, sh } from '../../src/resource-providers'; import { PipelineBlueprint } from '../../src/stacks/PipelineBlueprint'; import { TestAppConfig, TestRepositoryConfigCodeCommit, TestRepositoryConfigGithub } from '../TestConfig'; @@ -369,3 +369,32 @@ describe('pipeline-stack-test-proxy-vpc', () => { }).test(synthProject.Properties as any); }); }); + +describe('pipeline-stack-disable-compliance-log-bucket', () => { + const app = new cdk.App(); + + const template = Template.fromStack( + PipelineBlueprint.builder() + .applicationName(TestAppConfig.applicationName) + .applicationQualifier(TestAppConfig.applicationQualifier) + .defineStages([ + { stage: Stage.RES, ...TestAppConfig.deploymentDefinition.RES.env }, + { stage: Stage.DEV, ...TestAppConfig.deploymentDefinition.DEV.env }, + { stage: Stage.INT, ...TestAppConfig.deploymentDefinition.INT.env }, + ]) + .disable(GlobalResources.COMPLIANCE_BUCKET) + .repositoryProvider(new BasicRepositoryProvider(TestRepositoryConfigGithub)) + .synth(app), + ); + + test("Check if CodePipeline Pipeline doesn't have a compliance bucket", () => { + template.resourceCountIs('AWS::CodePipeline::Pipeline', 1); + template.resourcePropertiesCountIs( + 'AWS::S3::Bucket', + { + LoggingConfiguration: {}, + }, + 0, + ); + }); +});