Kubernetes ships with a trust model that most operators never examine. The platform assumes a trusted control plane, trusted node infrastructure, and network-level isolation that maps cleanly onto organizational boundaries. In practice, those assumptions erode the moment you introduce multiple teams, shared clusters, and the inevitable RBAC configurations that start as “we’ll tighten this later” and never get tightened.
What Kubernetes Assumes vs What Operators Assume
The Kubernetes trust model is surprisingly explicit if you read the security documentation carefully. The control plane (API server, etcd, scheduler, controller manager) is a trusted computing base. Nodes are semi-trusted: they can only access secrets for pods scheduled to them, albeit the kubelet API itself is a rich attack surface. The network is assumed flat by default, with every pod able to reach every other pod across every namespace.
Operators, meanwhile, carry a different mental model entirely. Namespaces feel like meaningful isolation, RBAC looks like it prevents lateral movement, and deploying a NetworkPolicy resource seems like it actually restricts traffic. Each of these assumptions contains a gap between intent and reality that widens under production pressure.
This mirrors a pattern visible across layered security architectures: every layer leaks, and the layers you assume are airtight are the ones that fail most dangerously.
Namespace Isolation Is a Naming Convention, Not a Security Boundary
Namespaces are the most misunderstood abstraction in Kubernetes. Teams treat them as security boundaries, mapping tenants to namespaces and assuming that what happens in team-alpha stays in team-alpha. The reality is far less comforting.
Every namespace in a cluster shares the same Linux kernel on each node, the same etcd datastore backing the API server, the same API server endpoint, and the same container runtime. A container escape in one namespace gives an attacker kernel-level access to every other container on that node. A misconfigured ClusterRole binding in one namespace can grant read access to secrets across all namespaces. The shared etcd instance means that a compromise of the control plane exposes every tenant’s configuration, secrets, and state simultaneously.
The kernel sharing problem is particularly acute. Whilst container runtimes like containerd and CRI-O provide process-level isolation through Linux namespaces and cgroups, they all share the host kernel’s syscall surface. A kernel vulnerability exploitable from within a container affects every container on that node, regardless of which Kubernetes namespace they belong to. Sandboxed runtimes like gVisor and Kata Containers address this by interposing an additional isolation layer, albeit with meaningful performance overhead that most teams aren’t willing to accept for all workloads.
RBAC: The Gap Between Least-Privilege Intent and Wildcard Reality
Every Kubernetes RBAC configuration starts with good intentions. The security team writes a policy requiring least-privilege access, the platform team creates a set of Roles and ClusterRoles that look reasonable in the design document, and the whole thing starts drifting the moment real workloads land.
The drift pattern is predictable: a developer needs to debug a failing deployment and gets get access to pods. Logs require pods/log, so that gets added. Exec into a container demands pods/exec, and that arrives next. Each permission makes sense in isolation, and each one widens the blast radius. The most common RBAC finding I encounter across the clusters I’ve audited is the wildcard verb on the wildcard resource: verbs: ["*"] on resources: ["*"]. It exists because someone needed to unblock a deployment at speed, and the rollback never happened.
RBAC policies drift under incident pressure, where speed beats scope every time, and the permission rollback never makes it onto the backlog.
ClusterRoles compound this problem because they apply across all namespaces. A ClusterRoleBinding intended for a platform team’s monitoring service account, if bound too broadly, gives that service account the same access across tenant namespaces. The blast radius of a single misconfigured ClusterRoleBinding spans the entire cluster.
Pod Security Standards: Why Many Clusters Run Privileged
Kubernetes Pod Security Standards define three profiles: Privileged (unrestricted), Baseline (prevents known privilege escalations), and Restricted (hardened best practices). The specification is well-designed, with each level clearly documented and the enforcement mechanism (Pod Security Admission) available in the API server since v1.23.
In my experience, many production clusters run Privileged by default. The reason is practical: system components, monitoring agents, log collectors, CSI drivers, and service mesh sidecars frequently require elevated privileges. Rather than carving out exceptions for infrastructure workloads and enforcing Baseline or Restricted for application workloads, teams apply the most permissive profile cluster-wide to avoid breaking deployments.
Multi-Tenancy: Choosing Your Isolation Guarantee
Once you accept that namespaces alone don’t provide security isolation, the multi-tenancy question becomes one of choosing your isolation guarantee and accepting its cost.
Namespace-per-tenant is the cheapest option in infrastructure cost and the weakest in isolation. It works when tenants trust each other, share an organizational security boundary, and the platform team enforces NetworkPolicies, ResourceQuotas, and Pod Security Standards consistently. It breaks down when tenants are external customers, compliance-separated business units, or any context where a shared kernel is unacceptable.
Cluster-per-tenant provides strong isolation at significant operational cost. Each tenant gets a dedicated control plane, dedicated nodes, and no shared kernel surface. The trade-off is managing fleet-wide configuration, upgrades, and observability across potentially hundreds of clusters. Tools like Cluster API and fleet management platforms (Rancher, Anthos) reduce the operational burden, albeit they introduce their own control plane trust dependencies.
Virtual clusters (vCluster, Kamaji) occupy the middle ground. Each tenant gets a dedicated API server and etcd instance running as pods inside a host cluster, providing control plane isolation without dedicated infrastructure. The workloads still share the host cluster’s nodes and kernel, so the compute isolation story is similar to namespace-per-tenant, albeit the API-level isolation prevents the ClusterRole and etcd cross-contamination problems.
Network Policies as Trust Boundary Enforcement
The default Kubernetes network model is a flat network where every pod can communicate with every other pod. NetworkPolicies are the mechanism for imposing structure onto that flat surface, and the default-deny pattern is the foundation of any meaningful network-level trust boundary.
A default-deny ingress policy in every namespace flips the model: traffic is blocked unless explicitly allowed. This is conceptually simple and operationally demanding, because every legitimate communication path needs a corresponding NetworkPolicy rule. Teams that skip default-deny and instead write allow-list policies on top of the default-allow model inevitably leave gaps, since you can’t enumerate every communication path that shouldn’t exist.
The CNI plugin choice matters here. Calico provides robust NetworkPolicy support with additional Calico-specific policy resources for more granular control. Cilium uses eBPF to enforce policies at the kernel level, with the added benefit of identity-based enforcement (policies can reference Kubernetes labels directly rather than IP addresses, which is critical in environments where pod IPs are ephemeral). Cilium’s Hubble observability layer gives visibility into what traffic is actually flowing, which is invaluable for validating that your policies match your intent.
Service Mesh as the Trust Boundary Layer
NetworkPolicies operate at L3/L4: they control which pods can communicate, but they don’t authenticate the communication or authorize specific requests. A service mesh (Istio, Linkerd, Cilium’s sidecar-less mesh) adds L7 trust boundaries through mTLS and authorization policies.
With mTLS enabled mesh-wide, every service-to-service call is encrypted and mutually authenticated. Services prove their identity through certificates issued by the mesh’s certificate authority, and the mesh’s authorization policies can enforce rules like “only the payment service can call the billing API’s charge endpoint.” This moves trust enforcement from the network layer (can these pods talk?) to the application layer (is this specific service authorized to make this specific request?).
The trust chain here matters. The mesh’s control plane issues certificates, manages policy distribution, and mediates the trust relationships between services. A compromise of the mesh control plane (Istiod, Linkerd’s control plane) undermines every trust boundary the mesh enforces. This is the same control plane trust problem that appears throughout infrastructure: the component you trust to enforce your security model is itself a high-value target that requires its own security boundary.
Every trust boundary enforcement mechanism introduces its own control plane, and that control plane becomes the highest-value target in the system. Securing the enforcer is at least as important as securing what it enforces, and often demands a broader threat model.
What Blockchain’s Trust Model Teaches About Infrastructure
Blockchain protocols start from a lower trust baseline: participants prove their claims cryptographically, state transitions are independently verifiable, and the trust model is encoded in the protocol rather than assumed from the deployment environment. Kubernetes starts from the opposite end, with trust baked into the control plane, the network fabric, and the assumption that operators will configure boundaries correctly.
Assumed trust scales poorly. A system that works securely when one team runs one cluster starts leaking trust boundaries when five teams share a cluster, and the leaks compound when those teams have different compliance requirements, different threat models, and different definitions of “production-ready.” Making trust boundaries explicit, enforced at the platform level rather than assumed through convention, is harder upfront and dramatically more resilient as the organization grows.
Running Kubernetes well means treating trust boundaries as a first-class architectural concern: designing namespace structures around isolation requirements rather than org charts, enforcing Pod Security Standards per-namespace, deploying default-deny NetworkPolicies before the first application pod, and running a service mesh for workloads that need L7 authorization. Without that upfront investment, the trust boundary gaps surface through incidents instead of architecture reviews.