Skip to content

cdklabs/cdk-nag

cdk-nag

PyPI version npm version Maven version NuGet version Go version

View on Construct Hub

Check CDK applications or CloudFormation templates for best practices using a combination of available rule packs. Inspired by cfn_nag.

Check out this blog post for a guided overview!

demo

Available Rules and Packs

See RULES for more information on all the available packs.

  1. AWS Solutions
  2. HIPAA Security
  3. NIST 800-53 rev 4
  4. NIST 800-53 rev 5
  5. PCI DSS 3.2.1
  6. Serverless

RULES also includes a collection of additional rules that are not currently included in any of the pre-built NagPacks, but are still available for inclusion in custom NagPacks.

Read the NagPack developer docs if you are interested in creating your own pack.

Usage

For a full list of options See NagPackProps in the API.md

Including in an application
import { App, Validations } from 'aws-cdk-lib';
import { AwsSolutionsChecks, NIST80053R5Checks } from 'cdk-nag';

declare const CdkTestStack: any;

const app = new App();
new CdkTestStack(app, 'CdkNagDemo');
// Simple rule informational messages using the AWS Solutions Rule pack
Validations.of(app).addPlugins(new AwsSolutionsChecks(app));
// Multiple rule packs can be run against the same app
Validations.of(app).addPlugins(new NIST80053R5Checks(app));
// Additional explanations on the purpose of triggered rules
// Validations.of(app).addPlugins(new AwsSolutionsChecks(app, { verbose: true }));

Acknowledging a Rule

Use CDK's native Validations.of() API to acknowledge (suppress) rule violations on specific constructs.

Example 1) Acknowledging a rule on a construct
import { SecurityGroup, Vpc, Peer, Port } from 'aws-cdk-lib/aws-ec2';
import { Stack, StackProps, Validations } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkTestStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const test = new SecurityGroup(this, 'test', {
      vpc: new Vpc(this, 'vpc'),
    });
    test.addIngressRule(Peer.anyIpv4(), Port.allTraffic());
    Validations.of(test).acknowledge({
      id: 'AwsSolutions-EC23',
      reason: 'This security group is used for internal testing only.',
    });
  }
}
Example 2) Acknowledging a rule on a stack
import { App, Validations } from 'aws-cdk-lib';
import { AwsSolutionsChecks } from 'cdk-nag';

declare const CdkTestStack: any;

const app = new App();
const stack = new CdkTestStack(app, 'CdkNagDemo');
Validations.of(app).addPlugins(new AwsSolutionsChecks(app));
Validations.of(stack).acknowledge({
  id: 'AwsSolutions-EC23',
  reason: 'All security groups in this stack are internal only.',
});
Example 3) Acknowledging a specific finding

Certain rules report multiple findings per resource (e.g., IAM wildcard permissions). Each finding has its own ID in the format RuleId[FindingId].

If you received the following errors on synth/deploy:

[Error at /StackName/rUser/DefaultPolicy/Resource] AwsSolutions-IAM5[Action::s3:*]: The IAM entity contains wildcard permissions.
[Error at /StackName/rUser/DefaultPolicy/Resource] AwsSolutions-IAM5[Resource::*]: The IAM entity contains wildcard permissions.

You can acknowledge a specific finding:

import { User, PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { Stack, StackProps, Validations } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkTestStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const user = new User(this, 'rUser');
    user.addToPolicy(
      new PolicyStatement({
        actions: ['s3:*'],
        resources: ['*'],
      })
    );
    // Only acknowledge the s3:* action — Resource::* still triggers
    Validations.of(user).acknowledge({
      id: 'AwsSolutions-IAM5[Action::s3:*]',
      reason: 'Need s3:* for cross-account replication.',
    });
  }
}

Rules and Property Overrides

In some cases L2 Constructs do not have a native option to remediate an issue and must be fixed via Raw Overrides. Since raw overrides take place after template synthesis these fixes are not caught by cdk-nag. In this case you should remediate the issue and acknowledge the rule.

Example) Property Overrides
import {
  Instance,
  InstanceType,
  InstanceClass,
  MachineImage,
  Vpc,
  CfnInstance,
} from 'aws-cdk-lib/aws-ec2';
import { Stack, StackProps, Validations } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkTestStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const instance = new Instance(this, 'rInstance', {
      vpc: new Vpc(this, 'rVpc'),
      instanceType: new InstanceType(InstanceClass.T3),
      machineImage: MachineImage.latestAmazonLinux(),
    });
    const cfnIns = instance.node.defaultChild as CfnInstance;
    cfnIns.addPropertyOverride('DisableApiTermination', true);
    Validations.of(instance).acknowledge({
      id: 'AwsSolutions-EC29',
      reason: 'Remediated through property override.',
    });
  }
}

Audit Trail: CloudFormation Metadata

By default, cdk-nag writes violations to CDK's policy-validation-report.json in the cloud assembly. If you need the v2-compatible cdk_nag metadata block in your synthesized CloudFormation templates (for existing compliance tooling), enable writeSuppressionsToCloudFormation:

import { App, Validations } from 'aws-cdk-lib';
import { AwsSolutionsChecks } from 'cdk-nag';

const app = new App();
// Writes acknowledged rules into CfnResource Metadata as cdk_nag: { rules_to_suppress: [...] }
Validations.of(app).addPlugins(new AwsSolutionsChecks(app, { writeSuppressionsToCloudFormation: true }));

This registers a WriteNagSuppressionsToCloudFormationAspect that runs during synthesis and copies Validations.of().acknowledge() data into the CloudFormation template Metadata section, preserving the same format as cdk-nag v2.

Using on CloudFormation templates

You can use cdk-nag on existing CloudFormation templates by using the cloudformation-include module.

Example) CloudFormation template

Sample App

import { App, Validations } from 'aws-cdk-lib';
import { AwsSolutionsChecks } from 'cdk-nag';

declare const CdkTestStack: any;

const app = new App();
new CdkTestStack(app, 'CdkNagDemo');
Validations.of(app).addPlugins(new AwsSolutionsChecks(app));

Sample Stack with imported template

import { CfnInclude } from 'aws-cdk-lib/cloudformation-include';
import { Stack, StackProps, Validations } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkTestStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const template = new CfnInclude(this, 'Template', {
      templateFile: 'my-template.json',
    });
    // Acknowledge rules on imported resources
    const bucket = template.getResource('rBucket');
    Validations.of(bucket).acknowledge({
      id: 'AwsSolutions-S1',
      reason: 'Logging not required for this bucket.',
    });
  }
}

Migrating from v2

cdk-nag v3 replaces the custom NagSuppressions API with CDK's native Validations.of().acknowledge() mechanism.

v2 v3
NagSuppressions.addResourceSuppressions(construct, [{ id, reason }]) Validations.of(construct).acknowledge({ id, reason })
NagSuppressions.addStackSuppressions(stack, [{ id, reason }]) Validations.of(stack).acknowledge({ id, reason })
NagSuppressions.addResourceSuppressionsByPath(stack, path, [...]) Validations.of(construct).acknowledge({ id, reason })
appliesTo: ['Action::s3:*'] id: 'AwsSolutions-IAM5[Action::s3:*]'
{ id: 'CdkNagValidationFailure', reason: '...' } Validations.of(construct).acknowledge({ id: 'RuleId', reason: '...' })

Note on bulk suppression: In v2, suppressing a rule without appliesTo would suppress all findings for that rule on the construct. In v3, each finding must be acknowledged individually (e.g., AwsSolutions-IAM5[Action::s3:*] and AwsSolutions-IAM5[Resource::*] are separate acknowledgments). Prefix matching (acknowledging AwsSolutions-IAM5 to suppress all findings) is not yet supported — tracked via [issue link].

Removed APIs:

  • NagSuppressions (use Validations.of().acknowledge())
  • INagSuppressionIgnore and all condition classes
  • NagPackSuppression interface
  • CdkNagValidationFailure concept
  • logIgnores and suppressionIgnoreCondition props

Contributing

See CONTRIBUTING for more information.

License

This project is licensed under the Apache-2.0 License.

About

Check CDK applications for best practices using a combination of available rule packs

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors