Network Policies¶
NetworkPolicy controls pod-to-pod traffic at Layer 3 and Layer 4.
By default, many clusters allow broad lateral traffic. NetworkPolicy lets you move to explicit allow rules.
Prerequisite¶
Your CNI must implement NetworkPolicy. If it does not, policy objects may apply successfully but have no effect.
The evaluation model (read this first)¶
NetworkPolicy has no deny rules, no priorities, and no ordering. The entire model reduces to two rules:
- A pod not selected by any policy accepts everything. Isolation is opt-in, per direction: a pod becomes ingress-isolated the moment any policy with
policyTypes: [Ingress]selects it (and likewise for egress). - Once isolated, traffic is allowed if any policy allows it. Policies are purely additive -- they union together. You can never write a policy that takes access away from what another policy grants; you can only avoid granting it.
This is why default-deny works the way it does: an empty podSelector: {} policy selects every pod in the namespace (making them all isolated) while allowing nothing. Every subsequent policy then punches specific holes.
One syntax trap worth burning into memory: in a from/to list, separate list items are OR, but namespaceSelector and podSelector combined in a single item are AND. A stray - turns "pods with this label in that namespace" into "all pods in that namespace, plus pods with this label anywhere" -- a real security bug that passes review easily.
Trust model¶
graph LR
subgraph payments namespace
API[api pod]
DB[db pod]
end
subgraph monitoring namespace
PROM[prometheus pod]
end
subgraph frontend namespace
WEB[web pod]
end
WEB -->|allowed: 8080| API
PROM -->|allowed: 9090| API
API -->|allowed: 5432| DB
WEB -. blocked .-> DB
Define your trust boundaries per namespace first. Then build allow rules to match.
Default-deny foundation¶
Start sensitive namespaces with default-deny, then add explicit allow rules.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: payments
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Allow app-to-app ingress¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-web-to-api
namespace: payments
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
Cross-namespace allow¶
Use namespaceSelector when source pods live in another namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring-scrape
namespace: payments
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9090
Egress and DNS¶
When egress restrictions are enabled, allow DNS explicitly or service discovery will break -- this is the most common self-inflicted outage when adopting egress policies (see DNS and Service Discovery).
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: payments
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
IP block rules¶
Use ipBlock to control traffic to or from external IP ranges. This is useful for allowing access from a corporate network or blocking cloud metadata endpoints.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-external-api
namespace: payments
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 203.0.113.0/24
except:
- 203.0.113.10/32
ports:
- protocol: TCP
port: 443
except lets you exclude specific IPs within a broader allowed range.
Troubleshooting¶
kubectl get netpol -A
kubectl describe netpol allow-web-to-api -n payments
kubectl get pods -A --show-labels
Also validate policy behavior with test pods and explicit connectivity checks (curl, nc, or purpose-built policy tests).
Certification notes¶
- NetworkPolicy is core CKS material and appears on CKA. Practice writing default-deny plus one allow rule from memory -- the YAML shape (
policyTypes,fromvsingress) is easy to fumble under time pressure. - Remember: policies select the pods they protect (
spec.podSelector), not the traffic source. Exam questions exploit this reversal. - Know the AND/OR distinction in
fromitems -- it's a favorite trick.
Design guidance¶
- define namespace trust boundaries first
- apply default-deny early in new namespaces
- make allow rules specific by label and port
- keep policy manifests version-controlled and reviewed
Summary¶
NetworkPolicy is a core Kubernetes security control for lateral movement reduction. It should be standard in production clusters, especially in multi-team environments.