mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 16:19:01 +00:00
Move the dev frontend to its custom domain now that the backend, DNS zones, and ACM cert all live in the dev account (396287094661): - CloudFront alias dev.seahaven.com with the *.seahaven.com ACM cert - /api/* proxied over HTTPS to api.dev.seahaven.com (no CORS, no mixed content) - Route 53 apex A/AAAA alias -> CloudFront in the delegated dev.seahaven.com zone Env-specific values (domain, cert, zone, API host, protocol) are parameterized and set in cdk.json context so the CI `cdk deploy` produces this with no flags; staging/prod override the same keys per environment.
156 lines
7.1 KiB
Markdown
156 lines
7.1 KiB
Markdown
# Infrastructure & CI/CD — SeaHaven SHOC frontend
|
|
|
|
AWS hosting for the Vite SPA, defined as an **AWS CDK** app local to this repo,
|
|
deployed through the org's **reusable** GitHub Actions workflow.
|
|
|
|
- **Hosting:** private S3 bucket (origin) + CloudFront, served on the custom
|
|
domain **`dev.seahaven.com`** (ACM `*.seahaven.com`, Route 53 apex alias).
|
|
- **API:** CloudFront proxies `/api/*` over HTTPS to `api.dev.seahaven.com`, so
|
|
the SPA calls it same-origin (`VITE_API_URL=/api`) — no CORS, no mixed content.
|
|
- Env-specific values (domain, cert, zone, API host) live in `cdk.json` context
|
|
so the CI `cdk deploy` picks them up with no flags.
|
|
- **Auth:** GitHub Actions → AWS via **OIDC** (no long-lived keys)
|
|
- **CD workflow:** `.github/workflows/deploy.yml` is a thin caller of the org's
|
|
`Sea-Haven-Industries/.github` → `cd-cdk.yaml`. That workflow runs `cdk deploy`
|
|
(provisions infra) then `scripts/deploy-web.sh` (builds + uploads the SPA).
|
|
- **Infra is local to this repo** (CDK in `infra/cdk`); the deploy role is
|
|
created by this stack, not added to the central `oidc-deploy-roles.yaml`.
|
|
- **Environments:** `dev` only today, deployed on push to the `dev` branch.
|
|
|
|
```
|
|
infra/cdk/
|
|
bin/app.ts entry point (reads -c context)
|
|
lib/frontend-stack.ts S3 + CloudFront + OAC + OIDC deploy role
|
|
scripts/deploy-web.sh build SPA -> s3 sync -> CloudFront invalidation
|
|
.github/workflows/
|
|
ci.yml quality gates (lint / build / test / e2e)
|
|
deploy.yml caller of the org reusable cd-cdk.yaml (push to dev)
|
|
```
|
|
|
|
## What the stack creates
|
|
|
|
| Resource | Purpose |
|
|
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
| S3 bucket `seahaven-shoc-frontend-dev` | private origin (BLOCK_ALL, SSE, OAC-only reads) |
|
|
| CloudFront distribution | HTTPS, gzip/br; default behavior → S3, `/api/*` → backend (HTTP origin) |
|
|
| CloudFront Function (viewer request) | SPA routing: rewrites extensionless paths to `/index.html` (scoped to the S3 behavior, so it never touches `/api`) |
|
|
| IAM role `githubdeploy-shoc-frontend-new-dev` | assumed by GitHub Actions via OIDC, scoped to `repo:Sea-Haven-Industries/shoc-frontend-new:ref:refs/heads/dev` |
|
|
|
|
The whole `cd-cdk.yaml` job runs as that role, so it holds: `sts:AssumeRole` on
|
|
`cdk-hnb659fds-*` (for `cdk deploy`), `cloudformation:DescribeStacks` (cd-cdk's
|
|
pre-flight/health-check + output reads), read/write on the bucket (`s3 sync`),
|
|
and `cloudfront:CreateInvalidation` (cache bust). The OIDC **provider** is a
|
|
singleton account resource — the stack only _imports_ it (created in step 2),
|
|
so `cdk destroy` can't delete a resource shared by other roles.
|
|
|
|
---
|
|
|
|
## One-time setup (run by a human with admin AWS creds)
|
|
|
|
### 1. Authenticate to the AWS account
|
|
|
|
```bash
|
|
aws configure # or: aws sso login --profile <admin>
|
|
aws sts get-caller-identity # confirm the right account + region (us-east-1)
|
|
```
|
|
|
|
### 2. Ensure the GitHub OIDC provider exists (once per account)
|
|
|
|
```bash
|
|
aws iam list-open-id-connect-providers
|
|
# If none ends in token.actions.githubusercontent.com, create it (thumbprint is
|
|
# no longer required — AWS validates GitHub against its own trust store):
|
|
aws iam create-open-id-connect-provider \
|
|
--url https://token.actions.githubusercontent.com \
|
|
--client-id-list sts.amazonaws.com
|
|
```
|
|
|
|
### 3. CDK bootstrap (once per account/region)
|
|
|
|
```bash
|
|
cd infra/cdk
|
|
npm ci
|
|
npx cdk bootstrap aws://<ACCOUNT_ID>/us-east-1
|
|
```
|
|
|
|
### 4. Domain, cert, and API origin (already wired for dev)
|
|
|
|
For dev these are set in `cdk.json` context (account `396287094661`):
|
|
|
|
| Context key | Value |
|
|
| --------------------------------------- | ------------------------------------------------------------ |
|
|
| `domainNames` | `dev.seahaven.com` |
|
|
| `certificateArn` | `…:certificate/2b78e74f-…` (ACM `*.seahaven.com`, us-east-1) |
|
|
| `hostedZoneId` / `hostedZoneName` | `Z07671212N75U4YLPWZR8` / `dev.seahaven.com` |
|
|
| `apiOriginDomain` / `apiOriginProtocol` | `api.dev.seahaven.com` / `https` |
|
|
|
|
The SPA calls `/api` same-origin; CloudFront proxies `/api/*` over **HTTPS** to
|
|
`api.dev.seahaven.com`. The stack creates the apex A/AAAA alias in the hosted
|
|
zone (which is in this account, delegated from the parent `seahaven.com` zone).
|
|
For staging/prod, override these context keys per environment.
|
|
|
|
### 5. First deploy (locally, with admin creds)
|
|
|
|
The deploy role doesn't exist until the first `cdk deploy`, so bootstrap it
|
|
locally. This provisions infra + the role:
|
|
|
|
```bash
|
|
cd infra/cdk
|
|
npx cdk deploy
|
|
```
|
|
|
|
Note the `DeployRoleArn` output. Then push the first content (or just push to
|
|
`dev` and let CI do everything from here on):
|
|
|
|
```bash
|
|
# from repo root, optional manual first content publish:
|
|
STACK_NAME=shoc-frontend-dev AWS_REGION=us-east-1 bash scripts/deploy-web.sh
|
|
```
|
|
|
|
### 6. Set the one GitHub secret
|
|
|
|
`cd-cdk.yaml` takes the role ARN as a **secret** (not a variable):
|
|
|
|
```bash
|
|
REPO=Sea-Haven-Industries/shoc-frontend-new
|
|
gh secret set AWS_DEPLOY_ROLE_ARN --repo "$REPO" \
|
|
--body "arn:aws:iam::<acct>:role/githubdeploy-shoc-frontend-new-dev"
|
|
```
|
|
|
|
(Or **Settings → Secrets and variables → Actions → Secrets**.)
|
|
|
|
### 7. From now on: push to `dev`
|
|
|
|
```bash
|
|
git push origin dev
|
|
```
|
|
|
|
`ci.yml` runs the quality gates and `deploy.yml` calls `cd-cdk.yaml`, which runs
|
|
`cdk deploy` then `scripts/deploy-web.sh`. Watch the **Actions** tab, then open
|
|
the `SiteUrl` output.
|
|
|
|
> First-run verification: this first push is what actually exercises the role's
|
|
> permissions and the OIDC trust through the reusable workflow (the local
|
|
> bootstrap used admin creds and tested none of that). Watch for
|
|
> credential/OIDC errors and a green post-deploy step.
|
|
|
|
---
|
|
|
|
## Adding staging / prod later
|
|
|
|
Separate accounts: deploy this stack there with `-c envName=staging`,
|
|
`-c deployBranch=<branch>`, and `-c apiOriginDomain=<that-env's-api-host>`; set
|
|
that repo's `AWS_DEPLOY_ROLE_ARN` secret; and add a job to `deploy.yml`. Because
|
|
the SPA calls `/api` same-origin, the API host is per-environment CloudFront
|
|
config (the `apiOriginDomain` context) — the build output is identical across
|
|
environments, so nothing env-specific gets baked into `vite build`.
|
|
|
|
## Notes
|
|
|
|
- **Teardown:** `npx cdk destroy`. The bucket uses `RemovalPolicy.DESTROY` +
|
|
`autoDeleteObjects` (dev artifacts are reproducible) — change this for prod.
|
|
- **CI and CD both fire on push to `dev`** in parallel; a red-CI commit still
|
|
deploys (matches the org's push-time-CD model). Gating deploy on CI is a
|
|
follow-up, not part of enabling CICD.
|
|
- **Local npm is pinned to v6**; the committed `package-lock.json` is
|
|
lockfileVersion 1. CI (Node 24 / npm 11) reads it fine via `npm ci`.
|