Free tech learning for everyone, from basics to pro

Kubernetes SecurityCloud SecurityIntermediate

Kubernetes network policies: default deny and allowing only needed traffic

In short: By default every pod in a Kubernetes cluster can talk to every other pod. Network policies, enforced by the cluster network plugin, let you deny all traffic and then allow only named flows by label, namespace and port. This contains attackers and is a core part of zero trust in a cluster.

The default is wide open

Kubernetes gives every pod an IP address and, out of the box, lets any pod connect to any other pod in any namespace. If an attacker compromises one web pod, they can scan and reach databases, internal APIs and monitoring tools across the cluster. A NetworkPolicy is a Kubernetes object that restricts this, using labels to select pods.

Without and with network policiesNo policiesAny pod reaches any podFlat networkEasy lateral movementEgress unrestrictedDefault deny plus allowsOnly listed flows workSegmented by labelBreach is containedEgress controlled
Figure 1. Kubernetes allows all pod traffic by default; network policies turn it into an allow-list.

Policies are enforced by the Container Network Interface (CNI) plugin, not by Kubernetes itself. Calico, Cilium and most managed-cloud network options support them, but a few basic plugins do not. If your CNI ignores policies, applying them silently does nothing, so always test.

How policies work

  • A policy selects pods with podSelector. Once any policy selects a pod for ingress (or egress), that direction becomes deny-by-default for that pod, and only listed traffic is allowed.
  • Rules can allow traffic from or to other pods (podSelector), namespaces (namespaceSelector) or IP ranges (ipBlock), on given ports.
  • Policies are additive: if several apply, the union of their allows is permitted.
  • Standard NetworkPolicy works at layers 3 and 4. Some CNIs add layer 7 rules, DNS-name rules or cluster-wide policies through their own resources.

Default deny, then allow

Start each application namespace with a policy that denies all ingress and egress:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: shop
spec:
  podSelector: {}
  policyTypes: ["Ingress", "Egress"]

Denying egress also blocks DNS, so almost every namespace needs a rule allowing UDP and TCP port 53 to the cluster DNS pods. Then add specific allows, such as letting the API pods reach the database on its port:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-allow-api
  namespace: shop
spec:
  podSelector:
    matchLabels: { app: db }
  policyTypes: ["Ingress"]
  ingress:
  - from:
    - podSelector:
        matchLabels: { app: api }
    ports:
    - protocol: TCP
      port: 5432

Designing policies

Three-tier policy designIngresscontrollerfrom internetFrontend podsallow from ingressAPI podsallow from frontendDatabase podsallow from API only
Figure 2. With default deny in place, each tier accepts traffic only from the tier in front of it.
  1. Map the real flows for each app, using CNI flow logs or observability tools where available.
  2. Label pods consistently (for example app and tier), because policies depend on labels.
  3. Apply default deny per namespace, plus a DNS allow.
  4. Add allow rules tier by tier and test each one.
  5. Restrict egress to the internet, and block the cloud metadata address (169.254.169.254) for pods that do not need it.
  6. Keep policies in git and review them like code.
Common mistakeEffect
Forgetting DNS after egress denyEvery app breaks with name resolution errors
CNI does not enforce policiesFalse sense of security
Allowing whole namespacesAny compromised pod there gets access
Labels anyone can changeAttackers relabel pods to match allow rules

Tip: this is the cluster version of the segmentation ideas in zero trust segmentation: deny by default and allow by identity, not by network location.

Practice

You apply a default-deny egress policy and every app fails to resolve names. Why?
DNS traffic to the cluster DNS service is now blocked; add a policy allowing port 53 to the DNS pods.
What enforces Kubernetes network policies?
The CNI network plugin, such as Calico or Cilium. Without a supporting plugin, policies have no effect.
What does an empty podSelector ({}) select?
Every pod in the policy namespace.

Key takeaways

  • Kubernetes allows all pod-to-pod traffic by default.
  • Network policies select pods by label and allow listed flows.
  • Start with default deny for ingress and egress, plus DNS.
  • Enforcement depends on the CNI; test that it works.
  • Restrict egress and access to the cloud metadata service.
Tracks your learning on this device only. See your progress on the learning paths.

About the author

Mohamed Fayas

Founder of FM TecHub. CCNA certified, with a BTEC HND in Network Engineering, and BEng (Hons) in Computer Networking and Cloud Security. He writes practical, plain-English guides on networking, security and cloud.

More about the author

Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.

Stay up to date by email

New notes, tools and security news from FM TecHub, explained simply. Free.

We only use your email to send these updates. See our privacy policy.