diff --git a/infra/cdk/NAG.md b/infra/cdk/NAG.md new file mode 100644 index 00000000..cb056bed --- /dev/null +++ b/infra/cdk/NAG.md @@ -0,0 +1,64 @@ +# cdk-nag / CDK version ceiling + +## Current pinned versions +- `aws-cdk-lib`: **2.250.0** +- `cdk-nag`: **2.38.2** +- EKS: stable `software.amazon.awscdk.services.eks_v2` (the deprecated `eks-v2-alpha` module was dropped). + +`cdk synth` passes with **0 cdk-nag findings** under the latest CDK CLI with this +combination. IAM4/IAM5 suppressions in `WorkshopApp` carry explicit `appliesTo` +evidence (a bare `AwsSolutions-IAM5` id does not suppress). + +## Why not newer + +`aws-cdk-lib` 2.251.0 introduced CDK's native policy-validation framework +(`software.amazon.awscdk.Validations`). From 2.251 onward, cdk-nag findings are +routed through it and must be suppressed via `Validations.of(scope).acknowledge()` +instead of `NagSuppressions`. + +That acknowledge API treats `::` as a reserved `prefix::ruleName` delimiter, so it +rejects finding ids that embed IAM ARNs (which contain `iam::aws` and +`arn::...`), e.g.: + + AwsSolutions::AwsSolutions-IAM4[Policy::arn::iam::aws:policy/AdministratorAccess] + -> InvalidValidationId: The '::' delimiter is reserved for separating the prefix from the rule name + +Because every AWS managed-policy finding embeds `iam::aws`, IAM4/IAM5 findings +cannot currently be acknowledged on aws-cdk-lib >= 2.251. + +cdk-nag 3.x does not help: its `NagPack` is plugin-only +(`IPolicyValidationPlugin`, no `IAspect`), so it relies entirely on the same +native `acknowledge` mechanism and cannot run report-only either. + +Verified: 2.250 synth passes (0 findings); 2.260 synth fails with 19 IAM4/IAM5 +findings even with correct `appliesTo`. + +## Trigger to update + +Do NOT pin the CDK CLI and do NOT add a Dependabot `ignore` for these bumps. +CI runs `cdk synth` with the latest CLI, so the Dependabot PR that bumps +`aws-cdk-lib` to >= 2.251 (or `cdk-nag` to 3.x) is a live tripwire: + +- While the `build-infra` check on that PR is **red**, the upstream gap is still open. +- When that check goes **green**, the fix has landed. Then: + 1. bump `aws-cdk-lib` (and optionally `cdk-nag` to 3.x), + 2. switch the IAM4/IAM5 suppressions in `WorkshopApp` from + `NagSuppressions` to `Validations.of(stack).acknowledge(...)`, + 3. delete this note. + +### Manual recheck +On a scratch branch with `aws-cdk-lib >= 2.251` + `cdk-nag` 3.x, confirm that + + Validations.of(stack).acknowledge( + Acknowledgment.builder() + .id("AwsSolutions-IAM4[Policy::arn::iam::aws:policy/AdministratorAccess]") + .reason("...").build()); + +no longer throws `InvalidValidationId` and that `cdk synth` exits 0. + +## Upstream references +- aws/aws-cdk#26844 - cdk synth used to return exit 0 despite policy-validation + failures (fixed in recent CLIs; this is what surfaced the findings). +- cdk-nag v3 README: prefix / bulk suppression "not yet supported" (tracked upstream). +- Watch `aws-cdk-lib` release notes for `Validations.acknowledge` id parsing that + accepts embedded `::`. diff --git a/infra/cdk/pom.xml b/infra/cdk/pom.xml index c4dbaabe..cdf7d80d 100644 --- a/infra/cdk/pom.xml +++ b/infra/cdk/pom.xml @@ -11,7 +11,7 @@ UTF-8 25 25 - 2.235.0 + 2.250.0 10.6.0 2.38.2 6.1.1 @@ -54,13 +54,6 @@ ${constructs.version} - - - software.amazon.awscdk - eks-v2-alpha - ${cdk.version}-alpha.0 - - io.github.cdklabs diff --git a/infra/cdk/src/main/java/sample/com/WorkshopApp.java b/infra/cdk/src/main/java/sample/com/WorkshopApp.java index 4f2b99e7..35bbbb1d 100644 --- a/infra/cdk/src/main/java/sample/com/WorkshopApp.java +++ b/infra/cdk/src/main/java/sample/com/WorkshopApp.java @@ -37,9 +37,24 @@ public static void main(final String[] args) { new NagPackSuppression.Builder().id("AwsSolutions-APIG6").reason("API Gateway access logging not needed for workshop").build(), new NagPackSuppression.Builder().id("AwsSolutions-COG4").reason("Workshop environment does not require Cognito User Pool authorization").build(), - // IAM - new NagPackSuppression.Builder().id("AwsSolutions-IAM4").reason("AWS Managed policies are acceptable for workshop").build(), - new NagPackSuppression.Builder().id("AwsSolutions-IAM5").reason("Wildcard permissions acceptable for workshop parallel resource creation").build(), + // IAM - IAM4/IAM5 require appliesTo evidence to suppress + new NagPackSuppression.Builder().id("AwsSolutions-IAM4") + .appliesTo(List.of( + "Policy::arn::iam::aws:policy/AdministratorAccess", + "Policy::arn::iam::aws:policy/PowerUserAccess", + "Policy::arn::iam::aws:policy/ReadOnlyAccess", + "Policy::arn::iam::aws:policy/AmazonSSMManagedInstanceCore", + "Policy::arn::iam::aws:policy/CloudWatchAgentServerPolicy", + "Policy::arn::iam::aws:policy/service-role/AWSLambdaBasicExecutionRole")) + .reason("AWS managed policies are acceptable for workshop").build(), + new NagPackSuppression.Builder().id("AwsSolutions-IAM5") + .appliesTo(List.of( + "Resource::*", + "Resource::arn::ec2:::network-interface/*", + "Resource::arn::codebuild:::report-group/-*", + "Resource::arn::logs:::log-group:/aws/codebuild/:*", + "Resource::arn:aws:logs:::log-group:/aws/bedrock/*")) + .reason("Wildcard permissions acceptable for workshop parallel resource creation").build(), // RDS new NagPackSuppression.Builder().id("AwsSolutions-RDS2").reason("Workshop non-sensitive test database does not need encryption at rest").build(), diff --git a/infra/cdk/src/main/java/sample/com/constructs/Eks.java b/infra/cdk/src/main/java/sample/com/constructs/Eks.java index 2792754e..8523435e 100644 --- a/infra/cdk/src/main/java/sample/com/constructs/Eks.java +++ b/infra/cdk/src/main/java/sample/com/constructs/Eks.java @@ -3,15 +3,15 @@ import software.amazon.awscdk.services.ec2.IVpc; import software.amazon.awscdk.services.ec2.ISecurityGroup; import software.amazon.awscdk.services.iam.IRole; -import software.amazon.awscdk.services.eks.v2.alpha.Cluster; -import software.amazon.awscdk.services.eks.v2.alpha.KubernetesVersion; -import software.amazon.awscdk.services.eks.v2.alpha.AccessEntry; -import software.amazon.awscdk.services.eks.v2.alpha.AccessEntryType; -import software.amazon.awscdk.services.eks.v2.alpha.AccessPolicy; -import software.amazon.awscdk.services.eks.v2.alpha.IAccessPolicy; -import software.amazon.awscdk.services.eks.v2.alpha.AccessPolicyNameOptions; -import software.amazon.awscdk.services.eks.v2.alpha.AccessScopeType; -import software.amazon.awscdk.services.eks.v2.alpha.Addon; +import software.amazon.awscdk.services.eks_v2.Cluster; +import software.amazon.awscdk.services.eks_v2.KubernetesVersion; +import software.amazon.awscdk.services.eks_v2.AccessEntry; +import software.amazon.awscdk.services.eks_v2.AccessEntryType; +import software.amazon.awscdk.services.eks_v2.AccessPolicy; +import software.amazon.awscdk.services.eks_v2.IAccessPolicy; +import software.amazon.awscdk.services.eks_v2.AccessPolicyNameOptions; +import software.amazon.awscdk.services.eks_v2.AccessScopeType; +import software.amazon.awscdk.services.eks_v2.Addon; import software.amazon.awscdk.services.iam.Effect; import software.amazon.awscdk.services.iam.ManagedPolicy; import software.amazon.awscdk.services.iam.PolicyStatement; diff --git a/infra/cdk/src/main/java/sample/com/constructs/ThreadAnalysis.java b/infra/cdk/src/main/java/sample/com/constructs/ThreadAnalysis.java index e21ea17e..86daff07 100644 --- a/infra/cdk/src/main/java/sample/com/constructs/ThreadAnalysis.java +++ b/infra/cdk/src/main/java/sample/com/constructs/ThreadAnalysis.java @@ -3,13 +3,13 @@ import software.amazon.awscdk.Duration; import software.amazon.awscdk.RemovalPolicy; import software.amazon.awscdk.services.ec2.*; -import software.amazon.awscdk.services.eks.v2.alpha.AccessEntry; -import software.amazon.awscdk.services.eks.v2.alpha.AccessEntryType; -import software.amazon.awscdk.services.eks.v2.alpha.AccessPolicy; -import software.amazon.awscdk.services.eks.v2.alpha.AccessPolicyNameOptions; -import software.amazon.awscdk.services.eks.v2.alpha.AccessScopeType; -import software.amazon.awscdk.services.eks.v2.alpha.Cluster; -import software.amazon.awscdk.services.eks.v2.alpha.IAccessPolicy; +import software.amazon.awscdk.services.eks_v2.AccessEntry; +import software.amazon.awscdk.services.eks_v2.AccessEntryType; +import software.amazon.awscdk.services.eks_v2.AccessPolicy; +import software.amazon.awscdk.services.eks_v2.AccessPolicyNameOptions; +import software.amazon.awscdk.services.eks_v2.AccessScopeType; +import software.amazon.awscdk.services.eks_v2.Cluster; +import software.amazon.awscdk.services.eks_v2.IAccessPolicy; import software.amazon.awscdk.services.iam.*; import software.amazon.awscdk.services.lambda.Code; import software.amazon.awscdk.services.lambda.Function; diff --git a/infra/cdk/src/main/resources/iam-policy.json b/infra/cdk/src/main/resources/iam-policy.json index 8a7f4773..223c5d73 100644 --- a/infra/cdk/src/main/resources/iam-policy.json +++ b/infra/cdk/src/main/resources/iam-policy.json @@ -17,7 +17,7 @@ "prod-xdkflymybwmvi", "prod-mxcfnwvpd6kb4", "prod-jhuafngbly644", - "prod-4pmewlybdftbs", + "prod-5ukwuglpt66kg", "prod-ffvjxvh4ltq64" ] }