Network Policies
By default every pod in a Kubernetes namespace can reach every other pod. NetworkPolicy is the firewall that fixes that, expressed as Kubernetes objects so the rules ship with the workload. They are CNI-implemented (Calico, Cilium, etc.) — confirm your cluster has one installed, otherwise the policies are silently ignored.
Default-deny, then explicitly allow what is needed
EXAMPLE
# 1) Default-deny ALL ingress in this namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: default-deny-ingress, namespace: shop }
spec:
podSelector: {} # selects every pod in the namespace
policyTypes: [Ingress]
---
# 2) Allow the API pods to be reached only from the web pods, on port 8080.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: api-from-web, namespace: shop }
spec:
podSelector:
matchLabels: { app: api }
policyTypes: [Ingress]
ingress:
- from:
- podSelector:
matchLabels: { app: web }
ports:
- protocol: TCP
port: 8080
---
# 3) Allow the DB pods to be reached only from API, AND only from this namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: db-from-api, namespace: shop }
spec:
podSelector:
matchLabels: { app: postgres }
policyTypes: [Ingress, Egress]
ingress:
- from:
- namespaceSelector:
matchLabels: { kubernetes.io/metadata.name: shop }
podSelector:
matchLabels: { app: api }
ports: [{ protocol: TCP, port: 5432 }]
egress:
- to: [] # nothing — DB pods make no outbound calls
ports: []
---
# 4) Egress allow-list for the API: only DNS, the DB, and our payment gateway.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: api-egress, namespace: shop }
spec:
podSelector:
matchLabels: { app: api }
policyTypes: [Egress]
egress:
- to:
- namespaceSelector: { matchLabels: { kubernetes.io/metadata.name: kube-system } }
podSelector: { matchLabels: { k8s-app: kube-dns } }
ports: [{ protocol: UDP, port: 53 }, { protocol: TCP, port: 53 }]
- to:
- podSelector: { matchLabels: { app: postgres } }
ports: [{ protocol: TCP, port: 5432 }]
- to:
- ipBlock: { cidr: 0.0.0.0/0, except: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16] }
ports: [{ protocol: TCP, port: 443 }]
# Verify a rule actually denies what you think it does:
kubectl run probe --rm -it --image=alpine -n shop -- sh -c 'apk add curl; curl http://api:8080'
Why it matters
Always start with a default-deny policy, then layer narrow allows on top. The opposite order — adding deny rules to plug holes — leaves the holes open between deploys, and forgotten allow-all rules tend to outlive the team member who wrote them.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…