shoc-frontend-new/infra/cdk/README.md

5.6 KiB

Frontend infrastructure and migration rehearsal

This CDK app describes the existing Sea Haven SHOC SPA hosting and an isolated, production-shaped Terraform adoption rehearsal. It performs no content upload. Content-only deployment is handled by scripts/deploy-web.sh.

Existing environments

Normal synthesis remains unchanged when the adoption flag is off:

  • private, versioned S3 bucket with CDK auto-delete cleanup
  • CloudFront distribution and origin access control
  • viewer-request function that rewrites extensionless SPA routes
  • optional Route 53 A and AAAA aliases
  • GitHub Actions OIDC deploy role

Dev remains the default context in cdk.json. Staging uses explicit context arguments. During migration, both content workflows are manual-only and use fixed environment configuration rather than discovering deployment targets from CloudFormation.

Terraform POC

The POC is isolated in account 396287094661, region us-east-1, and is created only with -c tfPoc=true plus an explicit tfPocPhase. It uses three ownership scopes:

  1. shoc-frontend-tf-poc-shared: a dedicated public hosted zone for frontend-tf-poc.seahaven.com.
  2. shoc-frontend-tf-poc-certificate: the DNS-validated ACM certificate.
  3. shoc-frontend-tf-poc: the private versioned bucket, CloudFront OAC, distribution, SPA function, A/AAAA aliases, and GitHub OIDC content deploy role.

Fixed application values:

  • bucket: seahaven-shoc-frontend-tf-poc
  • role: githubdeploy-shoc-frontend-new-tf-poc
  • GitHub environment: tf-poc
  • site: https://frontend-tf-poc.seahaven.com
  • API: https://api.tf-poc.seahaven.com/api

The shared stack is intentionally staged. The zone must exist and be delegated before ACM can validate a certificate inside it:

cd infra/cdk
npm ci
npm test
npm run synth:tf-poc-zone
npm run synth:tf-poc-environment

After approval, deploy only shoc-frontend-tf-poc-shared with tfPocPhase=zone. Its outputs provide the child name servers. Create the parent NS record as a separate approved change and verify public delegation. Only then use tfPocPhase=environment to deploy the separate certificate and site stacks. The zone stack never contains the certificate, so re-running the zone phase cannot remove a certificate created by the environment phase. Omitting tfPocPhase fails closed.

The stacks output the hosted zone ID, certificate ARN, delegation evidence, workspace tag, boundary ARN, and import IDs for the bucket, bucket policy, distribution, OAC, SPA function, A/AAAA records, deploy role, and inline role policy. They also emit the generated OAC name/description, deterministic origin ID, and inline policy name required by the tf-poc Terraform configuration.

Adoption retention

-c retainForTerraformAdoption=true is deliberately opt-in. Keep it enabled from the reviewed retention deployment through CloudFormation ownership detachment.

The emitted template applies both DeletionPolicy: Retain and UpdateReplacePolicy: Retain to:

  • site bucket and bucket policy
  • distribution, OAC, and SPA rewrite function
  • A and AAAA records
  • GitHub deploy role and its inline policy
  • SiteBucket/AutoDeleteObjectsCustomResource

The bucket remains configured with autoDeleteObjects: true. The emitted bucket and its matching custom resource are both retained, so deleting the stack cannot invoke that custom resource to empty the versioned bucket. Generated provider Lambda resources, provider IAM resources, provider logs, and CDK metadata are intentionally excluded. Template tests enforce this exact boundary.

In adoption mode, the deploy role also receives:

  • tag HcpTerraformWorkspace=shoc-frontend-new-{env}
  • permissions boundary arn:aws:iam::<account>:policy/shoc-frontend-new-{env}-deploy-boundary
  • exact StringEquals OIDC subject matching; for dev this narrows the current no-wildcard StringLike subject before Terraform import

These changes are absent when the flag is off.

Content deployment safeguards

scripts/deploy-web.sh requires explicit target and expectation variables:

  • SITE_BUCKET and matching EXPECTED_SITE_BUCKET
  • CLOUDFRONT_DISTRIBUTION_ID
  • SITE_URL
  • VITE_API_URL and matching EXPECTED_API_URL
  • DEPLOY_RELEASE_ID or GITHUB_SHA
  • optional comma-separated FORBIDDEN_API_URLS
  • optional API_SMOKE_URL and API_CORS_ORIGIN

The script verifies bucket versioning, builds the app, publishes immutable assets and a no-cache index, records a release manifest, invalidates and waits, then checks /, /login, an extensionless route, asset references, API URLs, and cache headers. Optional API preflight checks verify CORS.

If verification fails after publishing the index, the previous index version is restored and invalidated. Pruning starts only after successful remote verification. Current versions needed by the latest two release manifests are kept; unreferenced object versions are deleted.

Manual workflows

  • .github/workflows/deploy.yml: dev content deployment
  • .github/workflows/deploy-staging.yml: staging content deployment
  • .github/workflows/deploy-tf-poc.yml: isolated POC content deployment

All are workflow_dispatch only. Staging and tf-poc retain their GitHub environment protection and exact environment-scoped OIDC trust. Each dev and staging distribution ID is pinned in its workflow. The tf-poc environment must define its generated CLOUDFRONT_DISTRIBUTION_ID as a protected variable. Each workflow pins its environment's Swagger URL for API CORS/preflight checks.

Infrastructure creation, parent-zone delegation, Terraform imports, and ownership detachment remain separate administrator actions. None of these workflows performs them.