Skip to main content

Check CDK v2 applications for best practices using a combination on available rule packs.

Project description

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
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 (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.

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

cdk_nag-3.0.1.tar.gz (734.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cdk_nag-3.0.1-py3-none-any.whl (732.4 kB view details)

Uploaded Python 3

File details

Details for the file cdk_nag-3.0.1.tar.gz.

File metadata

  • Download URL: cdk_nag-3.0.1.tar.gz
  • Upload date:
  • Size: 734.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.14.5

File hashes

Hashes for cdk_nag-3.0.1.tar.gz
Algorithm Hash digest
SHA256 82db3c3383bbc6ab5e68f55cad688a04b02c9f37cc9e8de566d93b080a2efa87
MD5 bf46d4d349031224062e9e778027ebe3
BLAKE2b-256 878d7c98ad8a867925ba1ac7693dd4f74525def8459abb5a4fcef7731496f5be

See more details on using hashes here.

Provenance

The following attestation bundles were made for cdk_nag-3.0.1.tar.gz:

Publisher: release.yml on cdklabs/cdk-nag

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cdk_nag-3.0.1-py3-none-any.whl.

File metadata

  • Download URL: cdk_nag-3.0.1-py3-none-any.whl
  • Upload date:
  • Size: 732.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.14.5

File hashes

Hashes for cdk_nag-3.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b32b77e6ad29501231ed3a99f36f29670e85a587617fc05b554ff2f305243186
MD5 83024f6ef1348580fe54ea51a9869ee5
BLAKE2b-256 1dbc6e4116dad5ae0d2157c39373adcbdd86313822e499da499afefe43b892a5

See more details on using hashes here.

Provenance

The following attestation bundles were made for cdk_nag-3.0.1-py3-none-any.whl:

Publisher: release.yml on cdklabs/cdk-nag

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page