Check and secure CDK code with cdk-nag
Learn how to use cdk-nag from the Construct Hub to check your CDK applications for AWS best practices during synthesize.

Background
In my previous blog, CDK Pipelines and CloudFormation linting, I wrote about how you can use cfn_nag in CDK pipelines to check your CloudFormation templates on security best practices. With an end goal to make your code more secure and enterprise ready. Since 2 December last year, AWS announced the general availability of the Construct Hub.
In the Construct Hub the construct cdk-nag has been released. The cdk-nag construct allows you to check your CDK applications for best practices using a combination of available rule packs. Using this cdk-nag construct and use it inside your code to check upon security best practices, will eventually make your application more secure.
Prerequisites
Knowledge of CDK is required. Luckily AWS created workshops on this topic:
Furthermore access to an AWS Account with proper rights to deploy resources is needed.
Installation
The idea here is to create a basic S3 bucket, and let cdk-nag check the code by using the Aspect function in CDK.
➜ mkdir s3bucket_with_cdk_nag_construct && cd s3bucket_with_cdk_nag_construct
➜ cdk init app --language pythonReal World Scenario
Within enterprises, security frameworks are often used to make sure that resources are securely deployed in the cloud. AWS has the service Security Hub which can deploy rulesets to support such security frameworks.
When developing a CDK application, it is sometimes hard to track if your created code is compliant or not before actually deploying your CDK stacks.
Using tools like cfn_nag will allow you to check your CloudFormation templates on security best practices. Now with the construct cdk_nag from the Construct Hub it is possible to implement cfn_nag rules and checks directly into your code set during synthesizing.
Go Build
As we are using CDK version 2, we only need to add cdk-nag. In the CDK application edit the requirements.txt file:
aws-cdk-lib==2.16.0
constructs>=10.0.0,<11.0.0
cdk-nag>=2.10.0Now install everything and activate the virtual environment:
➜ source .venv/bin/activate
(.venv) ➜ pip install -r requirements.txtCreate S3 bucket
Open the file s3bucket_with_cdk_nag_construct_stack.py and add the S3 bucket:
from aws_cdk import (
aws_s3 as s3,
Stack,
)
from constructs import Construct
class S3BucketWithCfnNagConstructStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
s3.Bucket(self, 'S3Bucket')Now synthesize the CDK project. If you want to run cfn_nag_scan locally:
(.venv) ➜ cfn_nag_scan -i cdk.out/S3BucketWithCfnNagConstructStack.template.json
------------------------------------------------------------
| WARN W51
| Resource: ["S3Bucket07682993"]
| S3 bucket should likely have a bucket policy
------------------------------------------------------------
| WARN W35
| Resource: ["S3Bucket07682993"]
| S3 Bucket should have access logging configured
------------------------------------------------------------
| WARN W41
| Resource: ["S3Bucket07682993"]
| S3 Bucket should have encryption option set
Failures count: 0
Warnings count: 3What if we can use an Aspect for cfn_nag_scan. Let us configure cdk_nag:
from aws_cdk import (
Aspects,
Stack,
aws_s3 as s3,
)
from constructs import Construct
import cdk_nag
class S3BucketWithCfnNagConstructStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
s3.Bucket(self, 'S3Bucket')
Aspects.of(self).add(cdk_nag.AwsSolutionsChecks())So now synthesize the CDK app:
(.venv) ➜ cdk synth
[Error at /S3BucketWithCfnNagConstructStack/S3Bucket/Resource] AwsSolutions-S1: The S3 Bucket has server access logs disabled.
[Error at /S3BucketWithCfnNagConstructStack/S3Bucket/Resource] AwsSolutions-S2: The S3 Bucket does not have public access restricted.
[Error at /S3BucketWithCfnNagConstructStack/S3Bucket/Resource] AwsSolutions-S3: The S3 Bucket does not default encryption enabled.
[Error at /S3BucketWithCfnNagConstructStack/S3Bucket/Resource] AwsSolutions-S10: The S3 Bucket does not require requests to use SSL.
Found errorsIt does not synthesize due to errors raised by cdk_nag. If we compare the outcome with the normal cfn_nag_scan you can see that there is an extra error raised with the cdk_nag construct about SSL.
Make the bucket secure
Let us try the secure bucket construct from my previous blog. Add the package secure-bucket-construct==2.1.0 to the requirements.txt file and run pip install -r requirements.txt again.
from aws_cdk import (
Aspects,
Stack,
)
from constructs import Construct
from secure_bucket_construct import SecureBucket
import cdk_nag
class S3BucketWithCfnNagConstructStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
SecureBucket(self, 'SecureS3Bucket')
Aspects.of(self).add(cdk_nag.AwsSolutionsChecks())When synthesizing the template you can now see that no errors are raised by the cdk_nag construct. We can double check with cfn_nag_scan:
(.venv) ➜ cfn_nag_scan -i cdk.out/S3BucketWithCfnNagConstructStack.template.json
------------------------------------------------------------
Failures count: 0
Warnings count: 0Happy days! With cdk-nag from the Construct Hub we are able to see if resources are being deployed according to best practices during synthesize.
Try Yourself
The complete code can be found in my GitHub: S3 Bucket checked with cdk-nag construct
Have questions about cdk-nag or CDK security? Find me on Twitter or LinkedIn.