Tenant provisioning
Overview
Section titled “Overview”A “tenant” on Kestrel is a Capsule Tenant backed by a Keycloak group. You do not hand-author a Tenant CR. Instead, you add a per-tenant values file under the environments hierarchy and the rcs-tenants ApplicationSet renders the Capsule Tenant (plus its quotas, network policies, limit ranges, and resource pool) from the shared tenant Helm chart.
Provisioning a new tenant means:
- Ensuring the tenant’s Keycloak group exists (authN — see the note below).
- Adding
environments/arbutus/kestrel/<cluster>/tenants/<rap-group>/values.yaml(often empty) and merging it (authZ + namespace limits, applied by the chart).
Pre-flight
Section titled “Pre-flight”Before starting, confirm:
- You have
cluster-adminaccess to the target Kestrel cluster. - The tenant name is the exact Cloud RAP POSIX group for the project. RAP/Cloud-RAP group names may contain uppercase characters — use the group as-is (real example:
CCInternal-RAID). - The requesting PI or lead has been added to the RCS intake tracker.
Step 1 — Ensure the Keycloak group exists
Section titled “Step 1 — Ensure the Keycloak group exists”The tenant’s owner group is the Keycloak group whose name matches the tenant basename. Membership is managed in Keycloak.
- Log into the Keycloak admin console for the Kestrel realm.
- Confirm a group exists matching the tenant name (e.g.
CCInternal-RAID), or create it. - Add the initial members (at minimum the requesting PI or lead).
Step 2 — Add the tenant values file
Section titled “Step 2 — Add the tenant values file”Create the per-tenant values file the rcs-tenants ApplicationSet expects:
environments/arbutus/kestrel/<cluster>/tenants/<rap-group>/values.yamlFor example, for the production cluster:
environments/arbutus/kestrel/kestrel-prod/tenants/CCInternal-RAID/values.yamlFor most tenants this file is empty (or near-empty) — the cluster-group defaults already supply the storage classes, ingress class, priority classes, resource pool, network policies, and limit ranges:
---The defaults inherited from the cluster-group values include:
- Resource pool — cluster-scoped,
resourcePool.tier: standard. The pool is shared across all of the tenant’s namespaces. - Network policies — default-deny, allowing ingress from the
traefiknamespace, scrape from themonitoringnamespace, intra-tenant traffic, and DNS. There is no general egress allow. - Limit range defaults — limit
cpu 1/memory 1Gi; requestcpu 100m/memory 128Mi. - Storage classes —
csi-cinder-sc-delete(default) andcsi-cinder-sc-retain. - Priority classes —
uber-user-significant,uber-user-preempt-medium,uber-user-preempt-high.
Add per-tenant overrides to this file only when the tenant needs something beyond the defaults (for example, a static NFS PersistentVolume for ReadWriteMany storage, as the mlp-explorer tenant does).
Commit and merge — the rcs-tenants ApplicationSet renders tenant-<rap-group> and ArgoCD syncs the Tenant within ~60 seconds.
Post-provisioning checks
Section titled “Post-provisioning checks”After the ArgoCD sync completes:
kubectl get tenant <tenant-name>— status should beActive. (<tenant-name>is the lowercased basename, e.g.ccinternal-raid.)kubectl auth can-i create namespace --as-group=oidc:<rap-group>— should returnyes. Theoidc:prefix is required and the basename case is preserved (e.g.--as-group=oidc:CCInternal-RAID).- Ask the tenant lead to log in via
kubectl oidc-loginand create a test namespace — this validates the full Keycloak → Capsule → RBAC chain. - Verify the namespaces the tenant owns:
kubectl get tenant <tenant-name> -o jsonpath='{.status.namespaces}'returns the array of namespace names;kubectl get tenant <tenant-name> -o jsonpath='{.status.size}'returns the namespace count. - Confirm the resource pool:
kubectl describe resourcepool <tenant-name>(the resource pool is cluster-scoped, so do not pass-n— it is ignored). For per-namespace usage, usekubectl describe resourcequota -n <ns>.
Deprovisioning
Section titled “Deprovisioning”To remove a tenant:
- Delete all namespaces owned by the tenant (Capsule cascades resource cleanup).
- Remove the tenant’s
tenants/<rap-group>/directory fromubernetes-applicationsand merge — the ApplicationSet prunes the rendered Tenant. - Disable (do not delete) the Keycloak group — keeps the audit trail intact. (See the identity-rework caution in Step 1.)