Master Kubernetes NetworkPolicy: Secure Pod Communication with Real‑World Examples
This article explains Kubernetes NetworkPolicy, covering its purpose, how pod and namespace selectors work, required fields, policy types, and detailed YAML examples, followed by practical scenarios and step‑by‑step commands for deploying and testing network policies in a cluster.
Network Policy Overview
With the rise of micro‑service architectures and serverless frameworks, the demand for inter‑module network calls has grown dramatically. Kubernetes introduced NetworkPolicy in version 1.3 to provide application‑centric, policy‑based network control that isolates workloads and reduces the attack surface.
Pod communication can be verified through three combinations: allowed Pods, allowed namespaces, and IP CIDR blocks.
Version Changes
Brief Introduction
Related Explanation
By default, Pods are non‑isolated and accept any traffic.
When a Pod is selected by a NetworkPolicy, it becomes isolated. Any Pod in the same namespace that is not selected continues to accept all traffic.
Network policies do not conflict; a Pod selected by multiple policies is subject to the union of all inbound (Ingress) and outbound (Egress) rules.
When using NetworkPolicy, the network plugin must support it, such as Calico, Romana, Weave Net, or Trireme. "Egress" refers to outbound traffic, "Ingress" to inbound traffic.
Struct Definition
<code>staging/src/k8s.io/api/networking/v1/types.go</code>Below is a sample NetworkPolicy; see the official struct documentation for full details.
<code>apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: network-policy-sample
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978</code>Required fields: apiVersion, kind, and metadata (name, namespace).
spec contains all information needed to define a policy within a namespace.
podSelector selects the Pods the policy applies to; an empty selector matches all Pods in the namespace.
policyTypes lists Ingress, Egress, or both. If omitted, Ingress is assumed; Egress is added when egress rules are present.
ingress defines a whitelist of allowed inbound traffic, matching both "from" and "ports".
egress defines a whitelist of allowed outbound traffic, matching "to" and "ports".
Isolate Pods with label
role=dbin the
defaultnamespace.
Egress restriction: allow Pods with label
role=frontendin
default, Pods in namespaces labeled
project=myproject, and IP ranges
172.17.0.0/16except
172.17.1.0/24to reach port
6379/TCPon the selected Pods.
Ingress restriction: allow any Pod in namespaces with label
role=dbto reach port
5978/TCPon CIDR
10.0.0.0/24.
Simple Example (Calico)
1) Configure kubelet to use the CNI network plugin (usually pre‑configured).
<code>kubelet --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin ...</code>2) Install the Calico network plugin.
<code># Note: adjust CIDR to match the cluster's pod‑network‑cidr (default 192.168.0.0/16)
# Installation for clusters with fewer than 50 nodes
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml</code>3) Deploy an application (nginx).
<code>$ kubectl create deployment nginx --image=nginx
deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed</code>Test the network:
<code>$ kubectl get svc,pod
... (output omitted for brevity)
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.233.27.142:80)
remote file exists
/ #</code>Application Scenarios
General Scenarios
a) Deny access to a specific service.
<code>$ kubectl run web --image=nginx --labels app=web --expose --port 80
# Without a policy, the service is reachable
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
/ # wget -qO- http://web
<!DOCTYPE html>
<html>...</html></code>Create a deny‑all policy:
<code># cat web-deny-all.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-deny-all
spec:
podSelector:
matchLabels:
app: web
ingress: []
$ kubectl apply -f web-deny-all.yaml
networkpolicy "web-deny-all" created</code>Test that the service is now blocked:
<code>$ kubectl run busybox --rm -ti --image=busybox /bin/sh
/ # wget -qO- --timeout=2 http://web
wget: download timed out</code>Namespace Restrictions
a) Block non‑whitelisted traffic in a namespace.
<code># cat default-deny-all.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: default-deny-all
namespace: default
spec:
podSelector: {}
ingress: []
$ kubectl apply -f default-deny-all.yaml
networkpolicy "default-deny-all" created</code>b) Block traffic from other namespaces.
<code>$ kubectl create namespace secondary
$ kubectl run web --namespace secondary --image=nginx --labels=app=web --expose --port 80</code> <code># cat web-deny-other-namespaces.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
namespace: secondary
name: web-deny-other-namespaces
spec:
podSelector:
matchLabels:
ingress:
- from:
- podSelector: {}
$ kubectl apply -f web-deny-other-namespaces.yaml</code>Testing shows that pods in the default namespace cannot reach the service, while pods in
secondarycan.
Allow All Namespaces
<code># cat web-allow-all-namespaces.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
namespace: default
name: web-allow-all-namespaces
spec:
podSelector:
matchLabels:
app: web
ingress:
- from:
- namespaceSelector: {}
$ kubectl apply -f web-allow-all-namespaces.yaml</code>This policy permits traffic from any namespace to Pods labeled
app=web.
Restrict Access to Specific Namespaces
<code># cat web-allow-prod.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-allow-prod
spec:
podSelector:
matchLabels:
app: web
ingress:
- from:
- namespaceSelector:
matchLabels:
purpose: production
$ kubectl apply -f web-allow-prod.yaml</code>Only namespaces labeled
purpose=productioncan access the
webservice.
Allow Specific Pods Across Namespaces
<code># cat web-allow-all-ns-monitoring.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-allow-all-ns-monitoring
namespace: default
spec:
podSelector:
matchLabels:
app: web
ingress:
- from:
- namespaceSelector:
matchLabels:
team: operations
podSelector:
matchLabels:
type: monitoring
$ kubectl apply -f web-allow-all-ns-monitoring.yaml</code>Pods with label
type=monitoringin namespaces labeled
team=operationsare allowed to reach the
webservice.
Efficient Ops
This public account is maintained by Xiaotianguo and friends, regularly publishing widely-read original technical articles. We focus on operations transformation and accompany you throughout your operations career, growing together happily.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.