Tenant Gateways were pinned to the bundled Cilium class. Give the platform a default in gateway.className, the set a tenant may choose from in gateway.tenantSelectableClasses, and the set whose provider terminates TLS upstream of the Gateway in gateway.edgeTerminatedClasses. A tenant picks its own with tenant.spec.gatewayClass, read only when it owns a Gateway; an inheriting tenant runs on its ancestor's. The selectable set is an allowlist rather than free choice because Tenant is a tenant-writable object while a GatewayClass is cluster-scoped: without it a tenant could attach its Gateway to a class an admin keeps for internal-only traffic. Naming anything outside the set fails that tenant's own gateway release and reaches no other tenant. Where TLS ends is a property of the class, so the gateway chart derives certMode from whichever class the tenant landed on instead of taking it as a separate input. The two therefore cannot be configured out of step. The publishing tenant cannot cross that line by itself. The cluster-wide ACME issuers point their HTTP-01 solver at its Gateway and are rendered from the platform default alone, so a mismatch would pin the solver to a listener that Gateway does not have. Those issuers now drop the sectionName pin when the default class is edge-terminated, letting the challenge attach by hostname instead. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <3811295@gmail.com>
Tenant
A tenant is the main unit of security on the platform. The closest analogy would be Linux kernel namespaces.
Tenants can be created recursively and are subject to the following rules:
Tenant naming
Tenant names must be alphanumeric:
- Lowercase letters (
a-z) and digits (0-9) only - Must start with a lowercase letter
- Dashes (
-) are not allowed, unlike with other services - Maximum length depends on the cluster configuration (Helm release prefix and root domain)
This restriction exists to keep consistent naming in tenants, nested tenants, and services deployed in them.
A tenant cannot be named foo-bar because parsing internal resource names like tenant-foo-bar would be ambiguous.
For example:
- The root tenant is named
root, but internally it's referenced astenant-root. - A nested tenant could be named
foo, which would result intenant-fooin service names and URLs.
Unique domains
Each tenant has its own domain.
By default, (unless otherwise specified), it inherits the domain of its parent with a prefix of its name.
For example, if the parent had the domain example.org, then tenant-foo would get the domain foo.example.org by default.
Kubernetes clusters created in this tenant namespace would get domains like: kubernetes-cluster.foo.example.org
Example:
tenant-root (example.org)
└── tenant-foo (foo.example.org)
└── kubernetes-cluster1 (kubernetes-cluster1.foo.example.org)
Nesting tenants and reusing parent services
Tenants can be nested. A tenant administrator can create nested tenants using the "Tenant" application from the catalogue.
Higher-level tenants can view and manage the applications of all their children tenants. If a tenant does not run their own cluster services, it can access ones of its parent.
For example, you create:
- Tenant
tenant-u1with a set of services likeetcd,ingress,monitoring. - Tenant
tenant-u2nested intenant-u1.
Let's see what will happen when you run Kubernetes and Postgres under tenant-u2 namespace.
Since tenant-u2 does not have its own cluster services like etcd, ingress, and monitoring,
the applications running in tenant-u2 will use the cluster services of the parent tenant.
This in turn means:
- The Kubernetes cluster data will be stored in
etcdfortenant-u1. - Access to the cluster will be through the common
ingressoftenant-u1. - Essentially, all metrics will be collected in the
monitoringfromtenant-u1, and only that tenant will have access to them.
Example:
tenant-u1
├── etcd
├── ingress
├── monitoring
└── tenant-u2
├── kubernetes-cluster1
└── postgres-db1
Parameters
Common parameters
| Name | Description | Type | Value |
|---|---|---|---|
host |
The hostname used to access tenant services (defaults to using the tenant name as a subdomain for its parent tenant host). | string |
"" |
etcd |
Deploy own Etcd cluster. | bool |
false |
monitoring |
Deploy own Monitoring Stack. | bool |
false |
ingress |
Deploy own Ingress Controller. | bool |
false |
gateway |
Deploy own Gateway API Gateway (backed by Cilium Gateway API controller). When unset (the default), the chart auto-enables the Gateway for tenants whose apex is derived from the parent (i.e. host is empty), and leaves it off for tenants with a custom non-derived apex. Set to true or false explicitly to override that auto-behaviour. Note: leave the key absent (do not write gateway: null) — the chart distinguishes "unset" via missing-key, not via null value, to satisfy the JSON schema generated from this comment. |
bool |
false |
gatewayClass |
GatewayClass for this tenant's own Gateway. Empty uses the platform default (gateway.className). Only the classes the operator lists in the platform's gateway.tenantSelectableClasses, plus that default, may be named here — anything else fails this tenant's own gateway release and reaches no other tenant. Read only when this tenant owns a Gateway; an inheriting tenant uses its ancestor's. Whether a class terminates TLS itself or at its provider's edge is declared once per class on the platform, not here. |
string |
"" |
seaweedfs |
Deploy own SeaweedFS. | bool |
false |
computeplane |
Deploy own ComputePlane — a single-tenant, Cozystack-managed cluster for untrusted-code applications. The tenant receives no admin kubeconfig for it. Automatic routing of catalog applications onto it (placement: ComputePlane) is a planned follow-up and is not available yet; until it lands, external catalogs target the cluster via its computeplane-cluster-admin-kubeconfig Secret. See design-proposals/compute-plane in cozystack/community. | bool |
false |
schedulingClass |
The name of a SchedulingClass CR to apply scheduling constraints for this tenant's workloads. | string |
"" |
resourceQuotas |
Define resource quotas for the tenant. | map[string]quantity |
{} |
Configuration
Resource Quotas
The resourceQuotas parameter allows you to limit resources available to the tenant. Supported keys include:
Compute resources (converted to requests.X and limits.X):
cpu- Total CPU cores (e.g.,"4"or"500m")memory- Total memory (e.g.,"4Gi"or"512Mi")ephemeral-storage- Ephemeral storage limit (e.g.,"10Gi")storage- Total persistent storage (e.g.,"100Gi")
Object count quotas (passed as-is):
pods- Maximum number of podsservices- Maximum number of servicesservices.loadbalancers- Maximum number of LoadBalancer servicesservices.nodeports- Maximum number of NodePort servicesconfigmaps- Maximum number of ConfigMapssecrets- Maximum number of Secretspersistentvolumeclaims- Maximum number of PVCs
Example:
resourceQuotas:
cpu: 4
memory: 4Gi
storage: 10Gi
services.loadbalancers: "3"
pods: "50"