Kubernetes Multitenancy: Namespaces, vClusters, and Hard Boundaries

Philip Rehberger Oct 19, 2026 7 min read

Choose between soft and hard multitenancy based on threat model. Covers vCluster and Capsule.

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

Share this article

Related Articles

Need help with your project?

Let's discuss how we can help you build reliable software.