Introduction
If you run a shared Kubernetes cluster, multiple teams, multiple environments, one control plane, you've probably already asked the question: what actually stops one team's workloads from reaching another's? For most clusters today, the honest answer is namespaces plus RBAC, and RBAC controls who can create or modify resources, not what traffic can flow between them. Unless someone has also written and maintained NetworkPolicy, there's no network-layer enforcement at all: two pods in different namespaces can reach each other over the network by default, regardless of what RBAC says about who owns them.
Flow CNI gives platform teams a different answer: isolation that's enforced at the network layer itself, not by a policy engine matching labels.
The problem with policy-based isolation
Kubernetes NetworkPolicy works by matching pod labels and namespaces against rules, and using that logic to allow or drop traffic. It's flexible, and for a lot of use cases it's sufficient. But it has a structural weakness: it relies on a software-enforced architecture and operates cluster-wide, which means a single misconfigured rule, an unlabeled pod, or a policy that silently fails to apply can open a path between namespaces that were supposed to be isolated. Misconfigurations in label-matching can be difficult to detect.
To be precise, because this point matters in any real evaluation: this isn't a claim that other CNIs “don’t do namespace isolation.” Kubernetes NetworkPolicy, on any CNI that implements it, does namespace-level isolation. The distinction that matters is where the isolation boundary lives and how it fails. A label-matching rule that's misapplied fails open. A network-layer boundary doesn't depend on the label being correct in the first place.
This distinction has a name in the Kubernetes community: soft multi-tenancy assumes tenants are trusted and isolates mainly to prevent accidents. The usual toolkit is namespaces, RBAC, and NetworkPolicy. Hard multi-tenancy assumes tenants can be actively adversarial and requires isolation that holds even when someone's trying to break it. NetworkPolicy-based isolation, including on CNIs that implement it well, sits on the soft side of that line for networking. Specifically, the boundary is a rule, and rules can be wrong. VPC-based isolation moves that specific boundary to the hard side: it's enforced in the network itself, not evaluated against a rule per packet.
The table below summarizes how NetworkPolicy-based and VPC-based isolation differ in enforcement, failure behavior, and multi-tenancy.
What Flow CNI does differently
With Flow CNI, Kubernetes namespaces map directly to Nutanix VPCs. Isolation between namespaces isn't a policy decision layered on top of a flat network, it's a property of the network itself, enforced in the data plane.
Practically:
- Multiple teams or environments can share one physical cluster with real network boundaries between them. Dev, staging, and prod each land in their own VPC and cannot reach each other by default, not because a policy says so, but because there's no route between them.
- The boundary survives misconfiguration in a way label-matching can't. Because isolation is a network property rather than a rule that has to match correctly every time, it mitigates this specific misconfiguration risk where a missing or wrong label quietly permits traffic that should have been blocked.
Flow CNI supports both patterns. A tenant can also run a single VPC across an entire cluster, using namespaces plus RBAC and NetworkPolicy for softer, cooperative isolation between teams; that's still a fully supported configuration. Alternatively, the VPC-per-tenant model in the table above is what you reach for when isolation needs to be designed to enforce isolation at the network layer rather than maintained by convention, which is the focus of the rest of this post.
Creating a VPC from Prism Central
The Prism Central (PC) management console is the primary way to set this up. You don't need to touch YAML to get a VPC running; the CRD is there for teams who want it, but PC is the path most platform teams will use day to day.
When you create a VPC in PC, you choose a Scope: Virtual Machines, Containers, or both. That scope is set per VPC, not per cluster, which means a single Kubernetes cluster isn't limited to one federation boundary. You can have several VPCs on the same cluster, and each one independently decides whether it's container-only or federated across VMs and containers. For example, vpc-team-alpha and vpc-team-beta both federated across VMs and containers, plus vpc-team-gamma scoped to containers only, all coexisting side by side.
For a Containers-scoped VPC, PC walks you through:
- Kubernetes Cluster, which onboarded cluster this VPC applies to.
- Namespace Scope, all namespaces, or manually selected ones via a label selector.
- Pod CIDR, the VPC's own address range.
One more thing worth knowing: a VPC isn't limited to a single namespace. The namespace scope is a selector, so any number of namespaces carrying the matching label belong to the same VPC and share its address space. This is useful when a team's several namespaces, or a related set of services, should sit inside one isolation boundary rather than being split into a VPC apiece.
Under the hood: the VPC CRD
If your team manages infrastructure through GitOps rather than the PC UI, the same construct is available as a native Kubernetes CRD. A Vpc resource can have multiple namespaces attached to it. These namespaces are identified by a label selector rather than a one-off annotation on each namespace:
A few things worth calling out:
- Namespace selection is label-based, not a hardcoded list. Any namespace carrying the matching label is automatically part of that VPC, and since it's a selector, one VPC can just as easily cover several namespaces as it can cover one. Add the label to a new namespace and it inherits the VPC's isolation boundary with no extra step.
- The pod network is owned by the VPC, not the cluster. podNetwork.cidr and hostSlice define the VPC's own address space and how it's sliced per node. Every VPC on the cluster gets its own non-overlapping range, so there's no shared flat pod network underneath with a policy layer bolted on top.
- Shared access is on by default. allowAccessFromSharedVpc controls whether services sitting in the shared VPC, ingress controllers, monitoring, logging, service mesh controllers, can reach into pods in a tenant VPC. It defaults to true, so shared infrastructure can reach tenant pods without extra configuration (useful for things like an ingress controller routing to your workloads). Set it to false on a VPC that needs to stay unreachable from shared-VPC services. Core infrastructure, the kube-apiserver, is designed to remain reachable from every tenant VPC regardless of this flag.
- The status conditions tell you what's actually live. A quick kubectl describe vpc <name> shows conditions like ClusterUserDefinedNetworkAvailable and SharedServicesLsAvailable, useful for confirming the VPC's network and shared-services attachment are actually up, not just declared.
The default shared VPC
When Flow CNI is deployed onto a cluster, a shared VPC is provisioned automatically, there's no manual step to create it. It exists so a platform admin has somewhere to put cluster-wide shared services (e.g., DNS, monitoring agents) without placing them inside any single tenant's isolated VPC. User defined or tenant VPCs can reach it by default, since allowAccessFromSharedVpc defaults to true. The shared VPC is meant to be reachable out of the box, since that's usually exactly what you want for something like DNS. Isolation between tenant VPCs is unaffected either way; a tenant only loses shared-services access if that flag is explicitly set to false.
Where this shows up in practice
Two scenarios come up often enough that they're worth calling out directly.
Several business units or application teams on one cluster. A common pattern in large organizations is that platform teams get asked to support many BUs or app teams without provisioning a cluster per team. That's expensive to run and to keep patched. With namespace-selector-based VPCs, each BU gets a Vpc resource keyed to a label (team: alpha, team: beta, and so on). Every namespace an app team creates just needs the label, and it inherits that team's isolation boundary automatically. The platform team runs one cluster; each BU behaves, from a network perspective, as if it has its own.
Bare metal, for teams who chose it for performance. Some customers run Kubernetes directly on bare metal, no hypervisor, specifically to avoid virtualization overhead for latency or throughput-sensitive workloads. The assumption is often that going bare metal means giving up the network-level multi-tenancy a virtualized platform provides. It doesn't. With Flow CNI: a Containers-scoped VPC works the same way whether the underlying nodes are VMs or bare metal hosts. A bare-metal cluster shared across several teams gets the same per-team Vpc resources, the same non-overlapping pod networks, and the same default-closed boundary between them; the isolation model isn't tied to having a hypervisor underneath it.
This chart is a comprehensive snapshot of the memory usage breakdown across the cluster and is aggregated across the workloads on the hosts on the cluster to provide insights into some critical data points, such as the cumulative VM and host overheads in the cluster as well as the memory reserved for HA.
In addition to the above, Cluster level charts and metrics are now also available for Cumulative VM and host perspective memory allocation overview, CPU overcommit ratios as well as Memory runway available to power on new VMs.
What this looks like day to day
For a platform team running a shared cluster today, the practical shift is:
- Each team, BU, or environment gets its own VPC, matched to its namespaces by label, instead of relying on a shared flat pod network plus policy enforcement.
- Cross-VPC communication doesn't exist at the network layer by default. And within the VPC, cross-namespace communication is allowed unless you add a NetworkPolicy to restrict it.
- You can set it up either way, a few fields in the Prism Central VPC creation flow, or a Vpc CRD in Git if your team already manages infrastructure that way.
None of this requires re-architecting your applications or your cluster topology. Label the namespaces you already have, and they inherit the VPC's isolation boundary.
What VPC isolation doesn't cover
Worth being precise about scope, in the same spirit as the hard/soft distinction above: VPC isolation gets you hard multi-tenancy specifically on the network axis. On its own, it doesn't address:
- Compute/node sharing. Pods from two different VPCs can still land on the same physical or virtual node unless you separately configure node affinity, taints, or dedicated node pools.
- Kernel/runtime isolation. Containers on a shared node still share a kernel by default; a container breakout is a host-level concern, not something a network boundary prevents.
- Control plane. Every VPC on a cluster still shares one API server, one scheduler, one etcd. RBAC and API-level quotas are a separate control from network isolation.
If a tenant's threat model calls for isolation on those axes too, pair VPC isolation with the usual node-level and RBAC controls. For most shared-cluster scenarios, internal BUs, app teams, environments, network-axis hard isolation plus standard node hygiene is what a practical hard-tenancy posture looks like in production.
Pairing with Flow Network Security for defense in depth
VPC isolation and Flow Network Security (FNS) solve adjacent but different problems, and the two ship in the same release for a reason. VPC isolation is the hard boundary between tenants, it decides whether workloads in one VPC can reach another VPC at all, and by default they can't, since there's no east-west route across VPCs. What happens inside that boundary is a separate question: Flow CNI supports standard NetworkPolicy for it, so anything you've already written keeps working unchanged. Our recommendation, though, is the FNS solution, same job, plus staged monitor-then-enforce rollout and, via Workload Federation, one policy that holds across VMs and containers instead of two to maintain separately. Used together with VPC isolation, FNS governs the traffic that's allowed to exist inside the boundary.
Try it
The most convincing way to see this is to try to break it yourself:
Assuming team-alpha and team-beta are each attached to their own Vpc resource, the ping fails, not because a policy blocked it, since none exists, but because there's no route between the two VPCs' pod networks. Add a NetworkPolicy and the result doesn't change; remove one and it still doesn't change. That's the difference this post is about.
- Read the launch blog for the full picture of what shipped in this release, including FNS policy parity for containers.
- Try the VPC isolation demo in your own NKP cluster to see the boundary enforced in practice.
Flow CNI is included with Nutanix Cloud Infrastructure (NCI) Pro software licensing.
Minimum versions
©2026 Nutanix, Inc. All rights reserved. Nutanix, the Nutanix logo and all Nutanix product and service names mentioned are registered trademarks or trademarks of Nutanix, Inc. in the United States and other countries. Kubernetes is a registered trademark of The Linux Foundation in the United States and other countries. All other brand names mentioned are for identification purposes only and may be the trademarks of their respective holder(s). Code samples and snippets that appear in this content are unofficial, are unsupported, and are provided AS IS. Nutanix makes no representations or warranties of any kind, express or implied, as to the operation or content of the code samples, snippets and/or methods. Nutanix expressly disclaims all other guarantees, warranties, conditions and representations of any kind, either express or implied, and whether arising under any statute, law, commercial use or otherwise, including implied warranties of merchantability, fitness for a particular purpose, title and non-infringement therein.