Kubernetes Networking Without Default-Deny: The Flat Trap
Every namespace in a fresh Kubernetes cluster can reach every other namespace over the pod network because no NetworkPolicy resources exist anywhere. A single compromised pod in a low-trust namespace can then query internal services directly by ClusterIP or DNS, and existing RBAC and namespace boundaries do nothing to stop it.
Operational summary
At a glance
- Symptom
- A compromised pod in one namespace connects directly to services in another namespace with no policy blocking the path.
- Likely cause
- No NetworkPolicy resources exist in any namespace, leaving the pod network fully open by default.
- Impact
- Attackers pivot laterally across namespaces via pod IPs or ClusterIP DNS with no segmentation, authentication, or logging to stop them.
- Verification signal
- Re-run the detection test and a controlled negative-path test.
- Safe correction
- Deploy a default-deny NetworkPolicy in every namespace and enforce it with a policy-aware CNI such as Calico or Cilium.
- Rollback or recovery
- Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
The Trap
The absent default-deny NetworkPolicy. Kubernetes ships with no built-in network segmentation model. Unless an administrator explicitly creates NetworkPolicy objects, every pod on the cluster network can initiate a connection to every other pod, on any port, across any namespace, provided the underlying CNI plugin honours NetworkPolicy at all.
The Default State
A vanilla cluster install, whether kubeadm, EKS, AKS, or GKE with a basic CNI, applies zero NetworkPolicy resources at creation time. Namespaces are treated by engineers as logical and administrative boundaries, when in fact they impose no network isolation whatsoever. Teams routinely rely on namespace separation for multi-tenancy or environment isolation (dev, staging, payments, logging) while the pod network underneath remains completely flat. Ingress and egress are unrestricted by default, and this is documented Kubernetes behaviour, not a bug.
The Blast Radius
A single exploited container, say a public-facing web pod with a deserialisation vulnerability, can immediately reach the internal payments namespace, the secrets-management namespace, or kube-system components such as the metrics-server or CoreDNS pods, purely via pod IP or in-cluster DNS. There is no lateral-movement friction: no firewall rule, no segmentation, no authentication layer sits between namespaces. An attacker can port-scan the entire pod CIDR from inside one low-value workload, enumerate ClusterIP services, and pivot straight into databases or internal APIs that were never designed to be reachable from outside their own namespace. RBAC controls the Kubernetes API surface, not the pod-to-pod data plane, so tightly scoped ServiceAccounts and roles provide no protection here at all.
The Lead Mechanic Fix
Apply a default-deny NetworkPolicy in every namespace before any workload is scheduled: a policy with podSelector: {} and policyTypes: [Ingress, Egress] and no rules, which blocks all traffic by default. Layer explicit allow policies on top for required service-to-service paths only, matched by podSelector and namespaceSelector labels, never by CIDR ranges that drift. Confirm the CNI actually enforces NetworkPolicy (Calico, Cilium, or Azure CNI in policy mode; flannel alone does not). For stricter control, deploy Cilium with L7-aware CiliumNetworkPolicy or Calico GlobalNetworkPolicy to enforce a cluster-wide default-deny baseline that new namespaces inherit automatically, rather than relying on per-namespace hygiene.
Implementation Example
Apply the baseline to one test namespace first. Replace replace-me with the target namespace and confirm that explicit DNS and application allow policies are ready before wider rollout.
Default-deny ingress and egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: replace-me
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Inventory and controlled verification
# Inventory policies and identify namespaces with no baseline
kubectl get networkpolicy --all-namespaces
# Confirm the policy is present in the test namespace
kubectl -n replace-me describe networkpolicy default-deny-all
# Launch a temporary probe, then test a path that should be denied
kubectl -n replace-me run netpol-test
--image=curlimages/curl:8.10.1
--restart=Never -- sleep 3600
kubectl -n replace-me exec netpol-test --
curl --connect-timeout 5 http://TARGET_SERVICE.TARGET_NAMESPACE.svc.cluster.local
# Remove the temporary probe after testing
kubectl -n replace-me delete pod netpol-test
The denied request should time out or fail to connect. Repeat the test against every explicitly allowed path and confirm those requests still succeed before extending the baseline to another namespace.
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Fix commands and configuration
replace-meapiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: replace-me
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress# Inventory policies and identify namespaces with no baseline
kubectl get networkpolicy --all-namespaces
# Confirm the policy is present in the test namespace
kubectl -n replace-me describe networkpolicy default-deny-all
# Launch a temporary probe, then test a path that should be denied
kubectl -n replace-me run netpol-test
--image=curlimages/curl:8.10.1
--restart=Never -- sleep 3600
kubectl -n replace-me exec netpol-test --
curl --connect-timeout 5 http://TARGET_SERVICE.TARGET_NAMESPACE.svc.cluster.local
# Remove the temporary probe after testing
kubectl -n replace-me delete pod netpol-testVerify, roll back or escalate
Verify
Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.
Rollback
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.