Newer
Older
openstack-caracal-ipv4 / docs / tenant-onboarding-contract.md

Tenant onboarding contract -- operator/tenant boundary, intake, topology (DOCFIX-091)

Commissioned 2026-07-06 (operator A1 rulings). This is the authoritative statement of WHO does WHAT at tenant onboarding and why, for Omega Cloud v1 and carried to Roosevelt. Companions: scripts/tenant-onboard.sh (the ONLY sanctioned execution path), runbooks/tenant-onboarding-v2-DRAFT.md (procedure narrative; superseded points noted in its banner), runbooks/appendix-C-identity-rbac.md, runbooks/appendix-D-magnum-trust-model.md. Decisions: D-051 (Domain Manager persona), D-064 (policy mechanics), D-066 (account model), D-073 (list_trusts hardening, adopted 2026-07-06).

1. Identity model -- roles, explicit (D-066 Option-3 triad)

identity auth role grants (EXACT) purpose
<client>-domain-admin password manager on the domain -- EXACTLY ONE assignment, nothing else identity CRUD inside the domain: users, projects, in-domain role grants
<client>-cluster password member + load-balancer_member on the project cluster lifecycle (trust-capable); OWNS the nova keypair
<client>-svc password + UNRESTRICTED app credential member + load-balancer_member on the project non-trust automation: L3 build-out, templates, day-2 API work

The domain admin is the manager role, NEVER keystone admin. Keystone admin is architecturally not domain-confinable (a domain-scoped admin can escalate beyond the boundary -- upstream hard-coded limitation). The persona is the SCS Domain Manager (scs-0302) enforced by the D-051/D-064 policy override. Any admin grant anywhere in a tenant domain is an incident, not a convenience.

Why three identities, not one. Keystone refuses trust creation from app-cred tokens (regardless of --unrestricted), so Magnum cluster create MUST run as a password identity (-cluster). Nova keypairs are USER-scoped and Magnum validates the keypair in the cluster-creator/trustor context, so the keypair MUST be owned by -cluster (a -svc-owned key 400s at cluster create). Identity CRUD stays with the manager only. This split is PRESCRIPTIVE for tenants, not a suggestion.

2. Operator-only surface (and why)

surface why it is operator-only
domain lifecycle (create/disable/delete) it IS the tenancy boundary
manager account provisioning + password reset no self-service recovery exists; manager lockout is an operator support case (tenant-side bus factor -- tenants should name two custodians)
quotas (nova/cinder/neutron/octavia/magnum) the capacity envelope is a commercial + capacity-planning decision; the manager role cannot self-raise quotas by design
external/provider networks (provider-ext), FIP pool shared substrate; cross-tenant capacity
public Glance images, flavors shared substrate; Magnum-capable image/flavor requirements are operator-validated
keystone policy layer (policyd-override zip) it carries the isolation guarantee itself (D-051/D-064/D-073)
cloud control plane (juju, vault, ceph, ovn, octavia mgmt, magnum mgmt) not tenant-visible, ever

Everything else is tenant self-service via the triad: projects, users, in-domain role grants (manager); networks/subnets/routers (gateway to provider-ext), security groups, floating IPs, load balancers, Kubernetes clusters, instances, volumes, Barbican secrets/certificates, app credentials, keypairs (workload identities). Tenants never receive SSH or console access to operator infrastructure.

3. Tenant intake list (what the tenant provides BEFORE onboarding)

  1. Client short-name -- lowercase, DNS-safe; becomes the <client> prefix on the domain and every identity/resource name.
  2. Two named credential custodians + an out-of-band handoff channel (credentials are never sent in email/ticket bodies). Custodian #2 covers the manager-lockout bus factor.
  3. Quota ask: instances / vCPU / RAM, volumes + GB, networks/routers/FIPs, load balancers, clusters + node counts. (Maps to the stage-1 quota envelope.)
  4. Tenant CIDR(s) -- RFC1918, non-colliding with our allocations AND with any on-prem/VPN ranges they may later interconnect. Stage 4 fails closed on collision, but collecting it up front avoids a restart.
  5. Workload profile: Kubernetes yes/no (sizing against the capi templates), LB count expectations (amphora capacity), storage expectations.
  6. Authorized requesters -- who may request quota changes / password resets.
  7. (Optional) an SSH public key to import if they prefer their own key over the generated <client>-key.

4. Account creation -- steps, requirements, dangers

bash scripts/tenant-onboard.sh <client> [stage] is the only sanctioned path; ad-hoc onboarding is prohibited (deviations become script changes with a harness). Stages:

stage actor/identity does danger the script guards
0 operator (read-only) preflight: D-064 policy live (PO: active), roles exist, public kube image, clean slate for <client> proceeding onto a half-built or policy-less cloud
1 operator domain + manager (+ quota envelope) admin-instead-of-manager; quota must be set AFTER the project exists (or pre-create it)
2 manager (their creds) project + -cluster + -svc + grants; then an ANTI-ESCALATION self-check (an admin grant attempt must be DENIED -- if it lands, STOP: the policy layer is broken) privilege creep; policy-layer regression
3 -svc, then -cluster -svc mints the unrestricted app cred; -cluster creates the keypair THE KEYPAIR TRAP: key must be -cluster-owned or stage 6 400s
4 -svc app cred L3: net/subnet/router/ext-gw to provider-ext CIDR collision (fail-closed guard)
5 -svc app cred cluster template, image pinned BY UUID, no --keypair keypair on the template would bind the wrong owner; stage 6 supplies it
6 -cluster PASSWORD cluster create app-cred cluster create is impossible (keystone blocks trust from app creds) -- do not "simplify" to the app cred

Credential custody: per-identity 0600 files, never committed, handed off out-of-band to the named custodians; verify by length/format, never by printing.

5. Onboarding confirmation set ("access confirmed" means all of these)

  1. Horizon login as <client>-domain-admin, domain-scoped -- at onboarding.
  2. API/CLI auth for all three identities (the script asserts a token per identity inline at each stage).
  3. Horizon identity self-service probe -- manager creates and deletes a probe user via the GUI. VERIFY-LIVE: Horizon has its own policy layer and the GUI path for manager-role identity ops is historically the weak point; if it fails, the contract documents CLI as the identity path until fixed.
  4. Tenant access-proof (the "SSH access" confirmation): boot a canary instance on the tenant network, attach a FIP, SSH in with the tenant keypair, tear down. Proves end-to-end that the tenant can reach workloads inside their domain. PROPOSED as an optional stage-7 / first acceptance item -- not yet implemented.

6. Hardening against technician knowledge gaps

Existing (in the script today): script-as-procedure; stage-0 fail-closed preflight; stage-2 anti-escalation self-check; fail-closed CIDR guard; capture-then-test output validation; whitelist-write 0600 credentials; dynamic ID resolution (no pasted IDs). Systemic backstop: the D-051/D-064 policy layer bounds what tenant-side identities can do even if a technician errs; the residual risk is OPERATOR-side error (manual admin grant, wrong domain reuse, quota fat-finger).

PROPOSED (logged for operator prioritization; none implemented):

  • H1 tenant-assert.sh -- read-only post-onboard verifier: triad exists with the EXACT grants of section 1 (and nothing more), keypair owner is -cluster, app cred owner is -svc, manager has exactly one assignment, anti-escalation retest. Also serves as an offboard preflight and a periodic all-tenants drift sweep.
  • H2 stage-3 app-cred idempotency re-run guard (already in the logged backlog).
  • H3 canary access-proof stage (section 5 item 4).
  • H4 keystone-policy-drift.sh periodic run (script backlog item 6) -- guards the policy layer the whole model rests on.
  • H5 runbook rule: NOTHING outside the script; any needed deviation is a script change shipped with its harness, not a live improvisation.

Related: D-051, D-064, D-066, D-067, D-073, appendix-C, appendix-D, scripts/tenant-onboard.sh, runbooks/tenant-onboarding-v2-DRAFT.md.