Improving AWS CDK Security and Compliance with CDK Nag


Introduction
When building infrastructure with AWS CDK, it's easy to overlook security and compliance. CDK Nag helps catch misconfigurations early by scanning your stacks against best practices and regulatory standards.
What is CDK Nag?
CDK Nag is a compliance and best practices tool for AWS CDK. It scans your CDK constructs using the AWS CDK Aspects system to ensure they meet specific security, compliance, and architectural standards.
It supports rule packs based on:
AWS Solutions
CIS AWS Foundations Benchmark
NIST 800-53
When you define an S3 bucket or a DynamoDB table without encryption or logging, CDK Nag detects these issues before deployment. It acts like a linter for your infrastructure code, flagging insecure configurations such as public buckets, unencrypted tables, and missing backups.
How does it work?
As mentioned earlier CDK Nag uses the Aspects feature of AWS CDK to inspect the construct tree. Aspects allow you to run custom logic (like validations) on every node in the stack. CDK Nag implements this by attaching rule packs that define checks for common misconfigurations.
When you synthesize your CDK app (cdk synth
) or deploy (cdk deploy
), CDK Nag runs these checks and prints out warnings or errors for violations it detects.
Setting Up CDK and CDK Nag
To follow along, you'll need a CDK app. If you don’t have one, you can create a new CDK project using this guide: AWS CDK Getting Started (Python)
Step 1: Create a New CDK App (if needed)
cdk init app --language python
Step 2: Install CDK Nag Install the library:
pip install cdk-nag
Step 3: Apply CDK Nag in app.py
pythonCopyEditfrom aws_cdk import App, Aspects
from cdk_nag import AwsSolutionsChecks
from my_stack import MyStack # Your custom stack
app = App()
MyStack(app, "MyStack")
Aspects.of(app).add(AwsSolutionsChecks(verbose=True))
app.synth()
Example: S3 and DynamoDB with CDK Nag
Let’s create an example with:
An S3 bucket resource without logging/encryption
A DynamoDB table resource without encryption or point-in-time recovery
In the my_stack.py
add the following construct
from aws_cdk import (
Stack,
aws_s3 as s3,
aws_dynamodb as dynamodb,
)
from constructs import Construct
class MyStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs):
super().__init__(scope, id, **kwargs)
# Insecure S3 Bucket
bucket = s3.Bucket(self, "MyInsecureBucket")
# Insecure DynamoDB Table
table = dynamodb.Table(
self, "MyInsecureTable",
partition_key=dynamodb.Attribute(
name="id",
type=dynamodb.AttributeType.STRING
)
)
Running cdk synth
will yield warnings like:
[Error at /CdkNagStack/MyInsecureBucket/Resource] AwsSolutions-S1: The S3 Bucket has server access logs disabled. The bucket should have server access logging enabled to provide detailed records for the requests that are made to the bucket.
[Error at /CdkNagStack/MyInsecureBucket/Resource] AwsSolutions-S10: The S3 Bucket or bucket policy does not require requests to use SSL. You can use HTTPS (TLS) to help prevent potential attackers from eavesdropping on or manipulating network traffic using person-in-the-middle or similar attacks. You should allow only encrypted connections over HTTPS (TLS) using the aws:SecureTransport condition on Amazon S3 bucket policies.
[Warning at /CdkNagStack/MyInsecureTable/Resource] AwsSolutions-DDB3: The DynamoDB table does not have Point-in-time Recovery enabled. DynamoDB continuous backups represent an additional layer of insurance against accidental loss of data on top of on-demand backups. The DynamoDB service can back up the data with per-second granularity and restore it to any single second from the time PITR was enabled up to the prior 35 days.
Fix It or Suppress It?
At this point, you have two options:
Fix the issues by enabling the required security settings (recommended for production).
Suppress specific findings if you have a valid reason (e.g. test environments or prototypes).
How to Suppress CDK Nag Warnings
If you're intentionally skipping a best practice (like disabling access logs for a dev bucket), you can suppress that warning. Here’s is how to suppress specific CDK Nag findings directly in my_stack.py
, where your bucket and table are defined:
from aws_cdk import (
Stack,
aws_s3 as s3,
aws_dynamodb as dynamodb,
)
from constructs import Construct
class MyStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs):
super().__init__(scope, id, **kwargs)
# Insecure S3 Bucket
bucket = s3.Bucket(self, "MyInsecureBucket")
# Suppress CDK Nag warnings on the S3 bucket
cfn_bucket = bucket.node.default_child
cfn_bucket.cfn_options.metadata = {
"cdk_nag": {
"rules_to_suppress": [
{
"id": "AwsSolutions-S1", # Access logging
"reason": "Access logging is not needed for this development bucket."
},
{
"id": "AwsSolutions-S10", # Enforce SSL
"reason": "SSL is enforced at the application level for this dev bucket."
}
]
}
}
# Insecure DynamoDB Table
table = dynamodb.Table(
self, "MyInsecureTable",
partition_key=dynamodb.Attribute(
name="id",
type=dynamodb.AttributeType.STRING
)
)
# Suppress CDK Nag warning on the DynamoDB table
cfn_table = table.node.default_child
cfn_table.cfn_options.metadata = {
"cdk_nag": {
"rules_to_suppress": [
{
"id": "AwsSolutions-DDB3", # PITR
"reason": "Point-in-time recovery is not required for temporary data."
}
]
}
}
The warnings should go away!!
Best Practices for Suppression
Only suppress findings when you have a valid, documented reason.
Never suppress critical security checks in production without approval.
Always include a clear
"reason"
for future reference and audits.
Conclusion
CDK Nag is a powerful tool that gives you visibility into the security and compliance posture of your AWS CDK infrastructure. With very little setup, you can ensure your resources follow AWS best practices and standards like CIS, NIST, and AWS Well-Architected.
Whether you're working on a proof-of-concept or deploying to production, CDK Nag helps you catch problems early and either fix or safely suppress them.
Subscribe to my newsletter
Read articles from Louis Echefu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Louis Echefu
Louis Echefu
I am a Software Engineer currently learning about the Cloud (DevOps)