Skip to content
daniel@cosenza:~/blog
SRE & DevOpsHow-To April 29, 2026 3 min read

How to Set Up Kubernetes NetworkPolicies

A complete walkthrough restricting which pods can talk to which — Kubernetes allows all pod-to-pod traffic by default, and NetworkPolicies are how you actually change that.

By default, Kubernetes networking allows every pod to communicate with every other pod in the cluster, regardless of namespace — a NetworkPolicy is how you restrict that to only the traffic you actually intend to allow.

Step 1: confirm your cluster’s CNI plugin actually supports NetworkPolicy

kubectl get pods -n kube-system

NetworkPolicy resources are silently ignored if the cluster’s CNI plugin doesn’t implement them — not every CNI does. Calico, Cilium, and Weave Net all support NetworkPolicy; some simpler CNI plugins do not, in which case creating these resources has no actual effect regardless of how they’re written.

Step 2: start by understanding the default-allow baseline

Before writing any policies, understand what you’re changing: with zero NetworkPolicies applied, every pod can reach every other pod on any port. The moment you apply any NetworkPolicy selecting a given pod, that pod’s traffic becomes default-deny for whichever direction (ingress/egress) the policy covers — only explicitly allowed traffic gets through from that point on.

Step 3: create a default-deny-all policy for a namespace

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

An empty podSelector: {} matches every pod in the namespace — combined with no rules under Ingress/Egress, this denies all traffic by default, a common, deliberate starting point before adding specific allow rules on top.

Step 4: allow specific ingress traffic between two applications

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: myapp
spec:
  podSelector:
    matchLabels: {app: backend}
  ingress:
    - from:
        - podSelector:
            matchLabels: {app: frontend}
      ports:
        - port: 8080

This allows pods labeled app: frontend to reach pods labeled app: backend on port 8080 specifically — everything else remains blocked by the default-deny policy from Step 3.

Step 5: allow traffic from a specific namespace

ingress:
  - from:
      - namespaceSelector:
          matchLabels: {name: monitoring}

Useful for allowing a monitoring namespace’s Prometheus instance to scrape metrics endpoints across other namespaces, without opening those pods up to arbitrary traffic from everywhere else.

Step 6: allow necessary egress traffic explicitly

egress:
  - to:
      - namespaceSelector:
          matchLabels: {name: kube-system}
    ports:
      - protocol: UDP
        port: 53

Don’t forget DNS — a default-deny egress policy blocks DNS resolution too unless explicitly allowed, which breaks nearly everything in ways that can be confusing to diagnose if this specific rule is missed.

Step 7: test the policy actually behaves as intended

kubectl run test-pod --image=busybox --rm -it --labels="app=frontend" -- wget -qO- backend:8080
kubectl run test-pod2 --image=busybox --rm -it --labels="app=other" -- wget -qO- backend:8080

Confirm the allowed path succeeds and an unrelated pod without the matching label is actually blocked — testing both the positive and negative case, not just that the intended traffic works.

Step 8: apply policies incrementally, namespace by namespace

Rolling out default-deny policies across an entire cluster all at once, without first testing in one namespace, risks breaking legitimate traffic patterns you didn’t realize existed — applying incrementally and monitoring for unexpected connection failures is a meaningfully safer rollout path.

Why NetworkPolicy’s default-allow starting point catches people off guard

Most engineers coming from traditional network security assume “deny by default, explicitly allow what’s needed” is how Kubernetes networking already works out of the box — it isn’t, until you introduce NetworkPolicies yourself. Understanding that the default is wide open, and that policies are additive restrictions layered on top rather than a pre-existing restrictive baseline, is the conceptual model that makes the rest of NetworkPolicy configuration make sense.