diff --git a/lib/account-baseline-stack.ts b/lib/account-baseline-stack.ts index bde8c5a..5127107 100644 --- a/lib/account-baseline-stack.ts +++ b/lib/account-baseline-stack.ts @@ -258,8 +258,12 @@ export class AccountBaselineStack extends cdk.Stack { // deletion policy has to be in the live template before the construct is // removed, or CloudFormation Deletes, fails, and rollback tries to // recreate it. The SSM parameter stays on Delete. + // existingWebAclId keeps the parameter and output off WebACL.Arn. GetAtt + // calls GetWebACL, which fails because the ACL is gone. The id is the + // physical id CloudFormation already recorded for AppWebAclFE38F02F. new AppWebAcl(this, "AppWebAcl", { webAclRemovalPolicy: cdk.RemovalPolicy.RETAIN, + existingWebAclId: "cd668fe8-5cff-4d6a-9432-5c32145a7db4", }); // ── Day 5 AI governance ── diff --git a/lib/web-acl.ts b/lib/web-acl.ts index 880782e..76335c5 100644 --- a/lib/web-acl.ts +++ b/lib/web-acl.ts @@ -21,6 +21,13 @@ export interface AppWebAclProps { * already gone and a Delete call would fail and roll back into a recreate. */ readonly webAclRemovalPolicy?: cdk.RemovalPolicy; + /** + * Physical id of a WebACL CloudFormation already tracks. When set, the SSM + * parameter and output publish `global/webacl/seahaven-app-waf/` with + * account and region tokens, and do not reference WebACL.Arn. GetAtt on a + * missing ACL calls GetWebACL and fails the stack update. + */ + readonly existingWebAclId?: string; } export class AppWebAcl extends Construct { @@ -78,12 +85,21 @@ export class AppWebAcl extends Construct { webAcl.applyRemovalPolicy(props.webAclRemovalPolicy); } + const publishedArn = props?.existingWebAclId + ? cdk.Stack.of(this).formatArn({ + service: "wafv2", + resource: "global/webacl", + resourceName: `seahaven-app-waf/${props.existingWebAclId}`, + arnFormat: cdk.ArnFormat.SLASH_RESOURCE_NAME, + }) + : webAcl.attrArn; + new ssm.StringParameter(this, "AppWebAclArnParam", { parameterName: "/seahaven/waf/app-web-acl-arn", - stringValue: webAcl.attrArn, + stringValue: publishedArn, description: "ARN of the shared CloudFront WAF WebACL (audit M-17)", }); - new cdk.CfnOutput(this, "AppWebAclArn", { value: webAcl.attrArn }); + new cdk.CfnOutput(this, "AppWebAclArn", { value: publishedArn }); } }