Control Plane API and UI
The API and the UI ship through two entirely different pipelines, which trips people up when they go looking for "the cplane deploy" in one place.
Control plane API is just another app in the GitOps flow described in GitOps — the cplane Helm chart, synced last (wave 15, after Keycloak/Temporal/OpenBao are up) per the App Catalog & Sync Order doc. Its ingress sits on the region's own Route53 zone, behind the same ALB as the other Cogrion-owned services (cplane-api.sgp.prod.cogrion.com on prod-sgp). No separate walkthrough needed here — standing up the region via Terraform + ArgoCD brings the API up as part of that same sync.
Control plane UI (cplane-ui) is the exception: it's a static Vite SPA (control-plane/ui) deployed as a Cloudflare Worker, entirely outside the Terraform/ArgoCD flow above. control-plane/buildspec.ui.yml builds it and runs wrangler deploy --env {name}, triggered by a CodeBuild/CodePipeline pair per environment (cogrion-terraform/infra/cicd/pipelines/cloudflare-ui-pipeline.tf, generic over the cloudflare_ui_pipelines map in that stage's terraform.tfvars — one map entry per deploy target, each naming its source branch and CF_ENV).
The gotcha: a region's own domain, {region}.{env}.cogrion.com (e.g. sgp.prod.cogrion.com), is NS-delegated from Cloudflare to Route53 — that's where the ALB-backed API above actually lives. A Cloudflare Worker's custom_domain route can't bind inside a suffix that's been delegated away; trying anyway resolves to NXDOMAIN with an awsdns SOA, not a propagation delay. So cplane-ui's hostname puts the service name last instead of first, keeping it outside the delegated subtree and inside Cloudflare's own cogrion.com zone:
| Env | cplane-ui hostname | Defined in |
|---|---|---|
| dev-sgp | cplane.dev.cogrion.com | control-plane/ui/wrangler.jsonc → env.dev |
| prod-sgp | sgp.prod.cplane.cogrion.com | control-plane/ui/wrangler.jsonc → env.prod-sgp |
dev-sgp's hostname predates this convention (no region label at all — it happens to work because it was never nested under the delegated zone either, just by a different path) and hasn't been migrated to match prod's pattern yet.
Adding a new region+env means adding a matching env block to wrangler.jsonc, a matching entry to cloudflare_ui_pipelines, and keeping cplane.values.yaml's ALLOWED_APP_URLS/CORS_ALLOWED_ORIGINS/CONTROL_PLANE_UI_BASE_URL (in cogrion-gitops) pointed at whatever hostname wrangler.jsonc actually deploys to — these three have drifted out of sync before and aren't validated against each other by anything automated.
cplane-ui-prod-sgp pipeline never actually ran until recently — cogrion-terraform#120, merged: it watched a release branch that doesn't exist on control-plane (only main), passed cf_env = "prod" when wrangler.jsonc only defines env.prod-sgp, and pointed at a cogrion/prod/cloudflare-api-token secret that was never created. Fixed to main/prod-sgp/cogrion/cloudflare/api-token respectively.
Fixing that surfaced a second, previously-hidden bug: every buildspec.ui.yml (control-plane, oqullus) resolves CLOUDFLARE_API_TOKEN via CodeBuild's native env.secrets-manager block — hardcoded per-repo, not wired to the cloudflare_secret field in cloudflare_ui_pipelines (that Terraform variable is never actually referenced anywhere in cogrion-terraform; it's effectively dead config, informational only). control-plane/buildspec.ui.yml referenced cogrion/cloudflare-api-token (hyphen — doesn't exist; only cogrion/cloudflare/api-token, slash, exists in security-tooling), fixed directly in the buildspec. oqullus's buildspec already had the correct slash name, but still failed with AccessDeniedException on cogrion-codebuild — that pipeline's own identity policy (cogrion-terraform/infra/cicd/pipelines/iam.tf's CloudflareApiToken statement) referenced the wrong account (its own, 671905743213, instead of security-tooling 183184873475) and the wrong secret name, and the secret's own resource policy (infra/security/secrets-manager/terraform.tfvars's reader_role_arns) never listed cogrion-codebuild at all — both halves of the cross-account grant were missing. Fixed in cogrion-terraform#121 — identity-policy half applied locally already; resource-policy half needs main merge + the secrets-manager stack's own Plan → Approval → Apply pipeline before it's live.
Application-level setup (control-plane, manual today)
Application-level setup is not yet automated — this is the biggest gap in the end-to-end story right now. Status of each item lives on the master tracking issue, sparqd/project-management#277, and in the open items index; the following pages describe how each piece works today:
- Secret Management — how secrets are populated and rotated, including OpenBao's own bootstrap
- Authentication — Keycloak admin account, realm seeding, OIDC trust