Deploy the control-plane dashboard through CloudFront¶
Separate static assets from financial state¶
The optional CloudFront deployment publishes only the data-free shell from
internal/controlplane/ui/static/. It does not rebuild or restart inferplaned,
mayu, databases, policy stores or financial authorities. This avoids discarding
a memory-only CP's recent usage history merely to replace its UI. The embedded
console remains available on the CP itself; the CDN can serve a newer static
release while its APIs keep running on the existing CP image.
A private, encrypted, versioned S3 REST bucket is readable only by the existing
distribution through SigV4 OAC, with public access blocked. Static paths are
exact: /ui/, /ui/index.html, /ui/app.js, /ui/style.css. Do not route
/ui/* to S3: /ui/auth/config must stay on the authenticated-service origin's
public, secret-free SSO configuration endpoint. All /v1alpha1/*, inference and
admin behaviors retain their existing origins, Authorization forwarding and
query handling. A CloudFront Function redirects only / and /ui to /ui/;
all other requests pass through unchanged.
Static cache is disabled and responses use Cache-Control: no-store. Security
headers retain the CP's exact CSP, including configured Cognito login origins,
plus nosniff, no-referrer and frame denial. Only the shell is published; never
upload config files, environment files, credentials, policy documents or usage.
No new compute instances or distributions are needed. S3 storage/requests and
CloudFront Function requests still incur their normal small AWS charges.
Prepare and review¶
Support resources are declared in deploy/cloudfront/dashboard-resources.yaml,
with security rules in deploy/cloudfront/dashboard-security.guard.
prepare-cloudfront-dashboard.py prepares a candidate and rollback template;
it does not deploy them. It accepts the original get-template response or
a JSON template and requires the existing logical ID Distribution. Reading a
YAML TemplateBody requires PyYAML as an authoring dependency.
- Save the current template, parameter names, distribution config and ECS
deployment/task state to a private directory (umask 077). Capture the exact
CSP from the current
/ui/response. Do not log tokens or DSNs. - Validate the support template with cfn-lint and cfn-guard; create and inspect its change set and pre-deployment validation events before executing.
- Hash the three shell files. Upload the four exact object keys below an
immutable
releases/<content-hash>/prefix, with correct content types and no-store. Theui/object itself contains index.html: it is not public website hosting, and S3 does not supply an automatic index document. - Prepare the main-stack update from the original template and live distribution. Preserve the existing domain, ACM certificate and private VPC origins. Never normalize untouched scalar GetAtt expressions: that alone can force an ECS task-definition replacement. Use previous values for every old stack parameter. The helper refuses unknown origin IDs or existing edge functions rather than silently replacing them.
- Lint the candidate and rollback. Inspect the main change set: only Distribution may be modified, without replacement. If any ECS service, TaskDef, IAM, network or state resource appears, stop and fix the candidate.
- Check the distribution ETag for concurrent changes, execute the reviewed
change set, wait for stack UPDATE_COMPLETE and distribution Deployed, then
invalidate
/,/uiand/ui/*.
python3 scripts/prepare-cloudfront-dashboard.py \
--template "$PRIVATE_DIR/stack-template.before.json" \
--distribution-config "$PRIVATE_DIR/cloudfront.before.json" \
--support-outputs "$PRIVATE_DIR/support.outputs.json" \
--release-prefix "$RELEASE_PREFIX" \
--output "$PRIVATE_DIR/template.dashboard.json"
python3 -m unittest discover -s tests/deployment -v
cfn-lint --regions ap-northeast-2 -t deploy/cloudfront/dashboard-resources.yaml
Verify and roll back¶
Check deployed file hashes against the release manifest; root redirect; exact CSP and no-store; direct S3 anonymous access denied; protected APIs returning 401 without a bearer; configured reads returning 200; real browser navigation, mobile layout, disconnect and the Cognito authorization redirect. An IdP redirect check is not proof of a completed human SSO login or write admission. Do not test writes by altering a real financial policy. Confirm ECS task IDs and service revision are unchanged.
The helper writes .rollback.json and .rollback.parameters.json alongside
its candidate. They restore the adopted live baseline (including the domain,
TLS and VPC origins), not the historical template that omitted these manual
updates. Review and execute rollback as a CloudFormation change set with only
Distribution modified, then invalidate the same UI paths. Support assets remain
retained/private; do not delete the bucket or functions while attached.
For subsequent releases, upload a new hashed prefix and update only the existing
DashboardReleasePrefix parameter using the current template; retain all other
parameters and re-review the change set. The preparation helper deliberately
handles initial attachment only, not automatic replacement of existing edge
associations. If SSO origins change, review the support stack's CSP parameter too.
The operator UI workflow and its capability limits are described in the dashboard runbook.
Compatible chart deployment on an older control plane¶
The newer UI first requests the authenticated bounded /v1alpha1/usage/charts
rollup. If and only if that route returns 404, it uses the existing authenticated
/v1alpha1/usage/export with the same applied dates and JSON format. Rollup stays
in the signed-in user's page memory: no operating token or records are exported
to deployment tooling or embedded in public assets. The response is limited to
8 MiB/100,000 rows; select a shorter period if the limit is exceeded. Costs stay
integer microUSD and the existing OIDC queue/session fences remain in effect.
401/403 or store failures never select another route.
This compatibility path permits a static-only release while retaining a memory-only CP's process and history. It does not add the new server endpoint, alter policy-write authority, configure a policy store or attest identity bindings. File-authoritative deployments continue to show write controls as unavailable. Snapshot/export to an operator's filesystem needs explicit data access authorization; UI publication alone is not such an authorization.