Coverage for gco / stacks / nag_suppressions.py: 100%
60 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-30 21:47 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-30 21:47 +0000
1"""CDK-nag suppression utilities for GCO stacks.
3This module provides centralized suppression management for cdk-nag rules
4that are intentionally not applicable or have documented justifications.
6Supported Compliance Frameworks:
7- AWS Solutions: Best practices for AWS architectures
8- HIPAA Security: Healthcare compliance requirements
9- NIST 800-53 Rev 5: Federal security controls
10- PCI DSS 3.2.1: Payment card industry standards
11- Serverless: Best practices for serverless architectures
13Suppression Categories:
141. AWS Managed Policies - Required for EKS/Lambda integrations
152. Inline Policies - CDK-generated for custom resources
163. Wildcard Permissions - Required for dynamic resource access
174. Infrastructure Patterns - Intentional architectural decisions
18"""
20from aws_cdk import Stack
21from cdk_nag import NagPackSuppression, NagSuppressions
24def add_eks_suppressions(stack: Stack) -> None:
25 """Add suppressions for EKS-related cdk-nag findings.
27 EKS requires specific AWS managed policies that cannot be replaced
28 with customer-managed policies without breaking functionality.
29 """
30 # EKS requires these AWS managed policies - they are AWS-recommended
31 eks_managed_policies = [
32 "Policy::arn:<AWS::Partition>:iam::aws:policy/AmazonEKSClusterPolicy",
33 "Policy::arn:<AWS::Partition>:iam::aws:policy/AmazonEKSComputePolicy",
34 "Policy::arn:<AWS::Partition>:iam::aws:policy/AmazonEKSBlockStoragePolicy",
35 "Policy::arn:<AWS::Partition>:iam::aws:policy/AmazonEKSLoadBalancingPolicy",
36 "Policy::arn:<AWS::Partition>:iam::aws:policy/AmazonEKSNetworkingPolicy",
37 "Policy::arn:<AWS::Partition>:iam::aws:policy/AmazonEKSWorkerNodePolicy",
38 "Policy::arn:<AWS::Partition>:iam::aws:policy/AmazonEKS_CNI_Policy",
39 "Policy::arn:<AWS::Partition>:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",
40 "Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AmazonEFSCSIDriverPolicy",
41 # CloudWatch Observability addon policies for Container Insights
42 "Policy::arn:<AWS::Partition>:iam::aws:policy/CloudWatchAgentServerPolicy",
43 "Policy::arn:<AWS::Partition>:iam::aws:policy/AWSXrayWriteOnlyAccess",
44 ]
46 NagSuppressions.add_stack_suppressions(
47 stack,
48 [
49 NagPackSuppression(
50 id="AwsSolutions-IAM4",
51 reason=(
52 "EKS requires AWS managed policies for cluster, node, and add-on functionality. "
53 "These are AWS-recommended policies that provide necessary permissions for EKS Auto Mode. "
54 "See: https://docs.aws.amazon.com/eks/latest/userguide/security-iam-awsmanpol.html"
55 ),
56 applies_to=eks_managed_policies,
57 ),
58 ],
59 )
62def add_lambda_suppressions(stack: Stack) -> None:
63 """Add suppressions for Lambda-related cdk-nag findings.
65 Lambda functions used for CDK custom resources and infrastructure
66 automation have specific requirements that trigger cdk-nag warnings.
67 """
68 lambda_managed_policies = [
69 "Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
70 "Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",
71 ]
73 NagSuppressions.add_stack_suppressions(
74 stack,
75 [
76 NagPackSuppression(
77 id="AwsSolutions-IAM4",
78 reason=(
79 "Lambda basic execution and VPC access roles are AWS-recommended managed policies. "
80 "They provide minimal permissions for CloudWatch Logs and VPC ENI management. "
81 "See: https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html"
82 ),
83 applies_to=lambda_managed_policies,
84 ),
85 NagPackSuppression(
86 id="AwsSolutions-L1",
87 reason=(
88 "CDK Provider framework Lambda functions use a specific runtime version "
89 "managed by CDK. These are internal functions not exposed to users."
90 ),
91 ),
92 # HIPAA Lambda suppressions
93 NagPackSuppression(
94 id="HIPAA.Security-LambdaConcurrency",
95 reason=(
96 "Infrastructure Lambda functions (custom resources) are invoked only during "
97 "stack deployment and do not require concurrency limits. They are not user-facing."
98 ),
99 ),
100 NagPackSuppression(
101 id="HIPAA.Security-LambdaDLQ",
102 reason=(
103 "CDK custom resource Lambda functions have built-in retry logic and report "
104 "failures directly to CloudFormation. DLQ is not applicable for this pattern."
105 ),
106 ),
107 NagPackSuppression(
108 id="HIPAA.Security-LambdaInsideVPC",
109 reason=(
110 "CDK Provider framework Lambda functions need internet access to communicate "
111 "with CloudFormation. VPC placement would require NAT Gateway configuration. "
112 "User-facing Lambda functions (kubectl applier) ARE placed in VPC."
113 ),
114 ),
115 # NIST 800-53 Lambda suppressions
116 NagPackSuppression(
117 id="NIST.800.53.R5-LambdaConcurrency",
118 reason=(
119 "Infrastructure Lambda functions (custom resources) are invoked only during "
120 "stack deployment and do not require concurrency limits."
121 ),
122 ),
123 NagPackSuppression(
124 id="NIST.800.53.R5-LambdaDLQ",
125 reason=(
126 "CDK custom resource Lambda functions have built-in retry logic and report "
127 "failures directly to CloudFormation. DLQ is not applicable."
128 ),
129 ),
130 NagPackSuppression(
131 id="NIST.800.53.R5-LambdaInsideVPC",
132 reason=(
133 "CDK Provider framework Lambda functions need internet access to communicate "
134 "with CloudFormation. User-facing Lambda functions ARE placed in VPC."
135 ),
136 ),
137 # PCI DSS Lambda suppressions
138 NagPackSuppression(
139 id="PCI.DSS.321-LambdaInsideVPC",
140 reason=(
141 "CDK Provider framework Lambda functions need internet access to communicate "
142 "with CloudFormation. User-facing Lambda functions ARE placed in VPC."
143 ),
144 ),
145 # Serverless Lambda suppressions
146 NagPackSuppression(
147 id="Serverless-LambdaLatestVersion",
148 reason=(
149 "CDK Provider framework Lambda functions use a specific runtime version "
150 "managed by CDK. These are internal functions not exposed to users."
151 ),
152 ),
153 NagPackSuppression(
154 id="Serverless-LambdaDefaultMemorySize",
155 reason=(
156 "CDK Provider framework Lambda functions have appropriate memory for their "
157 "workload. Custom Lambda functions have explicit memory configuration."
158 ),
159 ),
160 NagPackSuppression(
161 id="Serverless-LambdaDLQ",
162 reason=(
163 "CDK custom resource Lambda functions have built-in retry logic and report "
164 "failures directly to CloudFormation. DLQ is not applicable."
165 ),
166 ),
167 ],
168 )
171def add_iam_suppressions(
172 stack: Stack, regions: list[str] | None = None, global_region: str | None = None
173) -> None:
174 """Add suppressions for IAM-related cdk-nag findings.
176 CDK generates inline policies for custom resources and some patterns
177 require wildcard permissions for dynamic resource access.
179 Args:
180 stack: The CDK stack to apply suppressions to
181 regions: List of regional deployment regions (for EKS addon patterns)
182 global_region: Global region for SSM parameters and DynamoDB tables
183 """
184 # Build dynamic applies_to list based on configured regions
185 applies_to = [
186 "Resource::<KubectlApplierFunction6147DA0C.Arn>:*",
187 "Resource::<GaRegistrationFunction4A12C41B.Arn>:*",
188 "Resource::<HelmInstallerFunction3FEB04EF.Arn>:*",
189 "Resource::<VpcFlowLogGroup86559C69.Arn>:*",
190 # Secrets Manager cross-region access with wildcard for suffix
191 f"Resource::arn:aws:secretsmanager:{global_region or 'us-east-2'}:<AWS::AccountId>:secret:gco/api-gateway-auth-token*",
192 ]
194 # Add EKS addon patterns for each configured region
195 if regions:
196 for region in regions:
197 applies_to.append(
198 f"Resource::arn:aws:eks:{region}:<AWS::AccountId>:addon/<GCOEksCluster841A896A>/*"
199 )
201 # Add SSM parameter patterns for global region and all regional regions
202 ssm_regions = set()
203 if global_region:
204 ssm_regions.add(global_region)
205 if regions:
206 ssm_regions.update(regions)
208 for region in ssm_regions:
209 applies_to.append(f"Resource::arn:aws:ssm:{region}:<AWS::AccountId>:parameter/gco/*")
211 # Add DynamoDB index wildcard patterns for global region
212 # Tables are created in global stack, accessed from all regional stacks
213 if global_region:
214 applies_to.extend(
215 [
216 f"Resource::arn:aws:dynamodb:{global_region}:<AWS::AccountId>:table/gco-job-templates/index/*",
217 f"Resource::arn:aws:dynamodb:{global_region}:<AWS::AccountId>:table/gco-webhooks/index/*",
218 f"Resource::arn:aws:dynamodb:{global_region}:<AWS::AccountId>:table/gco-jobs/index/*",
219 f"Resource::arn:aws:dynamodb:{global_region}:<AWS::AccountId>:table/gco-inference-endpoints/index/*",
220 ]
221 )
223 # Add S3 wildcard patterns for model weights bucket
224 # Bucket name is auto-generated by CDK, so we use a prefix pattern
225 applies_to.extend(
226 [
227 "Resource::arn:aws:s3:::gco-*",
228 "Resource::arn:aws:s3:::gco-*/*",
229 ]
230 )
232 # KMS wildcard scoped to S3 via condition for model weights bucket decryption
233 applies_to.append("Resource::arn:aws:kms:*:<AWS::AccountId>:key/*")
235 NagSuppressions.add_stack_suppressions(
236 stack,
237 [
238 # Inline policy suppressions for all frameworks
239 NagPackSuppression(
240 id="HIPAA.Security-IAMNoInlinePolicy",
241 reason=(
242 "CDK generates inline policies for custom resources and Lambda functions. "
243 "These are scoped to specific resources and follow least-privilege principles."
244 ),
245 ),
246 NagPackSuppression(
247 id="NIST.800.53.R5-IAMNoInlinePolicy",
248 reason=(
249 "CDK generates inline policies for custom resources and Lambda functions. "
250 "These are scoped to specific resources and follow least-privilege principles."
251 ),
252 ),
253 NagPackSuppression(
254 id="PCI.DSS.321-IAMNoInlinePolicy",
255 reason=(
256 "CDK generates inline policies for custom resources and Lambda functions. "
257 "These are scoped to specific resources and follow least-privilege principles."
258 ),
259 ),
260 # Wildcard permission suppressions
261 NagPackSuppression(
262 id="AwsSolutions-IAM5",
263 reason=(
264 "Wildcard permissions are required for: (1) EKS cluster admin access to manage "
265 "dynamic Kubernetes resources, (2) Custom resource providers to invoke Lambda versions, "
266 "(3) SSM parameter access for cross-region coordination, (4) EKS addon management, "
267 "(5) VPC Flow Logs to write to CloudWatch, (6) Secrets Manager cross-region access "
268 "with wildcard suffix for auth token, (7) DynamoDB GSI access for job queue, templates, "
269 "webhooks, and inference endpoints tables, (8) S3 access for model weights bucket "
270 "(auto-generated name). All wildcards are scoped to specific patterns. "
271 "(9) KMS decrypt scoped to S3 via condition for model weights bucket."
272 ),
273 applies_to=applies_to,
274 ),
275 ],
276 )
279def add_vpc_suppressions(stack: Stack) -> None:
280 """Add suppressions for VPC-related cdk-nag findings.
282 Public subnets and IGW routes are required for ALB and NAT Gateway
283 functionality in a multi-tier architecture.
284 """
285 NagSuppressions.add_stack_suppressions(
286 stack,
287 [
288 # HIPAA VPC suppressions
289 NagPackSuppression(
290 id="HIPAA.Security-VPCSubnetAutoAssignPublicIpDisabled",
291 reason=(
292 "Public subnets are required for internet-facing ALB. EC2 instances "
293 "(EKS nodes) are deployed only in private subnets."
294 ),
295 ),
296 NagPackSuppression(
297 id="HIPAA.Security-VPCNoUnrestrictedRouteToIGW",
298 reason=(
299 "Public subnets require IGW route for ALB to receive traffic from "
300 "Global Accelerator. All compute resources are in private subnets."
301 ),
302 ),
303 # NIST 800-53 VPC suppressions
304 NagPackSuppression(
305 id="NIST.800.53.R5-VPCSubnetAutoAssignPublicIpDisabled",
306 reason=(
307 "Public subnets are required for internet-facing ALB. EC2 instances "
308 "(EKS nodes) are deployed only in private subnets."
309 ),
310 ),
311 NagPackSuppression(
312 id="NIST.800.53.R5-VPCNoUnrestrictedRouteToIGW",
313 reason=(
314 "Public subnets require IGW route for ALB to receive traffic from "
315 "Global Accelerator. All compute resources are in private subnets."
316 ),
317 ),
318 # PCI DSS VPC suppressions
319 NagPackSuppression(
320 id="PCI.DSS.321-VPCSubnetAutoAssignPublicIpDisabled",
321 reason=(
322 "Public subnets are required for internet-facing ALB. EC2 instances "
323 "(EKS nodes) are deployed only in private subnets."
324 ),
325 ),
326 NagPackSuppression(
327 id="PCI.DSS.321-VPCNoUnrestrictedRouteToIGW",
328 reason=(
329 "Public subnets require IGW route for ALB to receive traffic from "
330 "Global Accelerator. All compute resources are in private subnets."
331 ),
332 ),
333 ],
334 )
337def add_api_gateway_suppressions(stack: Stack) -> None:
338 """Add suppressions for API Gateway-related cdk-nag findings."""
339 NagSuppressions.add_stack_suppressions(
340 stack,
341 [
342 NagPackSuppression(
343 id="AwsSolutions-COG4",
344 reason=(
345 "API Gateway uses IAM authentication (SigV4) instead of Cognito. "
346 "This is intentional for machine-to-machine API access patterns."
347 ),
348 ),
349 NagPackSuppression(
350 id="AwsSolutions-APIG2",
351 reason=(
352 "Request validation is performed by the backend Manifest Processor service "
353 "which has detailed schema validation. API Gateway acts as a pass-through proxy."
354 ),
355 ),
356 # Cache suppressions - caching is intentionally disabled
357 NagPackSuppression(
358 id="HIPAA.Security-APIGWCacheEnabledAndEncrypted",
359 reason=(
360 "Caching is disabled intentionally. Manifest submissions are unique "
361 "and should not be cached. Health checks need real-time data."
362 ),
363 ),
364 NagPackSuppression(
365 id="NIST.800.53.R5-APIGWCacheEnabledAndEncrypted",
366 reason=(
367 "Caching is disabled intentionally. Manifest submissions are unique "
368 "and should not be cached. Health checks need real-time data."
369 ),
370 ),
371 NagPackSuppression(
372 id="PCI.DSS.321-APIGWCacheEnabledAndEncrypted",
373 reason=(
374 "Caching is disabled intentionally. Manifest submissions are unique "
375 "and should not be cached. Health checks need real-time data."
376 ),
377 ),
378 # SSL certificate suppressions
379 NagPackSuppression(
380 id="HIPAA.Security-APIGWSSLEnabled",
381 reason=(
382 "Backend SSL certificates are not required as traffic flows through "
383 "Global Accelerator (TLS terminated) to internal ALB (HTTPS)."
384 ),
385 ),
386 NagPackSuppression(
387 id="NIST.800.53.R5-APIGWSSLEnabled",
388 reason=(
389 "Backend SSL certificates are not required as traffic flows through "
390 "Global Accelerator (TLS terminated) to internal ALB (HTTPS)."
391 ),
392 ),
393 NagPackSuppression(
394 id="PCI.DSS.321-APIGWSSLEnabled",
395 reason=(
396 "Backend SSL certificates are not required as traffic flows through "
397 "Global Accelerator (TLS terminated) to internal ALB (HTTPS)."
398 ),
399 ),
400 # CloudWatch Log Group encryption suppressions
401 NagPackSuppression(
402 id="HIPAA.Security-CloudWatchLogGroupEncrypted",
403 reason=(
404 "CloudWatch Logs are encrypted by default with AWS-managed keys. "
405 "Customer-managed KMS keys can be enabled via configuration if required."
406 ),
407 ),
408 NagPackSuppression(
409 id="NIST.800.53.R5-CloudWatchLogGroupEncrypted",
410 reason=(
411 "CloudWatch Logs are encrypted by default with AWS-managed keys. "
412 "Customer-managed KMS keys can be enabled via configuration if required."
413 ),
414 ),
415 NagPackSuppression(
416 id="PCI.DSS.321-CloudWatchLogGroupEncrypted",
417 reason=(
418 "CloudWatch Logs are encrypted by default with AWS-managed keys. "
419 "Customer-managed KMS keys can be enabled via configuration if required."
420 ),
421 ),
422 # API Gateway CloudWatch role
423 NagPackSuppression(
424 id="AwsSolutions-IAM4",
425 reason=(
426 "API Gateway CloudWatch role requires the AWS managed policy "
427 "AmazonAPIGatewayPushToCloudWatchLogs for logging functionality."
428 ),
429 applies_to=[
430 "Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs",
431 ],
432 ),
433 # CdkNagValidationFailure for structured logging check
434 NagPackSuppression(
435 id="CdkNagValidationFailure",
436 reason=(
437 "Validation failure due to CloudFormation intrinsic functions. "
438 "Access logging is properly configured on the API Gateway stage."
439 ),
440 ),
441 ],
442 )
445def add_monitoring_suppressions(stack: Stack) -> None:
446 """Add suppressions for monitoring-related cdk-nag findings."""
447 NagSuppressions.add_stack_suppressions(
448 stack,
449 [
450 NagPackSuppression(
451 id="AwsSolutions-SNS3",
452 reason="SNS topic has enforce_ssl=True enabled, which adds the required policy.",
453 ),
454 NagPackSuppression(
455 id="HIPAA.Security-SNSEncryptedKMS",
456 reason=(
457 "Alert notifications contain operational data (alarm names, thresholds) "
458 "not PHI. KMS encryption adds latency to time-sensitive alerts."
459 ),
460 ),
461 NagPackSuppression(
462 id="NIST.800.53.R5-SNSEncryptedKMS",
463 reason=(
464 "Alert notifications contain operational data (alarm names, thresholds). "
465 "KMS encryption adds latency to time-sensitive alerts."
466 ),
467 ),
468 NagPackSuppression(
469 id="PCI.DSS.321-SNSEncryptedKMS",
470 reason=(
471 "Alert notifications contain operational data (alarm names, thresholds). "
472 "KMS encryption can be enabled if required for PCI compliance."
473 ),
474 ),
475 # CloudWatch Log Group encryption
476 NagPackSuppression(
477 id="HIPAA.Security-CloudWatchLogGroupEncrypted",
478 reason="CloudWatch Logs are encrypted by default with AWS-managed keys.",
479 ),
480 NagPackSuppression(
481 id="NIST.800.53.R5-CloudWatchLogGroupEncrypted",
482 reason="CloudWatch Logs are encrypted by default with AWS-managed keys.",
483 ),
484 NagPackSuppression(
485 id="PCI.DSS.321-CloudWatchLogGroupEncrypted",
486 reason="CloudWatch Logs are encrypted by default with AWS-managed keys.",
487 ),
488 # CloudWatch Alarm Action suppressions for composite alarm inputs
489 # These alarms are intentionally used only as inputs to composite alarms
490 # The composite alarms have actions attached, not the individual alarms
491 NagPackSuppression(
492 id="HIPAA.Security-CloudWatchAlarmAction",
493 reason=(
494 "These alarms are inputs to composite alarms which have SNS actions. "
495 "Individual alarms don't need actions as they're aggregated for better signal-to-noise."
496 ),
497 ),
498 NagPackSuppression(
499 id="NIST.800.53.R5-CloudWatchAlarmAction",
500 reason=(
501 "These alarms are inputs to composite alarms which have SNS actions. "
502 "Individual alarms don't need actions as they're aggregated for better signal-to-noise."
503 ),
504 ),
505 ],
506 )
509def add_storage_suppressions(stack: Stack) -> None:
510 """Add suppressions for storage-related cdk-nag findings."""
511 NagSuppressions.add_stack_suppressions(
512 stack,
513 [
514 # EFS backup suppressions
515 NagPackSuppression(
516 id="HIPAA.Security-EFSInBackupPlan",
517 reason=(
518 "EFS backup is optional and can be enabled via AWS Backup if required. "
519 "Default deployment prioritizes cost optimization."
520 ),
521 ),
522 NagPackSuppression(
523 id="NIST.800.53.R5-EFSInBackupPlan",
524 reason=(
525 "EFS backup is optional and can be enabled via AWS Backup if required. "
526 "Default deployment prioritizes cost optimization."
527 ),
528 ),
529 # CloudWatch Log Group encryption
530 NagPackSuppression(
531 id="HIPAA.Security-CloudWatchLogGroupEncrypted",
532 reason=(
533 "CloudWatch Logs are encrypted by default with AWS-managed keys. "
534 "CDK Provider log groups are for infrastructure automation only."
535 ),
536 ),
537 NagPackSuppression(
538 id="NIST.800.53.R5-CloudWatchLogGroupEncrypted",
539 reason=(
540 "CloudWatch Logs are encrypted by default with AWS-managed keys. "
541 "CDK Provider log groups are for infrastructure automation only."
542 ),
543 ),
544 NagPackSuppression(
545 id="PCI.DSS.321-CloudWatchLogGroupEncrypted",
546 reason=(
547 "CloudWatch Logs are encrypted by default with AWS-managed keys. "
548 "CDK Provider log groups are for infrastructure automation only."
549 ),
550 ),
551 ],
552 )
555def add_sqs_suppressions(stack: Stack) -> None:
556 """Add suppressions for SQS-related cdk-nag findings."""
557 NagSuppressions.add_stack_suppressions(
558 stack,
559 [
560 NagPackSuppression(
561 id="AwsSolutions-SQS4",
562 reason="SQS queues have enforce_ssl=True enabled, which adds the required policy.",
563 ),
564 NagPackSuppression(
565 id="Serverless-SQSRedrivePolicy",
566 reason=(
567 "The dead-letter queue itself does not need a redrive policy. "
568 "The main job queue has a redrive policy pointing to the DLQ."
569 ),
570 ),
571 ],
572 )
575def add_secrets_suppressions(stack: Stack) -> None:
576 """Add suppressions for Secrets Manager-related cdk-nag findings."""
577 NagSuppressions.add_stack_suppressions(
578 stack,
579 [
580 # KMS key suppressions - using AWS-managed keys is acceptable
581 NagPackSuppression(
582 id="HIPAA.Security-SecretsManagerUsingKMSKey",
583 reason=(
584 "Secrets Manager encrypts secrets by default with AWS-managed keys. "
585 "Customer-managed KMS can be enabled if required for compliance."
586 ),
587 ),
588 NagPackSuppression(
589 id="NIST.800.53.R5-SecretsManagerUsingKMSKey",
590 reason="Secrets Manager encrypts secrets by default with AWS-managed keys.",
591 ),
592 NagPackSuppression(
593 id="PCI.DSS.321-SecretsManagerUsingKMSKey",
594 reason=(
595 "Secrets Manager encrypts secrets by default with AWS-managed keys. "
596 "Customer-managed KMS can be enabled if required for PCI compliance."
597 ),
598 ),
599 ],
600 )
603def add_eks_cluster_suppressions(stack: Stack) -> None:
604 """Add suppressions for EKS cluster-specific findings."""
605 NagSuppressions.add_stack_suppressions(
606 stack,
607 [
608 NagPackSuppression(
609 id="AwsSolutions-EKS1",
610 reason=(
611 "EKS public endpoint is enabled for kubectl access from CI/CD pipelines "
612 "and developer workstations. Access is controlled via IAM."
613 ),
614 ),
615 # CdkNagValidationFailure suppressions for security group rules with intrinsic functions
616 NagPackSuppression(
617 id="CdkNagValidationFailure",
618 reason=(
619 "Security group rules use VPC CIDR block via CloudFormation intrinsic function. "
620 "The rule restricts access to VPC CIDR only, which is secure."
621 ),
622 ),
623 ],
624 )
627def add_backup_suppressions(stack: Stack) -> None:
628 """Add suppressions for AWS Backup-related cdk-nag findings."""
629 NagSuppressions.add_stack_suppressions(
630 stack,
631 [
632 NagPackSuppression(
633 id="AwsSolutions-IAM4",
634 reason=(
635 "AWS Backup requires the AWSBackupServiceRolePolicyForBackup managed policy "
636 "attached to the backup service role to perform backup operations on DynamoDB tables. "
637 "This is the AWS-recommended policy for AWS Backup default service roles. "
638 "See: https://docs.aws.amazon.com/aws-backup/latest/devguide/iam-service-roles.html"
639 ),
640 applies_to=[
641 "Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup",
642 ],
643 ),
644 ],
645 )
648def add_aurora_pgvector_suppressions(stack: Stack) -> None:
649 """Add suppressions for Aurora pgvector-related cdk-nag findings.
651 Aurora Serverless v2 with pgvector triggers several compliance findings
652 that are intentionally accepted for this deployment pattern.
653 """
654 NagSuppressions.add_stack_suppressions(
655 stack,
656 [
657 # Secrets Manager KMS key — Aurora secret uses AWS-managed encryption
658 NagPackSuppression(
659 id="HIPAA.Security-SecretsManagerUsingKMSKey",
660 reason=(
661 "Aurora Serverless v2 credentials in Secrets Manager are encrypted with "
662 "AWS-managed keys by default. Customer-managed KMS can be enabled if required."
663 ),
664 ),
665 NagPackSuppression(
666 id="NIST.800.53.R5-SecretsManagerUsingKMSKey",
667 reason=(
668 "Aurora Serverless v2 credentials in Secrets Manager are encrypted with "
669 "AWS-managed keys by default."
670 ),
671 ),
672 # Secrets Manager rotation — Aurora manages rotation via RDS integration
673 NagPackSuppression(
674 id="HIPAA.Security-SecretsManagerRotationEnabled",
675 reason=(
676 "Aurora manages credential rotation via the RDS integration with Secrets "
677 "Manager. Manual rotation configuration is not required."
678 ),
679 ),
680 NagPackSuppression(
681 id="NIST.800.53.R5-SecretsManagerRotationEnabled",
682 reason=(
683 "Aurora manages credential rotation via the RDS integration with Secrets "
684 "Manager. Manual rotation configuration is not required."
685 ),
686 ),
687 # RDS in backup plan — Aurora has built-in continuous backups
688 NagPackSuppression(
689 id="HIPAA.Security-RDSInBackupPlan",
690 reason=(
691 "Aurora Serverless v2 has built-in continuous backups with point-in-time "
692 "recovery. AWS Backup integration is optional and can be enabled if required."
693 ),
694 ),
695 NagPackSuppression(
696 id="NIST.800.53.R5-RDSInBackupPlan",
697 reason=(
698 "Aurora Serverless v2 has built-in continuous backups with point-in-time "
699 "recovery. AWS Backup integration is optional."
700 ),
701 ),
702 # RDS logging enabled — covered by cloudwatch_logs_exports=["postgresql"]
703 # but some frameworks check for additional log types
704 NagPackSuppression(
705 id="HIPAA.Security-RDSLoggingEnabled",
706 reason=(
707 "PostgreSQL logs are exported to CloudWatch via cloudwatch_logs_exports. "
708 "Aurora Serverless v2 does not support all log types available on provisioned instances."
709 ),
710 ),
711 NagPackSuppression(
712 id="NIST.800.53.R5-RDSLoggingEnabled",
713 reason=(
714 "PostgreSQL logs are exported to CloudWatch via cloudwatch_logs_exports. "
715 "Aurora Serverless v2 does not support all log types available on provisioned instances."
716 ),
717 ),
718 NagPackSuppression(
719 id="PCI.DSS.321-RDSLoggingEnabled",
720 reason=(
721 "PostgreSQL logs are exported to CloudWatch via cloudwatch_logs_exports. "
722 "Aurora Serverless v2 does not support all log types available on provisioned instances."
723 ),
724 ),
725 # CloudWatch Log Group encryption for Aurora logs
726 NagPackSuppression(
727 id="HIPAA.Security-CloudWatchLogGroupEncrypted",
728 reason=(
729 "CloudWatch Logs for Aurora PostgreSQL are encrypted by default with "
730 "AWS-managed keys. Customer-managed KMS can be enabled if required."
731 ),
732 ),
733 NagPackSuppression(
734 id="NIST.800.53.R5-CloudWatchLogGroupEncrypted",
735 reason=(
736 "CloudWatch Logs for Aurora PostgreSQL are encrypted by default with "
737 "AWS-managed keys."
738 ),
739 ),
740 NagPackSuppression(
741 id="PCI.DSS.321-CloudWatchLogGroupEncrypted",
742 reason=(
743 "CloudWatch Logs for Aurora PostgreSQL are encrypted by default with "
744 "AWS-managed keys."
745 ),
746 ),
747 # Enhanced monitoring IAM role uses AWS managed policy
748 NagPackSuppression(
749 id="AwsSolutions-IAM4",
750 reason=(
751 "Aurora enhanced monitoring requires the AWS managed policy "
752 "AmazonRDSEnhancedMonitoringRole for publishing OS-level metrics to CloudWatch. "
753 "This is the AWS-recommended policy for RDS enhanced monitoring. "
754 "See: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Monitoring.OS.Enabling.html"
755 ),
756 applies_to=[
757 "Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole",
758 ],
759 ),
760 ],
761 )
764def apply_all_suppressions(
765 stack: Stack,
766 stack_type: str = "regional",
767 regions: list[str] | None = None,
768 global_region: str | None = None,
769) -> None:
770 """Apply all relevant suppressions to a stack.
772 Args:
773 stack: The CDK stack to apply suppressions to
774 stack_type: Type of stack - 'regional', 'global', 'api_gateway', or 'monitoring'
775 regions: List of regional deployment regions (for dynamic IAM suppression patterns)
776 global_region: Global region for SSM parameters (for dynamic IAM suppression patterns)
777 """
778 # Common suppressions for all stacks
779 add_lambda_suppressions(stack)
780 add_iam_suppressions(stack, regions=regions, global_region=global_region)
782 if stack_type == "regional":
783 add_eks_suppressions(stack)
784 add_eks_cluster_suppressions(stack)
785 add_vpc_suppressions(stack)
786 add_storage_suppressions(stack)
787 add_sqs_suppressions(stack)
788 add_aurora_pgvector_suppressions(stack)
790 elif stack_type == "global":
791 add_backup_suppressions(stack)
793 elif stack_type == "api_gateway":
794 add_api_gateway_suppressions(stack)
795 add_secrets_suppressions(stack)
797 elif stack_type == "monitoring":
798 add_monitoring_suppressions(stack)