quick-deploy: refuse to bake a wrong-tenant MSAL client into the cloud frontend¶
Motivation¶
scripts/dev/quick-deploy.sh is the fast path another operator uses to push
images to the shared Container App (all and frontend targets). A fresh
clone's .env / web/.env.local frequently carries the original
developer's tenant/client MSAL values (VITE_AZURE_CLIENT_ID / API_CLIENT_ID).
When a different operator runs quick-deploy.sh all (or frontend) without
exporting the deploy target's MSAL overrides, the SPA is baked to authenticate
against App Registration A while the target's api sidecar only accepts
bearer tokens minted for App Registration B. The deploy reports success,
but every /api/* call from the browser returns 401 — the exact
"another operator deployed the wrong MSAL values" incident class.
The script already guards two siblings of this failure (a localhost
VITE_API_BASE_URL and a leaked VITE_AUTH_DEV_BYPASS=true). The
wrong-tenant client id was the remaining unguarded one.
User-facing change¶
Before building the frontend image, quick-deploy.sh now compares the
VITE_AZURE_CLIENT_ID it is about to bake against the target Container
App's running api container API_CLIENT_ID env (the audience the api
validates bearer tokens against):
- Mismatch → the deploy aborts with a clear remediation message naming
both client ids. Escape hatch for a deliberate App Registration rotation:
ELB_ALLOW_MSAL_CLIENT_MISMATCH=1. - Target api has no
API_CLIENT_IDyet (first/bootstrap deploy) or theaz containerapp showquery fails (transient ARM error / read-only hiccup) → the check logs a note and continues, so a legitimate first rollout is never blocked.
The guard runs only when the frontend is actually built (! --no-build); the
--no-build GitHub Actions path preserves the already-baked env and is
unaffected. It mirrors the existing abort-with-escape-hatch style of the
auth-bypass guard rather than a default-OFF STRICT_* gate, because baking a
mismatched audience is always a bug — the safe default is to stop.
API / IaC diff summary¶
scripts/dev/quick-deploy.sh:- New helper
assert_msal_client_matches_target(defined afterresolve_image_digest). - Called in the
allbuild path and the singlefrontendbuild path, immediately after the existinglocalhost/VITE_AUTH_DEV_BYPASSguards and before the version-stamp resolution. - No backend, frontend, or Bicep changes. No new dependency.
Validation evidence¶
bash -n scripts/dev/quick-deploy.sh→ syntax OK.- JMESPath probe (
properties.template.containers[?name=='api'].env[] | [?name=='API_CLIENT_ID'].value | [0]) verified to return the api'sAPI_CLIENT_IDscalar when present andNone(→ skip) when absent, using a representative Container App template fixture. - Existing guards and the
--no-buildpath are untouched.