Skip to content
Docs

Multi-Tenancy

A single cluster-mode install can serve many tenants at once. Each tenant is an Organization — a real row in hyve-api’s own datastore (Postgres or SQLite, see internal/orgdb), not a Kubernetes object — paired with its own Kubernetes namespace and RBAC scaffolding. No separate Helm release per tenant, no separate controller+API pod pair to operate and upgrade for each one.

Creating, renaming, and deleting organizations

Terminal window
hyve organization create acme

Superadmin-only, and deliberately narrow: it turns a name into a real tenant — its own namespace, its own hyve-access-admin/hyve-access-readonly ServiceAccount+RoleBinding scaffolding (the same RBAC a one-install-per-tenant deployment gets from the Helm chart at install time, created programmatically here instead), and its own datastore record — and nothing more. Every organization also gets one default environment automatically — a named scope within it (staging, production, …) that clusters are created in; see hyve environment.

Creating it grants no one access. Add its first member from the web console’s Users page while viewing it (or POST /api/accounts) — a new user gets a password and is emailed about their account; an existing user from another organization is just added, keeping their own login. From inside the hyve-api pod there’s also:

Terminal window
hyve cluster-config api create-user alice --role admin --namespace acme

An organization’s name can be changed later — its Kubernetes namespace, the thing every binding/RBAC/reconciling-cluster lookup actually keys on, never can, so this is purely a relabel:

Terminal window
hyve organization migrate --help # renaming happens via the same PATCH /organizations/{name} as migration — see below

Names must stay unique, and the same two names creation reserves stay reserved for renaming too: hyve-system (the control plane’s own namespace) and any casing/spacing of control plane.

Deleting one is equally direct:

Terminal window
hyve organization delete acme

This marks the row for deletion and issues a standard Kubernetes namespace delete — Kubernetes’ own native cascade tears down everything inside it and then the namespace itself, no hyve-specific finalizer or out-of-band controller confirmation gates that removal. Deletion behaves the same way here as everywhere else in the application.

Reconciling clusters: where a tenant’s resources actually live

By default, an organization’s ClusterDefinition/Template/Workflow/Resource objects (and its own HyveConfig) live in its namespace on the control plane’s own home cluster, right alongside every other tenant’s. hyve-controller reconciles every such organization alongside the control plane — the Helm chart turns this on for api.multiTenant.enabled with api.db.driver: postgres (the controller reads the organization list from the same database, and picks up new organizations by restarting itself within about 30 seconds). A reconciling cluster lets one organization’s resources live on a different, dedicated physical Kubernetes cluster instead — useful for isolating a noisy or sensitive tenant, or for a hosted offering that never wants tenant workloads anywhere near its own control-plane infrastructure.

An organization can keep several clusters stored and switch between them by name — no re-entering a kubeconfig each time. This is self-service, reachable by the organization’s own admin:

Terminal window
hyve reconciling-cluster add k3s --kubeconfig-file ~/k3s.yaml
hyve reconciling-cluster add civo --kubeconfig-file ~/civo.yaml
hyve reconciling-cluster use civo # copies every resource over, then switches
hyve reconciling-cluster use --home # back to the control plane's own home cluster

The web console’s Reconciling cluster page does the same, and shows each cluster’s server endpoint, Kubernetes version, and live reachability. Cluster names are unique per organization, so two organizations can each have a prod. Switching locks the organization (423 Locked) while the copy runs; a failed copy leaves it where it was.

A superadmin can also register clusters in an install-wide pool and assign one to an organization directly:

Terminal window
hyve reconciling-cluster pool add cell-a --kubeconfig-file ./cell-a.yaml
hyve organization migrate acme --reconciling-cluster cell-a

--require-reconciling-cluster

A hosted/managed install can refuse to let any organization other than the control plane’s own ever land on (or migrate back to) the shared home cluster at all:

Terminal window
hyve cluster-config api run --require-reconciling-cluster ...

Every organization must then be given an explicit reconciling cluster at creation, and can never migrate back to "" (home) later — a hard operator guarantee that tenant workloads never touch the infrastructure the control plane itself runs on.

One account, many organizations

A user is one account — a username, an email, and a password, all unique across the install — with a membership in each organization they belong to, each with its own role. Adding someone to a second organization adds a membership, not a second account or password.

Logging in names no organization:

Terminal window
hyve context login --api-url https://hyve-api.example.com

Which organization a command acts in is picked per request, and checked against your memberships every time:

Terminal window
hyve organization list # the organizations you can access, and your role in each
hyve organization use acme # remembered on the active context
hyve cluster list --org widget # or for a single command

In the web console, the same choice is the Viewing picker, which lists only your organizations (and hides itself when there’s just one). With nothing picked, hyve-api uses your only organization — the first one, if you belong to several — or, for a superadmin, the control plane. Organization names are resolved server-side, so a renamed organization keeps working under its new name, and under its namespace.

The control plane’s own organization (hyve-system) appears once, as Control plane.

The superadmin role

Above the namespace-scoped admin/read-only roles sits one intentionally cluster-scoped tier: superadmin. It exists for a small, fixed set of things:

  • Create, rename, or delete a tenant organization.
  • Manage the install-wide reconciling-cluster pool and assign pool clusters to organizations (an organization’s own clusters, above, need no superadmin at all).
  • Act in any organization, member or not (picked like any other — hyve organization use, --org, or the console’s Viewing picker), always as superadmin.

It’s never the default role, and no tenant admin can grant it to themselves. A user’s email and password are shared by all their organizations, so an organization’s admin can change them only for someone who belongs to that organization alone — see Access Control for the full role model.

The host cluster

hyve-controller/hyve-api run on some cluster — the host. It’s represented as a ClusterDefinition marked spec.access.method: primary, in one of two ways:

  • No spec.driver (the zero-config default). The cluster already exists by definition, so hyve never creates, deletes, or scales it — it only reconciles its spec.resources. hyve cluster auth <name> gets a kubeconfig minted by hyve-api itself: a short-lived token for a dedicated cluster-admin-bound ServiceAccount (hyve-host-admin), superadmin only, since the host carries every tenant’s control plane.

    apiVersion: hyve.io/v1alpha1
    kind: ClusterDefinition
    metadata: {name: host, namespace: hyve-system}
    spec: {access: {method: primary}}
  • With a real spec.driver. Hyve provisions and authenticates to the host through that driver exactly like any other cluster — the pattern for a host cluster hyve itself created (for example from a template, locally or in a pipeline). primary is then only a marker hyve migrate cluster uses to find the current host.

See Cluster Patterns for creating a host cluster locally or from a pipeline.

The host as other organizations’ management cluster

A module with a management cluster (such as a Cluster API module — see Modules) can name the host. Clusters in the control plane can always do that; clusters in other organizations on the home cluster can only once a superadmin allows it — Organizations may use the host cluster in the control plane’s Settings (HyveConfig.spec.organizationsMayUseHostCluster). Off by default: the module then gets the host’s cluster-admin kubeconfig, and organizations choose their own modules, so only allow it when every organization is trusted with that.

Moving tenants and hosts: hyve migrate

hyve migrate cluster understands this model directly via --namespace, working alongside (not instead of) hyve organization migrate above:

  • A tenant namespace scopes the migration to just that tenant — split one tenant onto its own dedicated cluster while the source keeps running for everyone else.
  • hyve-system (the default) migrates everything — every organization, plus the control plane’s own objects.