AWS Cloud Operations Blog

Accelerating development with AWS CDK plugin – CfnGuardValidator

Customers can incorporate the CfnGuardValidator plugin into their AWS Cloud Development Kit (AWS CDK) application to accelerate their application development process. This acceleration stems from ensuring that the deployed resources comply with both organizational policy and AWS best practices. Without the plugin, however, ensuing policy compliance can often be an iterative process. Organizations may implement detective controls with AWS CloudFormation Guard or tools like AWS CloudFormation Linter to detect non-compliant changes; at other times, it is on developers to manually observe and make sure that the resources are securely configured. In either case, this process often results in a long turnaround time. Developers frequently find themselves waiting for the organizational deployment pipeline to process, or they end up deploying resources multiple times to achieve the correct configuration, which slows down the development cycle.

CfnGuardValidator is an AWS CDK plugin that allows developers to locally validate their AWS CDK code using AWS Control Tower proactive controls or AWS CloudFormation Guard rules before deploying the AWS infrastructure. This capability provides developers with fast and actionable feedback about security or configuration issues, thus reducing the manual errors during the deployment process, as well as increasing the success rate during the deployment pipeline.

In this blog post, you will learn how to integrate the CfnGuardValidator plugin into your existing AWS CDK application and validate it against organizational policies to accelerate your development process.

Overview of CfnGuardValidator

CfnGuardValidator provides developers a way to utilize AWS CloudFormation Guard rules for evaluating their CDK applications. AWS CloudFormation Guard is an open-source, general-purpose, policy-as-code evaluation tool. AWS CloudFormation Guard rules, written in domain-specific language (DSL), can only be validated against JSON- or YAML-formatted data.

Note: the APIs of higher-level constructs in this plugin are experimental and under active development. This means that you may need to updated your source code when upgrading to a newer version of this package.

Traditionally, customers need to build specific invocation pipelines to validate their AWS CDK code against AWS CloudFormation Guard rules, or utilize an alternative evaluation technique such as CDK Aspects or cdk-nag. Now, when the CfnGuardValidator plugin is enabled, and the AWS CDK application has finished synthesizing AWS CloudFormation templates, validation against AWS CloudFormation Guard rules is triggered automatically.

Furthermore, a predefined set of AWS Control Tower proactive controls is included, and enabled by default with this plugin. During validation execution, this plugin generates a final report summarizing the validation outcome (success or failure), with details about any detected misconfigurations. If non-compliance is discovered in relation to a specific policy, the report will include a root-cause analysis and offers suggestions for mitigation. A snapshot of the output is presented below.

Sample of failed validation from the CfnGuardValidator plugin
Figure 1: Sample of failed validation from the CfnGuardValidator plugin

Walkthrough

In this section, you will follow the workflow depicted in Figure 2. You will use an AWS Cloud9 instance to simulate a local Integrated Development Environment (IDE). Subsequently, you will build a small AWS CDK V2 application, using TypeScript as the programming language. From there, you will integrate the CfnGuardValidator plugin with this application and configure the plugin to enable both AWS Control Tower proactive controls and custom AWS CloudFormation Guard rules.

Overall workflow for using CfnGuardValidator pluginFigure 2: Overall workflow for using CfnGuardValidator plugin

Prerequisites

For this walkthrough, you should have the following prerequisites:

Create a baseline AWS CDK application

In this section, you will create and synthesize a small AWS CDK V2 application with an Amazon Simple Storage Service (Amazon S3) bucket.

  1. Run the following bash commands inside the terminal of your AWS Cloud9 development environment. This creates a sample template for your AWS CDK application.
mkdir CdkApp && cd CdkApp
cdk init app --language typescript
  1. Replace the contents of the lib/cdk_app-stack.ts with the following code, which adds an Amazon S3 bucket as part of the AWS CDK application.
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Bucket } from 'aws-cdk-lib/aws-s3';

export class CdkAppStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const bucket = new Bucket(this, 'Bucket')
  }
}
  1. Run the following commands to install dependencies and synthesize our sample app:
npm install
cdk synth

You should see an AWS CloudFormation template in cdk.out/CdkAppStack.template.json.

Use CfnGuardValidator plugin in your CDK application

In this section, you will install CfnGuardValidator plugin, and enable this plugin in your AWS CDK application.

  1. Run the following command to install the plugin:
npm install @cdklabs/cdk-validator-cfnguard
  1. Replace the contents of the bin/cdk_app.ts with the following code. This enables by default all the bundled AWS Control Tower proactive controls.
#!/usr/bin/env node
import 'source-map-support/register';
import { App } from 'aws-cdk-lib';
import { CdkAppStack } from '../lib/cdk_app-stack';
import { CfnGuardValidator } from '@cdklabs/cdk-validator-cfnguard';

const app = new App({
  policyValidationBeta1: [
    new CfnGuardValidator()
  ]});

new CdkAppStack(app, 'CdkAppStack');
  1. Run the following command to view the output and generate report:
cdk synth

You should see a validation report with status “failure” and violations of different AWS Control Tower proactive controls. One sample control violation should be similar to below, which tells you our created Amazon S3 bucket is failing to configure bucket level block public access (BPA) setting, under control CT.S3.PR.1.

Output for control violation of S3 bucket failing to configure block public access (BPA)
Figure 3: Output for control violation of S3 bucket failing to configure block public access (BPA)

Remediation of error and disabling AWS Control Tower proactive controls

In this section, you will remediate the failing controls “CT.S3.PR1”, “CT.S3.PR3”, and “CT.S3.PR7”, by configuring S3 bucket level BPA, a simple lifecycle rule to transition objects to Amazon S3 Glacier after 90 days of creation, and the enablement of server-side encryption with Amazon S3 managed keys (SSE-S3). You will also disable the rest of the S3 control tower proactive controls for the simplicity of this setup.

Disabling certain validation controls as part of your AWS CDK application can be very useful, as this helps to build an exception list for specific projects or environments. For example, for Amazon S3 buckets within a sandbox environment used by developers for quick prototyping, setting Amazon S3 object lock in control “CT.S3.PR.4” may not be the best fit. Thus, curating an exception list can help to reduces false positives in the overall evaluation.

Follow the procedures below to disable controls and remediate evaluation errors:

  1. Replace the contents of the bin/cdk_app.ts with the following code. This disables requirements such as server access logging, Amazon S3 event notification, etc.
#!/usr/bin/env node
import 'source-map-support/register';
import { App } from 'aws-cdk-lib';
import { CdkAppStack } from '../lib/cdk_app-stack';
import { CfnGuardValidator } from '@cdklabs/cdk-validator-cfnguard';

const app = new App({
  policyValidationBeta1: [
    new CfnGuardValidator({
      disabledRules: [
        'ct-s3-pr-2',  /* server access logging */
        'ct-s3-pr-4',  /* s3 event notification */
        'ct-s3-pr-9',  /* s3 object lock */
        'ct-s3-pr-10', /* s3 SSE-KMS encryption */
        'ct-s3-pr-11'  /* s3 versioning */
      ]
    })
  ]});

new CdkAppStack(app, 'CdkAppStack');
  1. Replace the contents of the lib/cdk_app-stack.ts with the following code. In this code, we block Amazon S3 public access, enable encryption using SSE-S3, and configure a lifecycle rule to transition Amazon S3 objects to Amazon S3 Glacier after 90 days of creation.
import { Stack, StackProps, Duration } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Bucket, BlockPublicAccess, BucketEncryption, StorageClass} from 'aws-cdk-lib/aws-s3';

export class CdkAppStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const bucket = new Bucket(this, 'Bucket',{
      blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
      encryption: BucketEncryption.S3_MANAGED,
      lifecycleRules: [{
        transitions: [{
          storageClass: StorageClass.GLACIER,
          transitionAfter: Duration.days(90),
        }]
      }]
    });
  }
}
  1. Run cdk synth command to view the output and generate report. You should see policy validation with status of “success” and a copy of the synthesized CloudFormation template.
Sample of successful validation from the CfnGuardValidator plugin
Figure 4: Sample of successful validation from the CfnGuardValidator plugin

Applying custom AWS CloudFormation Guard rules

In this section, you would like to enforce S3 bucket versioning using a custom Guard rule that is pulled from the aws-guard-rules-registry. This registry is an open-source repository of AWS Guard rule files and managed rule sets that can help organizations shift left in the Software Development Life Cycle (SDLC) process.

  1. Run the following command to download the Guard file that checks S3 bucket versioning.
curl -O https://raw.githubusercontent.com/aws-cloudformation/aws-guard-rules-registry/main/rules/aws/amazon_s3/s3_bucket_versioning_enabled.guard
  1. Replace the contents of the bin/cdk_app.ts with the following code. This enables CfnGuardValidator plugin to adopt additional rules.
#!/usr/bin/env node
import 'source-map-support/register';
import { App } from 'aws-cdk-lib';
import { CdkAppStack } from '../lib/cdk_app-stack';
import { CfnGuardValidator } from '@cdklabs/cdk-validator-cfnguard';

const app = new App({
  policyValidationBeta1: [
    new CfnGuardValidator({
      disabledRules: [
        'ct-s3-pr-2',  /* server access logging */
        'ct-s3-pr-4',  /* s3 event notification */
        'ct-s3-pr-9',  /* s3 object lock */
        'ct-s3-pr-10', /* s3 SSE-KMS encryption */
        'ct-s3-pr-11'  /* s3 versioning */
      ],
      rules: [
        './s3_bucket_versioning_enabled.guard'
      ],
    })
  ]});

new CdkAppStack(app, 'CdkAppStack');
  1. Run cdk synth command to view the output and generate report. You should see policy validation with status of “failure” and violation on the newly added Guard rule.
  2. Replace the contents of the lib/cdk_app-stack.ts with the following code. Here you enabled S3 bucket versioning.
import { Stack, StackProps, Duration } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Bucket, BlockPublicAccess, BucketEncryption, StorageClass} from 'aws-cdk-lib/aws-s3';

export class CdkAppStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const bucket = new Bucket(this, 'Bucket',{
      blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
      encryption: BucketEncryption.S3_MANAGED,
      lifecycleRules: [{
        transitions: [{
          storageClass: StorageClass.GLACIER,
          transitionAfter: Duration.days(90),
        }]
      }],
      versioned: true
    });
  }
}
  1. Run cdk synth command again to view the output and generate report. You should see policy validation with status of “success” and a copy of the synthesized CloudFormation template.

Cleaning up

To avoid incurring future charges, delete the AWS Cloud9 environment. Since all the AWS CDK resources are not deployed and only CloudFormation templates are synthesized and validated by locally, you will not need not to delete any Amazon S3 resources. To delete the AWS Cloud9 environment, you can follow the instructions in the Cloud9 User Guide.

Conclusion

In conclusion, integrating the CfnGuardValidator plugin with your existing AWS CDK applications can accelerate your development process by checking your architecture aligns with both organizational policies and AWS best practices prior to deployment. This plugin leverages AWS Control Tower proactive controls or custom AWS CloudFormation Guard rules for local validation, providing developers with prompt feedback and reducing manual errors during the deployment process.

To learn more about the plugin and other AWS Control Tower proactive controls that are provided as part of the plugin, feel free to navigate to the GitHub repository and the AWS Documentation.

About the authors:

Xiaoxue Xu

Xiaoxue Xu is a Solutions Architect for AWS based in Toronto. She primarily works with Financial Services customers to help secure their workload and design scalable solutions on the AWS Cloud.

Kanwar Bajwa

Kanwar Bajwa is a Sr. Technical Account Manager at AWS who works with customers to optimize their use of AWS services and achieve their business objectives.