>DevOps Interview KB

How would you design NetworkPolicies for a namespace using default-deny-all while still allowing necessary traffic?

IntermediateArchitectureKubernetes7 min read

Short Answer

Start with a baseline policy that selects all pods and denies all ingress and egress by default, then layer additional, narrowly-scoped policies that explicitly allow exactly the traffic patterns the namespace's applications actually need (specific pod-to-pod paths, DNS resolution, any required external egress) — building up from zero-trust rather than trying to retrofit restrictions onto an already-open namespace.

Detailed Explanation

Default-deny is a posture, not a single policy object — it's achieved by combining a blanket deny-everything baseline with a deliberately curated set of narrow allow-rules layered on top, and the design work is entirely in getting that layering right without breaking legitimate traffic.

Requirements

  • No traffic should be allowed by default; every allowed path must be the result of an explicit policy.
  • DNS resolution must continue working, since it's easy to accidentally block and causes widespread, confusing failures.
  • Legitimate application traffic (both within the namespace and to necessary external/cross-namespace destinations) must continue working without disruption.
  • The policy set should be maintainable as the namespace's applications evolve, not a one-time snapshot that goes stale.

Architecture

The default-deny baseline uses an empty podSelector with both policy types specified: a NetworkPolicy with spec.podSelector: {} (matching every pod in the namespace) and spec.policyTypes: [Ingress, Egress], but no ingress/egress rules at all, denies all traffic by default for every pod it selects — this is the foundational policy everything else builds on top of.

DNS egress must be explicitly allowed immediately, or nearly everything breaks confusingly: a default-deny-egress policy blocks DNS resolution (since it's just another network flow) unless explicitly permitted — an egress rule allowing UDP/TCP port 53 to the cluster's DNS service (typically in kube-system) needs to be one of the very first additional policies, since without it, applications fail in ways that don't obviously point to "this is a NetworkPolicy problem" (timeouts, resolution failures that look like a DNS outage).

Additional policies each express one specific, intentional allowed path: rather than one large, complex policy, separate NetworkPolicies (or separate rules within a small number of them) for each distinct legitimate traffic pattern — "frontend can reach backend on port 8080," "backend can reach the database on port 5432" — keeps each rule's intent legible and independently reviewable, rather than one sprawling policy that's hard to reason about or safely modify later.

Use namespaceSelector and podSelector together for cross-namespace traffic: if the namespace's applications need to talk to something in a different namespace (a shared platform service, for instance), the ingress/egress rule needs to specify both which namespace and which pods within it — omitting the podSelector within a matched namespace allows all pods in that namespace, which may be broader than intended.

Roll out incrementally, validating each addition against real traffic: applying default-deny in one step to an already-running namespace risks an outage from missing an allowed path nobody remembered to account for — starting in a non-production environment, or using each CNI plugin's available "audit"/log mode (where supported) to observe what traffic would be blocked before actually enforcing it, catches gaps before they cause a real incident.

Trade-offs

A fully explicit default-deny policy set requires ongoing maintenance as the namespace's applications add new traffic patterns — a new microservice-to-microservice call that isn't yet covered by a policy will simply fail, requiring someone to add the corresponding allow-rule, which is friction compared to an open namespace where nothing needs updating. This friction is the intended trade-off for the security benefit, but it does mean the policy set needs a clear owner and a reasonably fast process for adding new legitimate rules, or it becomes an obstacle developers route around rather than a control that's actually respected.

Interview Follow-Up Questions

  • How would you audit an existing, already-open namespace to discover exactly what traffic patterns actually exist, before designing the allow-rules?
  • How would you handle a namespace where different teams own different microservices, in terms of who's responsible for adding new allow-rules as services evolve?
  • What's the difference in how you'd approach this for egress to the public internet versus egress to other in-cluster namespaces?

Key Takeaways

  • The default-deny baseline uses an empty podSelector matching all pods, with both Ingress and Egress in policyTypes, and no rules — denying everything by default.
  • DNS egress needs to be explicitly allowed immediately, since blocking it produces widespread, confusing failures that don't obviously point to NetworkPolicy.
  • Express each legitimate traffic pattern as its own clear, narrowly-scoped policy rather than one large complex one, for reviewability and safer future changes.
  • Roll out incrementally with an audit/observe step before full enforcement, to catch missing allow-rules before they cause a production outage.

References

Last updated August 22, 2026 · Last reviewed August 22, 2026