Skip to main content
RunBook Academy

KubernetesCVII · Namespaces and Multi-TenancyMulti-tenancy

vCluster and Kyverno — hard multi-tenancy and per-tenant policy

Advanced⏱ ~17 minkubectlvclusterkyverno

What you'll learn

  • Use vCluster for hard multi-tenancy within a cluster
  • Use Kyverno for per-tenant policy enforcement
  • Reason about the integration with namespaces
  • Apply the operational discipline of choosing the right multi-tenancy tool

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

vCluster and Kyverno extend the multi-tenancy options. This lesson walks vCluster for hard multi-tenancy within a cluster, Kyverno for per-tenant policy, the integration, and the operational discipline.

vCluster for hard multi-tenancy

flowchart LR
    A[Host cluster] --> B["vCluster: tenant-a"]
    A --> C["vCluster: tenant-b"]
    B --> B1["API server: tenant-a"]
    B --> B2["etcd: tenant-a"]
    B --> B3["Scheduler: tenant-a"]
    C --> C1["API server: tenant-b"]
    C --> C2["etcd: tenant-b"]
    C --> C3["Scheduler: tenant-b"]
    B -->|schedules on| F[Host nodes]
    C -->|schedules on| F

vCluster runs a virtual Kubernetes control plane inside a host cluster. Each tenant gets:

  • Its own API server (running as a Pod in the host).
  • Its own etcd (running as a Pod in the host).
  • Its own scheduler and controller manager.

Pods from the virtual cluster schedule on the host cluster’s nodes. The tenants are isolated at the control-plane level: they cannot see each other’s objects.

A vCluster example

# Create a vCluster
vcluster create tenant-a --namespace tenant-a-vcluster

# Use the vCluster's kubeconfig
vcluster connect tenant-a --namespace tenant-a-vcluster

# Inside the vCluster, create a namespace
kubectl create namespace my-app

# Outside, in the host cluster, the vCluster Pods are visible
kubectl get namespaces -n tenant-a-vcluster

The vCluster is managed by a Helm chart; the vcluster CLI creates, connects, and deletes vClusters.

Kyverno for per-tenant policy

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: check-for-labels
      match:
        any:
          - resources:
              kinds:
                - Pod
              namespaceSelector:
                matchLabels:
                  tenant: tenant-a
      validate:
        message: "The labels 'app' and 'owner' are required."
        pattern:
          metadata:
            labels:
              app: "?*"
              owner: "?*"

Kyverno policies:

  • Validate. Block objects that don’t match the pattern.
  • Mutate. Modify objects to match the pattern.
  • Generate. Create additional objects based on the input.

Policies can be scoped to specific namespaces via namespaceSelector. A Kyverno policy can apply different rules to different tenants.

The integration

flowchart LR
    A[Tenant creates Pod] --> B[API server]
    B --> C["Admission webhook: Kyverno"]
    C --> D{Validates?}
    D -->|No| E[Rejected]
    D -->|Yes| F[Object stored]
    F --> G["vCluster: schedules on host"]
    G --> H["CNI: NetworkPolicy check"]
    H -->|Allowed| I[Pod runs]

The integration:

  1. The tenant creates a Pod in the vCluster’s namespace.
  2. The vCluster’s API server receives the request.
  3. Kyverno (via admission webhook) validates the Pod.
  4. The Pod is stored in the vCluster’s etcd.
  5. The vCluster’s scheduler places the Pod on the host cluster’s nodes.
  6. The host cluster’s CNI enforces NetworkPolicy.

Each layer enforces its policy. The combination provides defense in depth.

The operational trade-offs

flowchart LR
    A[vCluster] --> B[+ Hard isolation at control plane]
    A --> C[+ Cheaper than separate clusters]
    A --> D[- Adds operational complexity]
    A --> E[- Tenants share host nodes]
    F[Kyverno] --> G[+ Per-tenant policy]
    G --> H[+ YAML-based syntax]
    G --> I[- Requires webhook infrastructure]

The trade-offs:

vCluster:

  • Pros: Hard isolation at control plane; cheaper than separate clusters.
  • Cons: Operational complexity; tenants share host nodes (so node failure affects all).

Kyverno:

  • Pros: Per-tenant policy; YAML-based syntax; validation, mutation, generation.
  • Cons: Requires webhook infrastructure.

Quiz

Knowledge check · 4 questions

  1. Q1. What isolation does vCluster provide that namespaces do not?

  2. Q2. vCluster protects the host cluster from a container escape in a tenant workload.

  3. Q3. A Kyverno policy that should require an owner label is recording violations without blocking anything; make it enforce.

    The ClusterPolicy `require-owner-label` has been in the cluster for a month. `kubectl get policyreport -n tenant-b` shows 47 entries with result `fail` for its rule, yet all 47 Pods are Running. The policy sets `validationFailureAction: Audit`, `background: true`, and matches Pods with a `namespaceSelector` on `tenant: tenant-b`.

  4. Q4. Which Kyverno rule type gives every new tenant namespace a default-deny NetworkPolicy without the tenant applying one, and what is the operational risk of relying on it?

Passing score: 75%. Answers are checked in this browser.

The operational discipline

vCluster and Kyverno in production rest on five non-negotiable elements:

  • vCluster for untrusted tenants. Untrusted tenants need control-plane isolation.
  • Kyverno for policy enforcement. Per-tenant rules that the soft stack cannot express.
  • NetworkPolicy still required. vCluster does not replace NetworkPolicy.
  • Test isolation. Quarterly: verify tenants cannot access each other’s resources.
  • Document the topology. vCluster and Kyverno are part of the architecture diagram.

vCluster and Kyverno extend multi-tenancy. The discipline is to choose the right tool for the use case and to test the isolation.