Kubernetes NetworkPolicy Default Allow Leaves Workloads Exposed
Kubernetes namespaces do not isolate network traffic by default. This trap explains why, how to confirm the exposure with read-only checks, and how to apply and validate a deny-all policy safely.
Operational summary
At a glance
- Symptom
- Workloads in a Kubernetes namespace accept inbound connections from any pod in the cluster, regardless of the intended service boundary.
- Likely cause
- Kubernetes implements an allow-all network model by default.
- Impact
- Unrestricted pod-to-pod networking increases the blast radius of any single compromised workload.
- Verification signal
- Verify that unsolicited inbound traffic is now blocked and that explicitly permitted traffic still succeeds.
- Safe correction
- Apply a default deny-all ingress policy scoped to the specific namespace under review, then layer explicit allow rules for required traffic.
- Rollback or recovery
- If legitimate traffic is disrupted and the specific missing allow rule cannot be identified immediately, remove the deny-all policy to restore the previous allow-all state while the correct…
Symptom
Workloads in a Kubernetes namespace accept inbound connections from any pod in the cluster, regardless of the intended service boundary. During a routine security review, a pod belonging to one application was found able to reach the internal API port of an unrelated application in the same namespace, with no authentication or network-level restriction blocking the connection.
False Assumption
Teams often assume that Kubernetes namespaces provide network isolation by default, treating a namespace boundary as equivalent to a network boundary. Namespaces separate resource quotas, RBAC scope and naming, but Kubernetes documentation on debugging applications describes cluster networking as a distinct, separately configured layer. Namespace separation alone does not restrict which pods can send or receive traffic.
Root Cause
Kubernetes implements an allow-all network model by default. If no NetworkPolicy resource selects a pod, that pod accepts all inbound and outbound traffic from any source inside the cluster. This is a deliberate design choice that favours frictionless initial deployment over restrictive defaults, which means segmentation is opt-in: an operator must author and apply NetworkPolicy resources before any restriction takes effect. Absence of policy is not evidence of absence of exposure; it is the default exposed state.
Impact
Unrestricted pod-to-pod networking increases the blast radius of any single compromised workload. An attacker or a misbehaving process with access to one pod can probe network ports on every other pod in the namespace, and in many cluster network plugin configurations, across namespaces as well, bypassing application-layer authentication that was never designed to be the sole line of defence. The consequence is inferred from the documented default behaviour rather than observed in this instance, and should be confirmed against the specific network plugin in use before being treated as guaranteed for every deployment.
Diagnosis
Confirm the absence of NetworkPolicy resources selecting the affected workloads before making any change. This is a read-only check and produces direct evidence of the current state.
kubectl get networkpolicy -n <namespace>
An empty result, or a result containing policies whose podSelector does not match the affected pods, confirms that those pods are operating under the default allow-all rule. Record the namespace, the pod labels involved and the absence of a matching policy as the evidence baseline before proceeding to any change.
Correction
Apply a default deny-all ingress policy scoped to the specific namespace under review, then layer explicit allow rules for required traffic. Do not apply this to a namespace shared with unrelated production workloads without first identifying every legitimate traffic path, since the policy takes effect immediately for every pod it selects.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: <namespace>
spec:
podSelector: {}
policyTypes:
- Ingress
This is a state-changing action. Apply it first in an isolated or non-production namespace, confirm the intended behaviour, and only then repeat the change in a namespace that carries real traffic, with a maintenance window and a rollback path agreed in advance.
Validation
Verify that unsolicited inbound traffic is now blocked and that explicitly permitted traffic still succeeds. Use a disposable debug pod rather than a production workload for the negative test.
- Deploy a temporary test pod in the same namespace using an existing, already-approved base image.
- From the test pod, attempt a connection to a port on a pod that should now be isolated; the pass condition is a connection timeout or explicit refusal.
- From a pod that has an explicit allow rule, attempt the same class of connection; the pass condition is a successful response, confirming the deny-all policy did not silently block required traffic.
- Remove the temporary test pod once both checks are complete.
If the required-traffic check fails, do not leave the deny-all policy in place while you investigate; follow the rollback path below and re-diagnose the missing allow rule in the non-production namespace first.
Rollback
If legitimate traffic is disrupted and the specific missing allow rule cannot be identified immediately, remove the deny-all policy to restore the previous allow-all state while the correct allow rules are worked out.
Removing a NetworkPolicy is itself a state-changing, security-relevant action: it restores the wider exposure described in this trap, so treat it as a temporary containment measure, not a resolution, and re-apply segmentation as soon as the missing allow rule is confirmed. Because deleting the policy directly reintroduces the original exposure, escalate to a team member with cluster-admin context before removing it in any namespace carrying live traffic, and confirm the specific policy name and namespace with kubectl get networkpolicy -n <namespace> immediately beforehand to avoid removing the wrong resource.
Prevention
Treat NetworkPolicy coverage as a required property of every namespace rather than an optional hardening step. Add a check to the namespace provisioning or deployment pipeline that fails a build if a namespace has running workloads but no NetworkPolicy selecting them, using the same read-only kubectl get networkpolicy query shown in diagnosis. Review namespace network posture on a fixed schedule rather than only after an incident, and confirm the behaviour of the specific network plugin in use, since NetworkPolicy enforcement depends on the plugin implementing it correctly; the default-deny model described here is the Kubernetes API specification, not a guarantee of every plugin’s enforcement fidelity.
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
kubectl get networkpolicy -n <namespace>podSelectorapiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: <namespace>
spec:
podSelector: {}
policyTypes:
- IngressVerify, roll back or escalate
Verify
Verify that unsolicited inbound traffic is now blocked and that explicitly permitted traffic still succeeds.
Rollback
If legitimate traffic is disrupted and the specific missing allow rule cannot be identified immediately, remove the deny-all policy to restore the previous allow-all state while the correct allow rules are worked out.
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.