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!
See RULES for more information on all the available packs.
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.
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 }));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.',
});
}
}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.',
});
}
}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.
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.',
});
}
}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(useValidations.of().acknowledge())INagSuppressionIgnoreand all condition classesNagPackSuppressioninterfaceCdkNagValidationFailureconceptlogIgnoresandsuppressionIgnoreConditionprops
See CONTRIBUTING for more information.
This project is licensed under the Apache-2.0 License.