How do you implement multi-tenancy with Flux using namespaces and RBAC isolation?
Quick Answer
Flux multi-tenancy uses dedicated namespaces per tenant with separate GitRepository sources, Kustomizations scoped to specific namespaces, and Kubernetes RBAC service accounts that restrict each tenant's Flux reconciliation to only the resources within their assigned namespace boundary.
Detailed Answer
Think of Flux multi-tenancy like an apartment building where each tenant has their own unit with a separate lock and key. The building manager (platform team) controls the common infrastructure — hallways, elevators, and utilities — while each tenant (development team) can only access and modify their own apartment. Flux implements this pattern by assigning each tenant a dedicated namespace, a scoped service account with limited RBAC permissions, and a separate set of Flux resources (GitRepository, Kustomization) that can only reconcile resources within that tenant's namespace boundary. This prevents one team from accidentally or maliciously modifying another team's workloads.
The foundation of Flux multi-tenancy is the separation of platform-level and tenant-level Flux resources. The platform team maintains a top-level GitRepository and Kustomization that points to a repository containing the cluster infrastructure — things like namespace definitions, network policies, resource quotas, and the tenant onboarding configurations. Each tenant then gets their own GitRepository source pointing to their application repository and a Kustomization scoped to their namespace using the spec.targetNamespace and spec.serviceAccountName fields. The targetNamespace field forces all resources reconciled by that Kustomization to be created in the specified namespace, regardless of what namespace the tenant specifies in their manifests. The serviceAccountName field binds the reconciliation to a Kubernetes service account with RBAC roles that only allow creating and modifying resources within that namespace.
The RBAC configuration is critical for enforcing tenant isolation. The platform team creates a ServiceAccount, Role, and RoleBinding in each tenant namespace. The Role grants permissions like create, get, list, patch, update, and delete on specific resource types such as Deployments, Services, ConfigMaps, and Secrets, but only within that namespace. Importantly, the Role should not include cluster-scoped permissions like creating Namespaces, ClusterRoles, or CustomResourceDefinitions. When the Flux kustomize-controller reconciles resources using the tenant's service account, Kubernetes RBAC enforces these boundaries. If a tenant tries to deploy a ClusterRole or modify resources in another namespace, the reconciliation fails with a forbidden error, and Flux reports the failure in the Kustomization status.
In production environments at companies running services like payments-api, order-service, and inventory-service, the platform team typically structures the Git repository as a monorepo with a clusters directory for cluster-level configuration, a tenants directory containing the onboarding manifests for each team, and separate repositories per team for their application manifests. The flux-system namespace hosts the Flux controllers, while each tenant operates in their own namespace such as payments-team, orders-team, or inventory-team. Cross-namespace references are explicitly denied by setting spec.crossNamespaceReferences to false in the Flux configuration, preventing tenants from referencing GitRepository or other sources defined in other namespaces. Network policies complement the RBAC isolation by restricting network traffic between tenant namespaces.
A common production gotcha is forgetting to set spec.targetNamespace on the tenant Kustomization. Without it, tenants can specify any namespace in their manifests and bypass the intended isolation. Another pitfall is granting the tenant service account permissions on CustomResourceDefinitions or MutatingWebhookConfigurations, which could allow a tenant to escalate privileges or intercept traffic from other namespaces. Platform teams should also implement resource quotas and limit ranges per tenant namespace to prevent resource exhaustion attacks where one tenant consumes all cluster resources. Monitoring is equally important — the platform team should configure Flux notification alerts per tenant so that reconciliation failures are routed to the correct team's Slack channel rather than a shared channel where alerts get lost in noise.