Enforce AWS CDK security and compliance controls with cdk-nag. Use when adding rule packs, triaging findings, writing justified suppressions, integrating checks in CI/CD, or preventing insecure infrastructure patterns in CDK stacks.
Overall
score
100%
Does it follow best practices?
Validation for skill structure
Suppressions allow you to disable specific CDK Nag rules for valid business or technical reasons. Proper suppression practices ensure security while accommodating legitimate use cases.
Target specific constructs in your CDK code:
import { NagSuppressions } from 'cdk-nag';
NagSuppressions.addResourceSuppressions(resource, [
{
id: 'AwsSolutions-SNS3',
reason: 'SSL enforcement auto-applied when topic uses KMS encryption',
},
]);Apply the same suppression to multiple resources:
const resources = [lambda1, lambda2, lambda3];
NagSuppressions.addResourceSuppressions(
resources,
[
{
id: 'AwsSolutions-L1',
reason: 'Custom runtime layer requires specific image version',
},
],
true, // Apply to all resources in array
);Apply suppressions to an entire stack:
NagSuppressions.addStackSuppressions(stack, [
{
id: 'AwsSolutions-IAM5',
reason: 'Wildcard permissions required for CloudWatch Logs integration',
},
]);Target resources by their construct path:
NagSuppressions.addResourceSuppressionsByPath(
this,
'/StackName/Custom::CDKBucketDeployment8675309/ServiceRole/Resource',
[
{
id: 'AwsSolutions-IAM4',
reason: 'AWS managed policy required for bucket deployment',
},
],
);Apply suppressions to child constructs:
const user = new User(this, 'User');
user.addToPolicy(
new PolicyStatement({
actions: ['s3:PutObject'],
resources: ['arn:aws:s3:::bucket/*'],
}),
);
NagSuppressions.addResourceSuppressions(
user,
[
{
id: 'AwsSolutions-IAM5',
reason: 'Wildcard required for dynamic S3 object paths',
appliesTo: ['Resource::arn:aws:s3:::bucket/*'],
},
],
true, // Enable child construct suppression
);Target specific findings within a rule violation:
NagSuppressions.addResourceSuppressions(resource, [
{
id: 'AwsSolutions-IAM5',
reason: 'S3 wildcard actions required for object operations',
appliesTo: [
'Action::s3:*', // Suppress specific action
'Resource::*', // Suppress specific resource
],
},
]);Use regular expressions for dynamic matching:
NagSuppressions.addResourceSuppressions(resource, [
{
id: 'AwsSolutions-IAM5',
reason: 'SQS queue pattern requires wildcard for account-specific ARNs',
appliesTo: [
{
regex: '/^Resource::arn:aws:sqs:(.*):\\*$/g',
},
],
},
]);// IAM Actions
appliesTo: ['Action::s3:*'];
appliesTo: ['Action::kms:*'];
// Resource ARNs
appliesTo: ['Resource::*'];
appliesTo: ['Resource::arn:aws:s3:::bucket/*'];
// Parameter references
appliesTo: ['Parameter::BucketArn'];
// Log exports (for services with granular logging)
appliesTo: ['LogExport::audit', 'LogExport::api'];NagSuppressions.addResourceSuppressions(resource, [
{
id: 'CdkNagValidationFailure',
reason: 'Custom validation logic implemented in application layer',
},
]);NagSuppressions.addResourceSuppressions(resource, [
{
id: 'CdkNagValidationFailure',
reason: 'Lambda runtime validation handled by deployment pipeline',
appliesTo: ['AwsSolutions-L1'],
},
]);❌ Bad Examples:
{ id: 'AwsSolutions-IAM5', reason: 'Not applicable' }
{ id: 'AwsSolutions-S1', reason: 'We know what we are doing' }
{ id: 'AwsSolutions-EC23', reason: 'Suppressed' }✅ Good Examples:
{
id: 'AwsSolutions-IAM5',
reason: 'Wildcard required for CloudWatch Logs API calls with dynamic log group names'
}
{
id: 'AwsSolutions-S1',
reason: 'Access logging not required for internal artifact storage bucket with 7-day lifecycle'
}
{
id: 'AwsSolutions-EC23',
reason: 'Security group allows HTTP from ALB security group only, not 0.0.0.0/0'
}❌ Avoid broad suppressions:
// Suppresses ALL IAM5 violations on the resource
NagSuppressions.addResourceSuppressions(resource, [
{ id: 'AwsSolutions-IAM5', reason: 'Required for functionality' },
]);✅ Use granular suppressions:
// Suppresses only specific wildcard actions
NagSuppressions.addResourceSuppressions(resource, [
{
id: 'AwsSolutions-IAM5',
reason: 'CloudWatch metrics API requires wildcard for dynamic metric names',
appliesTo: ['Action::cloudwatch:PutMetricData'],
},
]);❌ Avoid stack-level suppressions:
NagSuppressions.addStackSuppressions(stack, [
{ id: 'AwsSolutions-IAM4', reason: 'AWS managed policies needed' },
]);✅ Target specific resources:
NagSuppressions.addResourceSuppressions(lambdaRole, [
{
id: 'AwsSolutions-IAM4',
reason: 'AWSLambdaVPCAccessExecutionRole required for VPC Lambda execution',
},
]);// VPC execution role
NagSuppressions.addResourceSuppressions(lambdaRole, [
{
id: 'AwsSolutions-IAM4',
reason:
'AWSLambdaVPCAccessExecutionRole managed policy required for VPC execution',
},
]);
// Custom runtime
NagSuppressions.addResourceSuppressions(lambda, [
{
id: 'AwsSolutions-L1',
reason:
'Custom runtime layer requires specific Python version for dependencies',
},
]);// Internal buckets without public access
NagSuppressions.addResourceSuppressions(bucket, [
{
id: 'AwsSolutions-S1',
reason:
'Internal artifact bucket with short lifecycle, access logging not required',
},
]);
// Static website buckets
NagSuppressions.addResourceSuppressions(bucket, [
{
id: 'AwsSolutions-S2',
reason: 'Public read access required for static website hosting',
},
]);// KMS encrypted topics
NagSuppressions.addResourceSuppressions(topic, [
{
id: 'AwsSolutions-SNS3',
reason:
'SSL enforcement automatically applied when topic uses KMS encryption',
},
]);// ALB to target communication
NagSuppressions.addResourceSuppressions(securityGroup, [
{
id: 'AwsSolutions-EC23',
reason:
'HTTP traffic allowed from ALB security group only, not public internet',
},
]);import { SuppressionIgnoreErrors } from 'cdk-nag';
Aspects.of(app).add(
new AwsSolutionsChecks({
suppressionIgnoreCondition: new SuppressionIgnoreErrors(),
}),
);import { ISuppressionIgnoreCondition } from 'cdk-nag';
class ProductionOnlyIgnore implements ISuppressionIgnoreCondition {
createMessage(input: SuppressionIgnoreInput): string {
if (process.env.ENVIRONMENT === 'production') {
return 'Suppression ignored in production environment';
}
return '';
}
}
Aspects.of(app).add(
new AwsSolutionsChecks({
suppressionIgnoreCondition: new ProductionOnlyIgnore(),
}),
);{
"Resources": {
"MyResource": {
"Type": "AWS::S3::Bucket",
"Properties": {},
"Metadata": {
"cdk_nag": {
"rules_to_suppress": [
{
"id": "AwsSolutions-S1",
"reason": "Access logging not required for internal bucket"
}
]
}
}
}
}
}{
"Metadata": {
"cdk_nag": {
"rules_to_suppress": [
{
"id": "AwsSolutions-IAM5",
"reason": "KMS actions require wildcard for key operations",
"applies_to": ["Action::kms:*"]
}
]
}
}
}// Include suppression metadata for tracking
NagSuppressions.addResourceSuppressions(resource, [
{
id: 'AwsSolutions-IAM5',
reason:
'CloudWatch Logs wildcard required for dynamic log groups. Reviewed: 2024-01-15. Next review: 2024-07-15',
},
]);Install with Tessl CLI
npx tessl i pantheon-ai/cdk-nag@0.1.1