Skip to main content
cd ../config-traps
risk/register/networkpolicy-additive-allow-all-overrides-deny-all.html
Kubernetes Networkinghigh severityKubernetes

Additive NetworkPolicy Semantics Let a Leftover Allow-All Rule Override a New Deny-All Policy

Severity
high
Reviewed
6 Aug 2026
Remediation
~20 minutes
Overview

A new deny-all NetworkPolicy in Kubernetes does not override an existing allow-all policy for the same pods; the two combine additively, leaving the namespace exposed while dashboards show the restriction as active.

Operational summary

At a glance

Symptom
A namespace that the platform team believed was newly locked down by a deny-all NetworkPolicy still accepts ingress traffic from pods that were supposed…
Likely cause
Kubernetes NetworkPolicies for a given pod are combined additively, not by override or precedence.
Impact
Every pod in the affected namespace remains reachable from any source that the legacy allow-all policy permitted, even though the team's change record and dashboards show a deny-all…
Verification signal
Re-run the same connectivity test used during diagnosis and confirm it now fails in the way the deny-all policy intends.From the disposable test pod, attempt the same connection…
Safe correction
Remove or narrow the overlapping legacy policy so the deny-all policy is no longer contradicted by an existing allow-all rule for the same pods.Identify every NetworkPolicy whose podSelector…
Rollback or recovery
If removing or narrowing the legacy policy breaks traffic that other services depend on, restore the previous policy set exactly as it existed before the change.Re-apply the original…

Symptom

A namespace that the platform team believed was newly locked down by a deny-all NetworkPolicy still accepts ingress traffic from pods that were supposed to be cut off, and a connectivity check from an unauthorised test pod returns a successful HTTP response instead of a connection timeout.

The deny-all policy was applied, is present when listed with kubectl get networkpolicy, and shows no errors in its status. Yet traffic that the team expected to be blocked continues to flow, and no alert or admission error indicates that anything is wrong.

False Assumption

The team assumed that applying a NetworkPolicy with an empty ingress rule set to a pod selector behaves like a firewall change: the newest, most restrictive rule for a given pod supersedes any earlier, more permissive rule that also selects that pod.

This mental model is reasonable for many network appliances, where rule order or rule specificity determines the effective outcome. It does not hold for Kubernetes NetworkPolicy objects.

Root Cause

Kubernetes NetworkPolicies for a given pod are combined additively, not by override or precedence. If any NetworkPolicy selecting a pod permits a given ingress connection, that connection is allowed, regardless of how many other NetworkPolicies also select that pod and would otherwise deny it. A pod becomes “isolated” for a traffic direction only once at least one policy selects it for that direction, and the effective allow-list for that pod is the union of the allow rules from every matching policy.

In this trap, an existing NetworkPolicy with a broad podSelector: {} and an open ingress rule was already selecting every pod in the namespace and allowing ingress from all sources. A new, narrower deny-all policy (empty ingress: [] with the same or overlapping selector) was applied with the intention of tightening access. Because policies combine additively, the union of the two policies still includes the original allow-all rule, so ingress remains fully open for any pod matched by both.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: legacy-allow-all
  namespace: payments
spec:
  podSelector: {}
  policyTypes: [Ingress]
  ingress:
    - {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: new-deny-all
  namespace: payments
spec:
  podSelector: {}
  policyTypes: [Ingress]
  ingress: []

Impact

Every pod in the affected namespace remains reachable from any source that the legacy allow-all policy permitted, even though the team’s change record and dashboards show a deny-all policy as “applied and active”.

The practical consequence is a false sense of network isolation. Workloads that the team believes are segmented from other namespaces, or from the wider cluster network, continue to accept unrestricted ingress. Depending on what the affected pods run, this can expose internal APIs, databases or admin interfaces to any pod or external caller that the older policy still permits, without any corresponding alert.

Diagnosis

Confirm the trap before making further changes, using read-only inspection of the existing policy objects.

  • List every NetworkPolicy in the affected namespace and note each one’s podSelector and policyTypes.
  • For each policy that selects the same pods as the new deny-all rule, inspect its ingress rules for a broad or empty match (such as an ingress entry with no from field).
  • From a disposable test pod inside the cluster, attempt a connection to a representative pod in the namespace and record whether it succeeds or times out.

Correction

Remove or narrow the overlapping legacy policy so the deny-all policy is no longer contradicted by an existing allow-all rule for the same pods.

  • Identify every NetworkPolicy whose podSelector overlaps with the new deny-all policy’s selector.
  • Either delete the legacy allow-all policy if it is no longer required, or rewrite it with a scoped podSelector and explicit from rules that match only the traffic that must still be permitted.
  • Re-apply the deny-all policy only after the overlapping permissive rule has been removed or scoped, so the union of active policies reflects the intended restriction.

Validation

Re-run the same connectivity test used during diagnosis and confirm it now fails in the way the deny-all policy intends.

  • From the disposable test pod, attempt the same connection that previously succeeded; it should now time out or be refused.
  • List NetworkPolicies again and confirm no remaining policy in the namespace grants an unscoped or empty ingress rule to the same pod selector.
  • Confirm any traffic that must still be permitted (for example, from a monitoring namespace) is allowed only through an explicit, scoped rule, not through a leftover broad policy.

Rollback

If removing or narrowing the legacy policy breaks traffic that other services depend on, restore the previous policy set exactly as it existed before the change.

  • Re-apply the original legacy allow-all NetworkPolicy manifest that was removed or edited, using the version stored in source control or captured before the change.
  • Delete the new deny-all policy if its presence alongside the restored legacy policy causes confusion in change records, since it has no effect while the legacy rule remains broad.
  • Confirm restored connectivity with the same test-pod connection check used in validation, expecting the pre-change result to return.

Prevention

Treat every new NetworkPolicy as an addition to an existing set of rules, not a replacement, and audit for overlap before relying on a new policy to tighten access.

  • Before applying any new restrictive policy, list all existing policies that share a pod selector and review their combined effect, not just the new policy in isolation.
  • Avoid broad podSelector: {} allow rules in shared namespaces; scope allow rules to specific labels so they cannot silently combine with later deny-all attempts.
  • Add a namespace-level review step that lists NetworkPolicy objects and their effective combined ingress rules as part of any change that claims to restrict network access.
03

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
podSelector: {}
ingress: []
04

Verify, roll back or escalate

Verify

Re-run the same connectivity test used during diagnosis and confirm it now fails in the way the deny-all policy intends.From the disposable test pod, attempt the same connection that previously succeeded; it should now time out or be refused.List NetworkPolicies…

Rollback

If removing or narrowing the legacy policy breaks traffic that other services depend on, restore the previous policy set exactly as it existed before the change.Re-apply the original legacy allow-all NetworkPolicy manifest that was removed or edited, using the version…

Escalate

Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.

After remediation

Further reading stays below the corrective workflow and is selected by platform, category and shared technical keywords.

Discover more

Connected KBY resources