Can Every Pod in Your Cluster Talk to Every Other Pod?
Pick any production Kubernetes cluster in your organization. Run this:
kubectl get networkpolicies -AHow many results come back? If the answer is zero, every pod in that cluster can reach every other pod on every port. No restrictions. No segmentation. A flat, open network.
Now ask yourself: is that what you intended?
The question you need to answer about your cluster
If a single pod in your cluster gets compromised through a vulnerable dependency, what stops the attacker from scanning the entire cluster network, finding your database, your secrets store, your internal APIs, and connecting to all of them?
If you cannot answer that with a specific technical control, you have a flat network problem. NetworkPolicies are not the only control that matters here. RBAC, pod security standards, service mesh mTLS, and runtime detection tools like Falco all play a role. But NetworkPolicies are the one control that restricts what a compromised pod can reach at the network layer, and they are the one most commonly missing.
This is the default, and most clusters stay that way
Kubernetes, by design, operates as a flat network where every pod can communicate with every other pod across all namespaces. The Kubernetes documentation is explicit about this. Without NetworkPolicies, there are no restrictions on pod-to-pod traffic.
This design makes sense for getting started. It reduces friction during early development. But it becomes a serious liability as clusters grow in size, complexity, and tenant count.
The scale of exposure is significant. The CNCF Annual Cloud Native Survey reported that 82% of container users now run Kubernetes in production, up from 66% in 2023. That is a massive installed base running with default-allow networking.
The Red Hat State of Kubernetes Security Report (2024), based on a survey of 600 DevOps, engineering, and security professionals, found that 67% of organizations have delayed or slowed application deployments because of Kubernetes security concerns. 46% reported revenue or customer loss from container or Kubernetes security incidents. 89% experienced at least one container or Kubernetes related security incident in the past year.
These numbers reflect broad security challenges across the Kubernetes stack: misconfigurations, vulnerabilities, access control gaps, and lack of network segmentation. Flat networking is not the sole cause. But when everything can talk to everything, every other misconfiguration gets worse. A container escape is bad. A container escape with unrestricted network access to every pod in the cluster is catastrophic.
Why NetworkPolicies do not get written
If the fix is "write NetworkPolicies," why does almost nobody do it?
Because the NetworkPolicy API is genuinely difficult to work with.
The Kubernetes Network Policy API Working Group, the people responsible for the specification, acknowledged that NetworkPolicy "proves limited in functionality, difficult to extend, understand, and use". This is not an outside critic's opinion. This is the assessment of the working group chartered to improve it.
Here are the specific frustrations that stop teams from adopting NetworkPolicies:
Namespace scope only. NetworkPolicies are namespaced resources. A cluster administrator cannot define a cluster-wide default deny policy in one place. They have to create identical policies in every namespace. Update one? Update them all. Miss one? That namespace is wide open.
No explicit deny. NetworkPolicies only have an "allow" semantic. The deny behavior is implicit: once any policy selects a pod, all traffic not explicitly allowed is denied. This implicit logic makes policies hard to reason about and harder to debug. You cannot look at a single policy and know what it blocks.
Additive evaluation. Multiple policies affecting the same pod combine additively. The allowed traffic is the union of what all applicable policies permit. This means adding a new policy can only make things more permissive, never more restrictive. Order does not matter because there is no priority system.
Silent failure. If your CNI plugin does not support NetworkPolicy enforcement, your policies are silently ignored. You apply them. kubectl get networkpolicies shows them. No errors. No warnings. They do nothing. Your network is still flat.
Flannel in its default configuration does not enforce NetworkPolicies. Clusters running on it will accept your YAML, store it, and ignore it entirely. If you want enforcement, you need Calico, Cilium, or Weave Net.
To check which CNI your cluster runs:
kubectl get pods -n kube-system | grep -E 'calico|cilium|weave|flannel'A note on managed services: most major cloud providers ship CNIs that support NetworkPolicy enforcement. EKS uses the AWS VPC CNI (with Calico or Cilium available for policy enforcement), AKS supports Azure CNI with Cilium, and GKE uses Dataplane V2 (Cilium-based). The Flannel problem is most common in self-managed and on-prem clusters. Know your environment.
What lateral movement looks like without segmentation
In 2018, attackers compromised Tesla's Kubernetes environment by exploiting an unprotected Kubernetes dashboard that had no password. From inside the cluster, they accessed AWS credentials stored in a pod, deployed cryptomining software, and exfiltrated telemetry data from an S3 bucket. The attack combined multiple failures: no authentication on the dashboard, exposed credentials, and no network segmentation to limit what a compromised pod could reach.
That was 2018. The pattern has not changed. A compromised pod in a flat network can:
- Scan the entire cluster IP range and discover every running service.
- Connect to database pods in other namespaces on their service ports.
- Hit internal APIs that were never designed to face untrusted traffic.
- Reach the Kubernetes API server if it is accessible from within the cluster network.
None of this requires a sophisticated attack. It requires a compromised pod and no network segmentation.
Note: some attack paths, like accessing secrets in etcd, require privilege escalation through the Kubernetes API rather than direct network access. NetworkPolicies restrict network-layer traffic. They do not prevent a pod from calling the Kubernetes API using its service account token. For API-layer protections, you need RBAC, pod security admission, and properly scoped service accounts. Network segmentation and API-layer hardening are complementary, not interchangeable.
Starting from default deny
The fix starts with a default deny policy in every namespace, followed by explicit allow rules for the traffic your application actually needs.
Here is a default deny policy:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- EgressThis blocks all inbound and outbound traffic for every pod in the production namespace.
Warning: this will break DNS. The single most common reason teams revert a default-deny egress policy is that pods can no longer resolve DNS names. CoreDNS (or kube-dns) runs in the kube-system namespace, and your pods need to reach it on UDP port 53. Every default-deny namespace needs a companion policy that allows DNS egress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53From here, you add specific policies that allow only the required paths. Here is a working example for a typical three-tier application: a frontend that talks to a backend API, and a backend that talks to a PostgreSQL database.
Allow frontend to backend on port 8080:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080Allow backend to database on port 5432:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-to-database
namespace: production
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 5432With these three policies (default deny, DNS egress, and the application-specific allow rules), your frontend can reach the backend, the backend can reach the database, and a compromised pod in the monitoring namespace cannot reach any of them.
Discover traffic before you write policies
The challenge is knowing what traffic your application actually needs. Do not guess.
If you run Cilium, enable Hubble and observe actual traffic flows before writing policies:
hubble observe --namespace production --verdict ALLOWEDIf you run Calico, enable flow logs or use calicoctl to inspect traffic. If you run neither, you can still start from inside the pod:
kubectl exec -it <pod-name> -n production -- ss -tulnpThis shows you what ports the process inside the pod is listening on and what connections are active. It is not comprehensive, but it tells you the basics: what services the pod exposes, what it is connecting to.
The workflow is: discover existing traffic first, write policies second, validate third.
The AdminNetworkPolicy API: what is coming
The Network Policy API Working Group is not just acknowledging the problems with the current API. They are shipping a fix.
AdminNetworkPolicy and BaselineAdminNetworkPolicy are new cluster-scoped resources that directly address the frustrations listed above:
- Cluster-scoped. Define a policy once, apply it across namespaces. No more duplicating identical policies in every namespace.
- Explicit deny. AdminNetworkPolicy supports Allow, Deny, and Pass actions. You can look at a rule and know exactly what it does.
- Priority ordering. AdminNetworkPolicies have a priority field. Higher-priority policies are evaluated first. Lower-priority policies cannot override them. This gives cluster administrators a way to enforce guardrails that namespace owners cannot circumvent.
- Three-tier evaluation. AdminNetworkPolicy (highest priority) > NetworkPolicy (namespace-level, developer-owned) > BaselineAdminNetworkPolicy (cluster-wide defaults). Administrators set the guardrails. Developers refine within them.
The API is currently v1alpha1. OVN-Kubernetes (used in OpenShift) and Antrea support it today. Cilium has an open feature proposal to add support. Calico supports cluster-scoped policies through its own GlobalNetworkPolicy CRD, which covers similar use cases with a different API surface.
If you are a cluster administrator frustrated by the limitations of the current NetworkPolicy API, this is the upstream effort to watch.
Validating before you apply
Writing a NetworkPolicy and applying it is only half the job. You also need to validate that the policy does what you think it does and does not accidentally allow more than intended.
A policy with podSelector: {} in the ingress from field matches every pod in the namespace. That means any pod in the namespace can reach the target on the specified ports. If that target is your database, you have just allowed your frontend, your logging sidecars, your debug pods, and anything else in the namespace to connect to it directly.
netbobr accepts Kubernetes NetworkPolicy YAML as an import format. It parses the selectors, ports, and CIDR ranges, scores each rule against a risk model that accounts for source breadth, destination breadth, and port exposure, and flags policies that are overly permissive. A policy that allows ingress from podSelector: {} on all ports in a production namespace would score high risk on source breadth because it matches every pod in the namespace, with no restriction on which workloads can reach the target.
This gives you a way to catch overly broad policies before they hit the cluster: the same way you would validate a firewall request before submitting it.
The practical path forward
You do not need to segment an entire cluster in one pass. Start with one namespace that runs something sensitive. Production databases, payment processing, secrets management: pick the highest-value target.
- Check your CNI. Confirm it enforces NetworkPolicies. If not, everything else is theater.
- Discover traffic. Use Hubble, Calico flow logs, or manual inspection to map what your pods actually talk to.
- Apply default deny. Include the DNS egress policy. Test in a staging environment first.
- Write explicit allow rules. Only the paths your application actually needs.
- Validate the policies. Check that the allow rules are not broader than intended.
- Expand to the next namespace. Repeat.
This is not a weekend project. It is a deliberate, iterative process. But the alternative, a flat network where a single compromised pod can reach everything, is not a defensible position.