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.
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.
Figure 2: Overall workflow for using CfnGuardValidator plugin
Prerequisites
For this walkthrough, you should have the following prerequisites:
- An AWS account.
- An AWS Cloud9 development environment. Instructions to setup an environment in AWS Cloud9 User Guide.
- Access to the internet to download the CfnGuardValidator plugin and aws-guard-rules-registry.
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.
- 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
- 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')
}
}
- 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.
- Run the following command to install the plugin:
npm install @cdklabs/cdk-validator-cfnguard
- 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');
- 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.
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:
- 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');
- 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),
}]
}]
});
}
}
- 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.
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.
- 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
- 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');
- 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. - 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
});
}
}
- 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: