cdk-nag is a CDK construct that helps enforce least privilege IAM policies by auditing your CDK CloudFormation templates for common security misconfigurations.

Let’s see it in action. Imagine you have a Lambda function that needs to read from an S3 bucket.

from aws_cdk import core
from aws_cdk.aws_lambda import Function, Runtime
from aws_cdk.aws_s3 import Bucket
from cdk_nag import AwsSolutionsChecks, NagSuppressions

class MyCdkStack(core.Stack):
    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        bucket = Bucket(self, "MyBucket")

        my_lambda = Function(
            self, "MyLambda",
            runtime=Runtime.PYTHON_3_9,
            handler="index.handler",
            code=Function.from_inline("def handler(event, context):\n    print('Hello from Lambda!')"),
            # This grants broad S3 access, which cdk-nag will flag
            initial_policy=[
                core.PolicyStatement(
                    actions=["s3:*"],
                    resources=[bucket.bucket_arn, f"{bucket.bucket_arn}/*"]
                )
            ]
        )

        # Apply cdk-nag checks
        AwsSolutionsChecks(reports_enabled=True, verbose=True).visit(self)

        # Example of suppressing a known violation
        NagSuppressions.add(
            my_lambda,
            [
                {
                    "id": "AwsSolutions-IAM4",
                    "reason": "This is a legacy example, real-world would scope down access."
                }
            ]
        )

When you synthesize this CDK app, cdk-nag will run its checks against the generated CloudFormation. It identifies that the MyLambda function has an IAM policy that grants s3:* actions, which is too broad. The specific violation might be something like AwsSolutions-IAM4 (IAM.4: IAM user group, role, and policy should not have Karthik access).

The problem cdk-nag solves is that it’s easy to grant overly permissive IAM roles in CDK, especially when you’re starting out or dealing with complex resource interactions. Developers often copy-paste broad permissions or use wildcards (*) for actions and resources, leading to security vulnerabilities. cdk-nag acts as a linter for your infrastructure-as-code, flagging these potential issues before deployment.

Internally, cdk-nag traverses the CDK app’s construct tree. When it encounters certain constructs (like aws_lambda.Function or aws_iam.Policy), it inspects their associated CloudFormation properties, particularly IAM policies. It then applies a set of predefined rules (based on AWS Solutions Library best practices) to these policies. If a policy violates a rule, it reports it as a finding.

The primary levers you control are the specific IAM policies you define within your CDK constructs. cdk-nag doesn’t change your policies; it audits them. You can:

  1. Scope down actions: Instead of s3:*, use specific actions like s3:GetObject or s3:PutObject.
  2. Scope down resources: Instead of * for resources, specify the exact ARN of the bucket or object.
  3. Use NagSuppressions: For known, acceptable deviations, you can add a suppression with a clear justification. This is crucial for cases where the automated check is too strict or you have a valid reason for broader access (though this should be rare and well-documented).

The most surprising thing is how often the AwsSolutions-IAM4 rule (and others like it) will flag policies that look perfectly reasonable at first glance. It’s not just about preventing malicious access; it’s about preventing accidental overreach. For instance, a policy allowing s3:ListBucket on arn:aws:s3:::my-bucket also implicitly grants permission to list objects within that bucket. cdk-nag often flags this as insufficient resource scoping if you only intended ListBucket and not operations on the objects themselves.

The next step after enforcing least privilege is often to implement automated security scanning for your container images.

Want structured learning?

Take the full Cdk course →