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).
| 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.
| 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.
<client> prefix on the domain and every identity/resource name.<client>-key.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.
<client>-domain-admin, domain-scoped -- at onboarding.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):
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.keystone-policy-drift.sh periodic run (script backlog item 6) -- guards the policy layer the whole model rests on.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.