Network Policies
By default, every Pod in a Kubernetes cluster can reach every other Pod, a flat, fully open network, which is convenient for getting started but is a serious liability in production multi-tenant or compliance-sensitive environments. A NetworkPolicy is a namespaced resource that uses a label selector to pick a set of Pods and then declares an allow-list of permitted ingress and/or egress traffic; critically, NetworkPolicies are purely additive and default-deny once any policy selects a Pod, meaning the moment one policy targets a Pod for ingress, all ingress traffic not explicitly allowed by some policy is dropped.
Cricket analogy: It's like an open-access practice ground where any local player can walk in and bowl in the nets by default, until the academy posts a sign-in sheet restricting access to only registered players for a specific net session, at which point anyone not on that list is turned away from that net.
Ingress and Egress Rule Anatomy
A NetworkPolicy's podSelector picks the target Pods, and its policyTypes list, Ingress, Egress, or both, determines which direction is restricted; each rule under ingress or egress combines from/to peer selectors, which can be podSelector (Pods by label, scoped to the same namespace unless combined with namespaceSelector), namespaceSelector (entire namespaces by label), or ipBlock (CIDR ranges, typically for traffic to/from outside the cluster), with an optional ports list restricting protocol and port. An empty ingress: [] with no rules means default-deny-all-ingress for the selected Pods, while omitting ingress from policyTypes entirely means ingress is left unrestricted by this particular policy, a distinction that trips up almost everyone the first time.
Cricket analogy: It's like a stadium's VIP box having a guest list where you specify allowed individuals by name, allowed entire delegations by team badge, or an allowed range of seat numbers for corporate blocks, and leaving the guest list completely blank means nobody at all gets in, a subtly different rule from not checking the guest list in the first place.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-from-frontend
namespace: prod
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: gateway
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: data
ports:
- protocol: TCP
port: 5432
- to:
- ipBlock:
cidr: 0.0.0.0/0
except: ["169.254.169.254/32"] # block cloud metadata endpoint
ports:
- protocol: TCP
port: 443
Default-Deny Baselines
A common production pattern is to apply a namespace-wide default-deny policy first, one with an empty podSelector: {} matching every Pod and policyTypes: [Ingress, Egress] with no rules, then layer on specific allow policies for each legitimate communication path, so nothing is reachable except what's been explicitly justified. This whitelist-first posture is far safer than trying to enumerate every bad actor after the fact, but it also means that during incident response or a new deployment, forgetting an egress rule for DNS (port 53 to kube-system) is one of the most common ways teams accidentally break an entire namespace.
Cricket analogy: It's like a ground curator locking every gate around the stadium first, then issuing individual keys only to groundstaff, security, and ticketed sections one by one, rather than leaving every gate open and trying to eject unauthorized people after they've already wandered onto the pitch.
A default-deny Egress policy silently breaks DNS resolution unless you explicitly allow egress to kube-dns/CoreDNS on UDP and TCP port 53 in kube-system; this is the single most common self-inflicted outage when teams roll out default-deny for the first time, because Pods that can't resolve DNS also can't reach Services by name, masking the real root cause as a mysterious application timeout.
CNI Support and Enforcement Boundaries
NetworkPolicy is a Kubernetes API specification, not an enforcement mechanism, the API server will happily accept and store a NetworkPolicy object even if no component in the cluster is capable of enforcing it, so if your CNI plugin, Flannel in its default configuration, for instance, doesn't implement the NetworkPolicy controller, every policy you write is silently ignored while looking perfectly valid in kubectl get. Calico, Cilium, and Weave Net all implement enforcement, and Cilium in particular extends the base API with CiliumNetworkPolicy for L7-aware rules, like restricting an HTTP path or a specific gRPC method, that plain Kubernetes NetworkPolicy cannot express since it only understands L3/L4, IPs, ports, and protocols.
Cricket analogy: It's like a league officially publishing a strict anti-doping rulebook that every team receives, but if the specific host board never actually contracts a testing lab to enforce it at a given tournament, the rules exist on paper while zero athletes are ever actually tested that season.
Always verify enforcement with a real test, deploy two Pods, apply a deny policy between them, and confirm connectivity actually fails with kubectl exec and curl or nc, rather than trusting that kubectl get networkpolicy returning your object means anything is actually being blocked.
- By default, all Pods in a cluster can reach all other Pods; NetworkPolicy is required to restrict this.
- NetworkPolicies are additive and default-deny-once-selected: the moment any policy selects a Pod for Ingress or Egress, unlisted traffic in that direction is dropped.
- Peers are matched via podSelector, namespaceSelector, or ipBlock, optionally combined with a ports restriction.
- A namespace-wide default-deny baseline plus specific allow policies is the recommended production pattern.
- Forgetting to allow egress to CoreDNS on port 53 is the most common cause of self-inflicted outages after enabling default-deny.
- NetworkPolicy is only an API spec; it requires a CNI plugin (Calico, Cilium, Weave Net) that implements enforcement, otherwise policies are silently ignored.
- Cilium's CiliumNetworkPolicy CRD extends beyond L3/L4 to L7-aware rules like HTTP paths or gRPC methods, which plain NetworkPolicy cannot express.
Practice what you learned
1. What is the default network connectivity between Pods in a Kubernetes cluster with no NetworkPolicies applied?
2. What happens the moment a NetworkPolicy's podSelector selects a Pod for Ingress?
3. Why might a NetworkPolicy appear correctly created via kubectl get but have no actual effect on traffic?
4. What is a common outage cause when rolling out a namespace-wide default-deny Egress policy for the first time?
5. What capability does CiliumNetworkPolicy add beyond the standard Kubernetes NetworkPolicy API?
Was this page helpful?
You May Also Like
The Kubernetes Networking Model
How Kubernetes guarantees flat, NAT-free Pod-to-Pod connectivity and how CNI plugins and kube-proxy implement that contract.
Services In Depth
How Kubernetes Services provide stable virtual IPs over dynamic Pod sets, covering all four Service types, EndpointSlices, and headless Services.
Service Mesh Basics with Istio
How Istio's sidecar-based service mesh delivers mutual TLS, traffic shaping, and observability transparently, covering its control/data plane split and key resources.