diff --git a/labs/unicorn-store/infrastructure/cdk/pom.xml b/labs/unicorn-store/infrastructure/cdk/pom.xml
index efa27f7fa..328c2b624 100644
--- a/labs/unicorn-store/infrastructure/cdk/pom.xml
+++ b/labs/unicorn-store/infrastructure/cdk/pom.xml
@@ -10,7 +10,7 @@
UTF-8UTF-8
- 2.257.0
+ 2.261.06.1.0
@@ -21,8 +21,8 @@
maven-compiler-plugin3.15.0
- 17
- 17
+ 25
+ 25
@@ -48,7 +48,7 @@
io.github.cdklabscdknag
- 2.38.2
+ 3.0.1
diff --git a/labs/unicorn-store/infrastructure/cdk/src/main/java/com/unicorn/UnicornStoreApp.java b/labs/unicorn-store/infrastructure/cdk/src/main/java/com/unicorn/UnicornStoreApp.java
index fe38c4cd4..ac99980b4 100644
--- a/labs/unicorn-store/infrastructure/cdk/src/main/java/com/unicorn/UnicornStoreApp.java
+++ b/labs/unicorn-store/infrastructure/cdk/src/main/java/com/unicorn/UnicornStoreApp.java
@@ -1,6 +1,6 @@
package com.unicorn;
-import java.util.List;
+import java.util.HashMap;
import com.unicorn.alternatives.UnicornAuditService;
import com.unicorn.alternatives.UnicornStoreMicronaut;
@@ -9,11 +9,8 @@
import com.unicorn.core.InfrastructureStack;
import io.github.cdklabs.cdknag.AwsSolutionsChecks;
-import io.github.cdklabs.cdknag.NagPackSuppression;
-import io.github.cdklabs.cdknag.NagSuppressions;
-import software.amazon.awscdk.App;
-import software.amazon.awscdk.Aspects;
-import software.amazon.awscdk.StackProps;
+import io.github.cdklabs.cdknag.NagPackProps;
+import software.amazon.awscdk.*;
public class UnicornStoreApp {
@@ -23,51 +20,54 @@ public static void main(final String[] args) {
var infrastructureStack = new InfrastructureStack(app, "UnicornStoreInfrastructure", StackProps.builder()
.build());
- var unicornStoreSpring = new UnicornStoreStack(app, "UnicornStoreSpringApp", StackProps.builder()
+ new UnicornStoreStack(app, "UnicornStoreSpringApp", StackProps.builder()
.build(), infrastructureStack);
- var unicornStoreMicronaut = new UnicornStoreMicronaut(app, "UnicornStoreMicronautApp", StackProps.builder()
+ new UnicornStoreMicronaut(app, "UnicornStoreMicronautApp", StackProps.builder()
.build(), infrastructureStack);
- var unicornStoreSpringGraalVM = new UnicornStoreSpringGraalVM(app, "UnicornStoreSpringGraalVMApp", StackProps.builder()
+ new UnicornStoreSpringGraalVM(app, "UnicornStoreSpringGraalVMApp", StackProps.builder()
.build(), infrastructureStack);
- var unicornStoreQuarkus = new UnicornStoreQuarkus(app, "UnicornStoreQuarkusApp", StackProps.builder()
+ new UnicornStoreQuarkus(app, "UnicornStoreQuarkusApp", StackProps.builder()
.build(), infrastructureStack);
- var unicornAuditService = new UnicornAuditService(app, "UnicornAuditServiceApp", StackProps.builder()
+ new UnicornAuditService(app, "UnicornAuditServiceApp", StackProps.builder()
.build(), infrastructureStack);
-
//Add CDK-NAG checks: https://github.com/cdklabs/cdk-nag
+ Validations.of(app).addPlugins(new AwsSolutionsChecks(app,
+ NagPackProps.builder().writeSuppressionsToCloudFormation(true).build()));
+
//Add suppression to exclude certain findings that are not needed for Workshop environment
- Aspects.of(app).add(new AwsSolutionsChecks());
- var suppression = List.of(
- new NagPackSuppression.Builder().id("AwsSolutions-APIG4").reason("The workshop environment does not require API-Gateway authorization").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-COG4").reason("The workshop environment does not require Cognito User Pool authorization").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-RDS3").reason("Workshop environment does not need a Multi-AZ setup to reduce cost").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-IAM4").reason("AWS Managed policies are acceptable for the workshop").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-IAM5").reason("A wildcard is acceptable for this workshop to allow parallel creation of resources").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-RDS10").reason("Workshop environment is ephemeral and the database should be deleted by the end of the workshop").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-RDS11").reason("Database is in a private subnet and can use the default port").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-APIG2").reason("API Gateway request validation is not needed for workshop").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-APIG1").reason("API Gateway access logging not needed for workshop setup").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-APIG6").reason("API Gateway access logging not needed for workshop setup").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-VPC7").reason("Workshop environment does not need VPC flow logs").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-SMG4").reason("Ephemeral workshop environment does not need to rotate secrets").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-RDS2").reason("Workshop non-sensitive test database does not need encryption at rest").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-APIG3").reason("Workshop API Gateways do not need AWS WAF assigned").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-EC23").reason("Not needed").build(),
- new NagPackSuppression.Builder().id("AwsSolutions-RDS13").reason("Workshop Database does not need backups").build(),
- new NagPackSuppression.Builder().id("CdkNagValidationFailure").reason("Suppress warnings see: https://github.com/cdklabs/cdk-nag/issues/817").build()
+ Validations.of(app).acknowledge(
+ new Acknowledgment.Builder().id("AwsSolutions-APIG4").reason("The workshop environment does not require API-Gateway authorization").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-COG4").reason("The workshop environment does not require Cognito User Pool authorization").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-RDS3").reason("Workshop environment does not need a Multi-AZ setup to reduce cost").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-RDS10").reason("Workshop environment is ephemeral and the database should be deleted by the end of the workshop").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-RDS11").reason("Database is in a private subnet and can use the default port").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-APIG2").reason("API Gateway request validation is not needed for workshop").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-APIG1").reason("API Gateway access logging not needed for workshop setup").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-APIG6").reason("API Gateway access logging not needed for workshop setup").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-VPC7").reason("Workshop environment does not need VPC flow logs").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-SMG4").reason("Ephemeral workshop environment does not need to rotate secrets").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-RDS2").reason("Workshop non-sensitive test database does not need encryption at rest").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-APIG3").reason("Workshop API Gateways do not need AWS WAF assigned").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-EC23").reason("Not needed").build(),
+ new Acknowledgment.Builder().id("AwsSolutions-RDS13").reason("Workshop Database does not need backups").build(),
+ new Acknowledgment.Builder().id("CdkNagValidationFailure").reason("Suppress warnings see: https://github.com/cdklabs/cdk-nag/issues/817").build()
);
- NagSuppressions.addStackSuppressions(infrastructureStack, suppression);
- NagSuppressions.addStackSuppressions(unicornStoreSpring, suppression);
- NagSuppressions.addStackSuppressions(unicornStoreMicronaut, suppression);
- NagSuppressions.addStackSuppressions(unicornStoreSpringGraalVM, suppression);
- NagSuppressions.addStackSuppressions(unicornStoreQuarkus, suppression);
- NagSuppressions.addStackSuppressions(unicornAuditService, suppression);
+ // Suppress parameterized IAM findings directly via metadata
+ // (Validations.acknowledge() rejects IDs containing '::' due to CDK delimiter validation bug)
+ var iamSuppressions = new HashMap();
+ iamSuppressions.put("AwsSolutions-IAM4", "AWS Managed policies are acceptable for the workshop");
+ iamSuppressions.put("AwsSolutions-IAM5", "A wildcard is acceptable for this workshop to allow parallel creation of resources");
+ iamSuppressions.put("AwsSolutions-IAM4[Policy::arn::iam::aws:policy/service-role/AWSLambdaBasicExecutionRole]", "AWS Managed policies are acceptable for the workshop");
+ iamSuppressions.put("AwsSolutions-IAM4[Policy::arn::iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole]", "AWS Managed policies are acceptable for the workshop");
+ iamSuppressions.put("AwsSolutions-IAM4[Policy::arn::iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs]", "AWS Managed policies are acceptable for the workshop");
+ iamSuppressions.put("AwsSolutions-IAM5[Resource::arn:aws:secretsmanager:*:*:secret:unicornstore-db-secret-*]", "A wildcard is acceptable for this workshop");
+ app.getNode().addMetadata(Validations.ACKNOWLEDGED_RULES_METADATA_KEY, iamSuppressions);
app.synth();
}