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

1"""CDK-nag suppression utilities for GCO stacks. 

2 

3This module provides centralized suppression management for cdk-nag rules 

4that are intentionally not applicable or have documented justifications. 

5 

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 

12 

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""" 

19 

20from aws_cdk import Stack 

21from cdk_nag import NagPackSuppression, NagSuppressions 

22 

23 

24def add_eks_suppressions(stack: Stack) -> None: 

25 """Add suppressions for EKS-related cdk-nag findings. 

26 

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 ] 

45 

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 ) 

60 

61 

62def add_lambda_suppressions(stack: Stack) -> None: 

63 """Add suppressions for Lambda-related cdk-nag findings. 

64 

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 ] 

72 

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 ) 

169 

170 

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. 

175 

176 CDK generates inline policies for custom resources and some patterns 

177 require wildcard permissions for dynamic resource access. 

178 

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 ] 

193 

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 ) 

200 

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) 

207 

208 for region in ssm_regions: 

209 applies_to.append(f"Resource::arn:aws:ssm:{region}:<AWS::AccountId>:parameter/gco/*") 

210 

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 ) 

222 

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 ) 

231 

232 # KMS wildcard scoped to S3 via condition for model weights bucket decryption 

233 applies_to.append("Resource::arn:aws:kms:*:<AWS::AccountId>:key/*") 

234 

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 ) 

277 

278 

279def add_vpc_suppressions(stack: Stack) -> None: 

280 """Add suppressions for VPC-related cdk-nag findings. 

281 

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 ) 

335 

336 

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 ) 

443 

444 

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 ) 

507 

508 

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 ) 

553 

554 

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 ) 

573 

574 

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 ) 

601 

602 

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 ) 

625 

626 

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 ) 

646 

647 

648def add_aurora_pgvector_suppressions(stack: Stack) -> None: 

649 """Add suppressions for Aurora pgvector-related cdk-nag findings. 

650 

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 ) 

762 

763 

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. 

771 

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) 

781 

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) 

789 

790 elif stack_type == "global": 

791 add_backup_suppressions(stack) 

792 

793 elif stack_type == "api_gateway": 

794 add_api_gateway_suppressions(stack) 

795 add_secrets_suppressions(stack) 

796 

797 elif stack_type == "monitoring": 

798 add_monitoring_suppressions(stack)