Set Up Multi-Tenancy with Flux
Give each team its own namespace and repository, and enforce isolation with Kubernetes RBAC.
When several teams share a cluster, you want each to deploy its own applications without being able to touch anyone else’s. Flux builds this on Kubernetes primitives: each tenant gets a namespace, a service account, and a role binding, and Flux applies the tenant’s manifests while impersonating that service account. Isolation is enforced by Kubernetes RBAC, with no separate policy engine required. This guide sets up a tenant called dev-team.
The two roles
- Platform admins own the cluster and the Flux installation. They create tenants and decide what each may access.
- Tenants own their applications. They commit manifests to their own repository, and Flux applies them inside the tenant’s namespace only.
Create the tenant
The CLI generates the namespace, service account, and RBAC for you. Run it in a clone of the platform repository:
mkdir -p tenants/base/dev-team
flux create tenant dev-team \
--with-namespace=apps \
--export > tenants/base/dev-team/rbac.yaml
The generated YAML contains a Namespace named apps, a ServiceAccount named dev-team, and a RoleBinding that grants that service account the cluster-admin role within the apps namespace only. It can’t do anything outside it.
Connect the tenant’s repository
Create a source and Kustomization for the tenant’s own repository, in the tenant’s namespace:
flux create source git dev-team \
--namespace=apps \
--url=https://github.com/your-org/dev-team-apps \
--branch=main \
--export > tenants/base/dev-team/sync.yaml
flux create kustomization dev-team \
--namespace=apps \
--service-account=dev-team \
--source=GitRepository/dev-team \
--path="./" \
--prune=true --interval=5m \
--export >> tenants/base/dev-team/sync.yaml
The important line is serviceAccountName: dev-team on the Kustomization. It makes kustomize-controller apply the tenant’s manifests as that service account, so any attempt to create resources outside apps, or cluster-wide resources such as a ClusterRole, is rejected by the Kubernetes API. The same field exists on HelmRelease.
Add a kustomization.yaml in tenants/base/dev-team/ listing rbac.yaml and sync.yaml, and reference the tenant from the cluster’s folder, for example through a Flux Kustomization in clusters/production/tenants.yaml with path: ./tenants/production. Commit and push. Flux creates the namespace, the RBAC, and the tenant’s sync, and the team’s own repository takes over from there.
For a private tenant repository, create the credentials in the tenant’s namespace so only that tenant’s objects reference them:
flux create secret git dev-team-auth \
--namespace=apps \
--url=https://github.com/your-org/dev-team-apps \
--username=git --password=<token>
Then add --secret-ref=dev-team-auth to the source.
Lock down the controllers
Service accounts only help if tenants can’t bypass them. Configure the controllers to enforce the rules by patching the Flux installation in clusters/<env>/flux-system/kustomization.yaml:
patches:
- patch: |
- op: add
path: /spec/template/spec/containers/0/args/-
value: --no-cross-namespace-refs=true
- op: add
path: /spec/template/spec/containers/0/args/-
value: --default-service-account=default
target:
kind: Deployment
name: "(kustomize-controller|helm-controller)"
- patch: |
- op: add
path: /spec/template/spec/containers/0/args/-
value: --no-cross-namespace-refs=true
target:
kind: Deployment
name: "(notification-controller|image-reflector-controller|image-automation-controller)"
What these flags do:
--no-cross-namespace-refs=truestops a tenant’s Kustomization from referencing a source in another namespace, so tenants can’t use each other’s repositories or credentials.--default-service-account=defaultmakes controllers impersonate thedefaultservice account in the object’s namespace when none is set. A tenant that forgetsserviceAccountNamegets almost no permissions instead of Flux’s cluster-admin identity.
Commit the patches to the kustomization.yaml that bootstrap generated in that folder. Re-running bootstrap keeps customizations you add to that file. Check the current Flux multi-tenancy documentation for the exact patch for your version.
Restrict what tenants can do
Beyond the namespace boundary, consider extra controls:
- Namespace-scoped RBAC. Replace the generated
cluster-adminrole binding with a narrower role if tenants shouldn’t create, say, Roles or NetworkPolicies. - Admission policy. Use Kyverno or a ValidatingAdmissionPolicy to enforce image registries, resource limits, or forbid privileged Pods.
- Quotas. Add a
ResourceQuotaandLimitRangeto the tenant namespace, alongside the RBAC. - Network isolation. Add default-deny
NetworkPolicyobjects so tenant namespaces can’t talk to each other.
Verify the isolation
Add a manifest that creates something outside the tenant namespace, such as a ClusterRole, to the tenant’s repository and push. Then check:
flux get kustomizations -n apps
kubectl describe kustomization dev-team -n apps
The Kustomization fails with a forbidden error naming the service account, which is exactly what you want. Remove the bad manifest and Flux recovers on its own.
How this compares with project-based tenancy
Some tools model tenants as projects with their own policy objects. Flux has no such concept. A tenant is simply a namespace plus a service account that Flux impersonates, which means the Kubernetes API server is the single place permissions are enforced.
Popular Guides
-
Push vs Pull: How Flux Delivers to Kubernetes Why pull-based, Git-driven delivery changes how you deploy, secure, and recover clusters. -
Deploy Your First Application with a GitRepository and Kustomization Point Flux at manifests in Git using a Kustomization resource and watch it sync. -
Control Sync Behavior: Intervals, Prune, Drift Correction, and Rollback Decide when Flux applies changes, what it deletes, how to pause it, and how to undo a bad deploy. -
Automate Image Updates with Flux Image Automation Let Flux detect new container image tags and commit them back to Git. -
Configure Multi-Cluster with Flux Manage several clusters from one repository, with shared infrastructure and per-cluster differences. -
Flux CD vs Argo CD: Choosing a GitOps Tool Compare architecture, UI, Helm, secrets, tenancy, and image automation to pick the right tool.