Kubernetes was designed with the assumption that one cluster serves one tenant. Real organizations have many tenants — teams, products, customers — and the question of how to isolate them in shared Kubernetes clusters comes up early and often. The answers range from "namespaces with conventions" to "virtual clusters with full isolation."
This post is the spectrum of multitenancy patterns, what each one isolates, and the cases that justify the increasing operational cost.
What "Multitenancy" Means Here
Three flavors:
Internal multitenancy. Multiple teams within one organization share a cluster. Mutual trust exists; isolation is for operational reasons (resource conflicts, accidental impact).
External multitenancy. Multiple customer organizations on one cluster. No mutual trust; isolation is a security boundary.
Workload multitenancy. One organization, but workloads with different reliability or compliance needs share a cluster.
Internal multitenancy is what most teams need. External multitenancy is what SaaS platforms running customer code need. Workload multitenancy is everywhere.
The mechanisms differ based on which kind you need.
Soft Isolation: Namespaces
The simplest pattern: each tenant gets a namespace. Namespaces provide scoping for names, RBAC boundaries, and resource quotas.
apiVersion: v1
kind: Namespace
metadata:
name: team-payments
labels:
team: payments
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: payments-quota
namespace: team-payments
spec:
hard:
requests.cpu: "100"
requests.memory: 200Gi
persistentvolumeclaims: "20"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: payments-developer
namespace: team-payments
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
Each tenant gets:
- Their own namespace
- A quota that caps total resource consumption
- RBAC restricting what their service accounts can do
What it does not give:
- Network isolation (pods in different namespaces can talk by default)
- Hard CPU/memory limits per pod (a runaway pod can use up the quota)
- Protection from cluster-scoped resources (CRDs, ClusterRoles)
- Isolation from the kernel (containers share the host kernel)
For internal multitenancy with mutual trust, namespaces are enough. For external multitenancy or strict isolation, you need more.
Medium Isolation: Network Policies, Pod Security
Add NetworkPolicy and Pod Security Standards on top of namespaces:
# Block all traffic into the namespace by default
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: team-payments
spec:
podSelector: {}
policyTypes: [Ingress]
# Pod Security Admission - enforce restricted policy
apiVersion: v1
kind: Namespace
metadata:
name: team-payments
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Together, these give:
- Network traffic between namespaces is denied by default
- Pods cannot run privileged or with broad capabilities
- Hostpaths and other dangerous patterns are blocked
This level is appropriate for most internal multitenancy. The cluster admin defines the policies; tenants work within them.
Strong Isolation: vClusters
A virtual cluster is a separate Kubernetes API server running inside a host cluster's namespace. Tenants interact with their virtual cluster as if it were their own; the host cluster handles the actual workload scheduling.
# Install a vCluster with the vcluster CLI
vcluster create payments-cluster --namespace team-payments
What this gives:
- Each tenant has their own API server, their own etcd, their own CRDs
- Tenants can install operators, CRDs, anything cluster-scoped
- Host cluster admin controls the workloads (they actually run on the host)
- Tenants cannot see each other's API objects
The cost:
- Higher resource overhead (one API server per tenant)
- More complex networking
- Some Kubernetes features behave differently
vClusters fit when tenants need cluster-scoped permissions but should not see each other. Common in platform engineering contexts where each team gets a "real" cluster.
The dominant tool is loft.sh's vCluster (open source plus commercial offerings).
Strong Isolation: Separate Clusters
The strongest isolation: each tenant gets their own actual Kubernetes cluster.
What this gives:
- Complete isolation (different etcd, different API servers, different nodes)
- Kernel isolation if nodes are different
- No shared infrastructure to compromise
The cost:
- Many clusters to operate
- Resource overhead of control planes
- Coordination between clusters is non-trivial
This is appropriate for:
- External multitenancy where security is paramount (banking, healthcare)
- Tenants with vastly different operational profiles
- Regulatory requirements for complete separation
Multi-cluster management tools (Rancher, Anthos, OpenShift) help operate many clusters. Crossplane can provision new clusters as part of tenant onboarding.
The Hierarchy in Practice
Most organizations end up with multiple levels:
- Production clusters with strong isolation per tenant
- Staging cluster with namespace-level isolation
- Dev cluster with minimal isolation
Each tier matches the risk profile of the workloads in it.
Resource Isolation Beyond Quotas
ResourceQuota caps total namespace resources but does not prevent a single pod from misbehaving. For real workload isolation:
LimitRange sets default and max per-pod resources:
apiVersion: v1
kind: LimitRange
metadata:
name: defaults
namespace: team-payments
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: "4"
memory: 8Gi
PriorityClass lets you prioritize critical workloads. Lower-priority pods get evicted first under pressure.
Node taints prevent some workloads from landing on certain nodes. A "dedicated" tenant might have nodes only for them.
Capacity Sharing
Even with namespaces and quotas, multiple tenants share the underlying nodes. If tenant A bursts and exhausts node capacity, tenant B's pods cannot schedule even though tenant B has quota available.
The mitigation: ensure node capacity is enough for everyone's combined max usage. Or use Pod Topology Spread Constraints to balance load across nodes.
For genuinely strict isolation: dedicated node pools per tenant. Tenant A's pods only run on tenant A's nodes. Loses the cost benefit of sharing but provides predictable performance.
Cost Allocation
When multiple tenants share a cluster, who pays for what?
Tools like OpenCost (Kubernetes-native) allocate cluster costs to namespaces, deployments, or labels. Each tenant's monthly cost becomes visible.
# OpenCost CLI
opencost cost-by-namespace --window=30d
For internal multitenancy, this is reporting. For external multitenancy with charge-back to customers, it becomes billing.
Pitfalls
- Trusting namespaces for security. Namespaces are organization, not isolation. A workload in one namespace can attack another in the same cluster.
- No NetworkPolicy. Pods can talk freely; a compromised pod in one namespace can scan and attack others.
- No PodSecurityAdmission. Pods can run as root, mount host paths, escape. One bad container compromises the host.
- Quotas without LimitRanges. A single pod can consume all of the tenant's quota.
- Treating vCluster as security boundary. vCluster is operational separation, not hard security. Workloads still run on shared nodes.
Decision Heuristics
Use namespaces only when:
- Internal multitenancy with mutual trust
- No real security concerns between tenants
- Small number of tenants
Add NetworkPolicy + PodSecurity when:
- Multiple teams sharing a cluster
- Compliance requires defense-in-depth
- You want to limit blast radius of compromise
Use vCluster when:
- Tenants need cluster-scoped permissions (operators, CRDs)
- Strong operational separation without separate clusters
- Platform engineering serving many internal teams
Use separate clusters when:
- External customers running their own code
- Regulatory or compliance requirements
- Workloads with dramatically different operational profiles
A Practical Default
For most teams: namespaces + NetworkPolicy + PodSecurity + ResourceQuota + LimitRange. This covers internal multitenancy adequately.
For platform engineering: add vCluster for teams that need more.
For SaaS running customer code: separate clusters per customer, or at least dedicated node pools.
The right amount of isolation matches the trust model. Over-engineering isolation in low-trust contexts is wasteful; under-engineering it in high-trust contexts is a security incident.
Designing Kubernetes multitenancy for a platform that has outgrown "one cluster, all the things"? We help teams pick isolation models that match team structure and security requirements. scopeforged.com