Check CDK v2 applications for best practices using a combination on available rule packs.
Project description
cdk-nag
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!
Available Rules and Packs
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.
Usage
For a full list of options See NagPackProps in the API.md
Including in an application
from aws_cdk import App, Validations
from cdk_nag import AwsSolutionsChecks, NIST80053R5Checks
# CdkTestStack: Any
app = App()
CdkTestStack(app, "CdkNagDemo")
# Simple rule informational messages using the AWS Solutions Rule pack
Validations.of(app).add_plugins(AwsSolutionsChecks(app))
# Multiple rule packs can be run against the same app
Validations.of(app).add_plugins(NIST80053R5Checks(app))
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
from aws_cdk.aws_ec2 import SecurityGroup, Vpc, Peer, Port
from aws_cdk import Stack, StackProps, Validations
from constructs import Construct
class CdkTestStack(Stack):
def __init__(self, scope, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None, propertyInjectors=None):
super().__init__(scope, id, description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation, propertyInjectors=propertyInjectors)
test = SecurityGroup(self, "test",
vpc=Vpc(self, "vpc")
)
test.add_ingress_rule(Peer.any_ipv4(), Port.all_traffic())
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
from aws_cdk import App, Validations
from cdk_nag import AwsSolutionsChecks
# CdkTestStack: Any
app = App()
stack = CdkTestStack(app, "CdkNagDemo")
Validations.of(app).add_plugins(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:
from aws_cdk.aws_iam import User, PolicyStatement
from aws_cdk import Stack, StackProps, Validations
from constructs import Construct
class CdkTestStack(Stack):
def __init__(self, scope, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None, propertyInjectors=None):
super().__init__(scope, id, description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation, propertyInjectors=propertyInjectors)
user = User(self, "rUser")
user.add_to_policy(
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
from aws_cdk.aws_ec2 import Instance, InstanceType, InstanceClass, MachineImage, Vpc, CfnInstance
from aws_cdk import Stack, StackProps, Validations
from constructs import Construct
class CdkTestStack(Stack):
def __init__(self, scope, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None, propertyInjectors=None):
super().__init__(scope, id, description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation, propertyInjectors=propertyInjectors)
instance = Instance(self, "rInstance",
vpc=Vpc(self, "rVpc"),
instance_type=InstanceType(InstanceClass.T3),
machine_image=MachineImage.latest_amazon_linux()
)
cfn_ins = instance.node.default_child
cfn_ins.add_property_override("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:
from aws_cdk import App, Validations
from cdk_nag import AwsSolutionsChecks
app = App()
# Writes acknowledged rules into CfnResource Metadata as cdk_nag: { rules_to_suppress: [...] }
Validations.of(app).add_plugins(AwsSolutionsChecks(app, write_suppressions_to_cloud_formation=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
from aws_cdk import App, Validations
from cdk_nag import AwsSolutionsChecks
# CdkTestStack: Any
app = App()
CdkTestStack(app, "CdkNagDemo")
Validations.of(app).add_plugins(AwsSolutionsChecks(app))
Sample Stack with imported template
from aws_cdk.cloudformation_include import CfnInclude
from aws_cdk import Stack, StackProps, Validations
from constructs import Construct
class CdkTestStack(Stack):
def __init__(self, scope, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None, propertyInjectors=None):
super().__init__(scope, id, description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation, propertyInjectors=propertyInjectors)
template = CfnInclude(self, "Template",
template_file="my-template.json"
)
# Acknowledge rules on imported resources
bucket = template.get_resource("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(useValidations.of().acknowledge())INagSuppressionIgnoreand all condition classesNagPackSuppressioninterfaceCdkNagValidationFailureconceptlogIgnoresandsuppressionIgnoreConditionprops
Contributing
See CONTRIBUTING for more information.
License
This project is licensed under the Apache-2.0 License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cdk_nag-3.0.0.tar.gz.
File metadata
- Download URL: cdk_nag-3.0.0.tar.gz
- Upload date:
- Size: 734.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3913c0b2eee28f97183d0ad1d1de35cad3435913b271d5999e27653239eb594
|
|
| MD5 |
87761c6acaff1bd677aba4dc28e52dba
|
|
| BLAKE2b-256 |
03cec64af50525744cd6195ab8cd9c3b1697720427ff882e0c268205bffd37e5
|
Provenance
The following attestation bundles were made for cdk_nag-3.0.0.tar.gz:
Publisher:
release.yml on cdklabs/cdk-nag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cdk_nag-3.0.0.tar.gz -
Subject digest:
e3913c0b2eee28f97183d0ad1d1de35cad3435913b271d5999e27653239eb594 - Sigstore transparency entry: 1803326865
- Sigstore integration time:
-
Permalink:
cdklabs/cdk-nag@2c0175c2b6d893c9b55122c1298250318b663eb5 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cdklabs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2c0175c2b6d893c9b55122c1298250318b663eb5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cdk_nag-3.0.0-py3-none-any.whl.
File metadata
- Download URL: cdk_nag-3.0.0-py3-none-any.whl
- Upload date:
- Size: 732.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d559b97dc2d4fefd31bbf66919b7b44d842a427ecff89cb3efca714af10abbe
|
|
| MD5 |
a2038257cae2f831dd3012a0d452f89c
|
|
| BLAKE2b-256 |
e1a45cd6a0243bc8fa02b1627b1241d82cf98c2d63bd752dd08730a762493809
|
Provenance
The following attestation bundles were made for cdk_nag-3.0.0-py3-none-any.whl:
Publisher:
release.yml on cdklabs/cdk-nag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cdk_nag-3.0.0-py3-none-any.whl -
Subject digest:
1d559b97dc2d4fefd31bbf66919b7b44d842a427ecff89cb3efca714af10abbe - Sigstore transparency entry: 1803326747
- Sigstore integration time:
-
Permalink:
cdklabs/cdk-nag@2c0175c2b6d893c9b55122c1298250318b663eb5 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cdklabs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2c0175c2b6d893c9b55122c1298250318b663eb5 -
Trigger Event:
push
-
Statement type: