Articles

Kubernetes Network Policies Explained

Kubernetes NetworkPolicies control which pods can talk to which, at the network layer. Here's how they work and why pods are open by default.

Chisato Chisato · · 4 min read
Network switch with patch cables

A NetworkPolicy is a Kubernetes resource that controls which pods are allowed to send or receive traffic from which other pods, namespaces, or IP ranges. Without one, Kubernetes pods can reach any other pod in the cluster by default — flat, fully open networking. NetworkPolicies are how you introduce actual segmentation, restricting communication to only the paths your application intentionally needs.

Why pod networking starts out fully open

Kubernetes networking is designed so every pod gets its own IP address and can, by default, reach every other pod in the cluster without NAT. That flat model makes service discovery and scaling simple — pods don’t need to know about network topology to talk to each other — but it also means a compromised pod in one namespace can, by default, probe and connect to workloads in a completely unrelated namespace.

That’s a meaningfully different default than most people assume. Setting up RBAC controls who can create or modify resources through the Kubernetes API, but it says nothing about which pods can talk to which over the network at runtime — those are two separate layers of access control, and it’s easy to lock down one while leaving the other wide open.

What a NetworkPolicy actually restricts

A NetworkPolicy selects a set of pods (via label selectors, the same mechanism used throughout pods, deployments, and services) and then defines ingress and/or egress rules for traffic to and from that set. A minimal example that only allows a backend pod to receive traffic from pods labeled role: frontend:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-allow-frontend
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              role: frontend
      ports:
        - protocol: TCP
          port: 8080

The critical detail: as soon as any NetworkPolicy selects a pod for a given direction (ingress or egress), that pod’s default for that direction flips from “allow all” to “deny all except what’s explicitly permitted.” A pod with no matching NetworkPolicy at all stays fully open. This all-or-nothing switch per pod is a common source of outages — adding one narrow policy to lock down ingress on a pod also silently blocks traffic you never intended to restrict, if you forgot to allow it explicitly.

Selecting by namespace, not just by pod

Policies commonly combine podSelector with namespaceSelector to express rules like “allow traffic from any pod in the monitoring namespace, regardless of its labels”:

ingress:
  - from:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: monitoring

This pattern is how clusters typically isolate tenants or environments that share the same physical cluster — each namespace gets policies that permit only specific cross-namespace traffic (metrics scraping, a shared ingress controller, a shared database) while denying everything else by default. It complements — but doesn’t replace — the boundary a namespace provides on its own, since namespaces alone don’t restrict network traffic without policies layered on top.

Egress rules and default-deny

Ingress rules get most of the attention, but egress rules are just as important for limiting blast radius. A pod that can freely make outbound connections can exfiltrate data or reach an attacker-controlled endpoint even if inbound traffic is locked down tightly. A common baseline for a namespace is a default-deny policy applied to every pod, followed by narrower policies that explicitly allow only the traffic each workload actually needs:

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

An empty podSelector: {} matches every pod in the namespace, and specifying no ingress or egress rules means nothing is allowed — the strictest possible starting point. From there, add allow rules incrementally as you discover what each workload legitimately needs to reach.

NetworkPolicy vs a service mesh

NetworkPolicies operate at layer 3/4 — IP addresses, ports, and protocols. They don’t understand HTTP paths, mutual TLS identity, or request-level routing. A service mesh operates at a higher layer and can enforce far more granular rules — this specific HTTP method to this specific path, encrypted end to end regardless of the underlying network. The two aren’t competitors: NetworkPolicies provide a coarse, cluster-native baseline (this pod can reach that pod, full stop), while a service mesh layers finer-grained, identity-aware control on top for teams that need it. Many clusters use NetworkPolicies alone and never need a mesh; some layer both.

It’s also worth noting NetworkPolicies require a compatible CNI plugin to actually enforce them — creating the resource with a CNI that doesn’t support NetworkPolicy enforcement will silently do nothing, which is worth verifying before relying on one as a security boundary. That’s a different concern from Kubernetes vs Docker more generally, but it’s a reminder that Kubernetes’ networking model is pluggable, and not every plugin implements every feature.

The takeaway

Kubernetes pods can reach each other freely by default, and NetworkPolicies are the primary way to change that — selecting pods by label and namespace, then explicitly allowing only the ingress and egress traffic each workload needs. The moment a pod is selected by any policy for a direction, everything not explicitly allowed in that direction is denied, which makes a namespace-wide default-deny policy plus targeted allow rules a much safer starting posture than adding restrictions piecemeal after the fact.

Chisato Chisato · · 4 min read

Kubernetes Init Containers Explained

Init containers run to completion before a pod's main containers start, making them the standard way to handle setup steps and startup ordering.

#Kubernetes #DevOps #Cloud
The Lycoris Team The Lycoris Team · · 4 min read

What Is Container Image Scanning?

Container image scanning checks a container's layers for known vulnerabilities and secrets before it ships. How it works and where to run it.

#DevOps #Security #Cloud