Chapter 06: Network Policies (Production Isolation)
Learning Objectives
By the end of this chapter, you will be able to:
- Implement a default-deny NetworkPolicy for a namespace
- Diagnose blocked traffic using kubectl and network policy selectors
- Evaluate whether an allow rule follows least-privilege principles
- Construct a rollback plan for a failed network policy deployment
Start with the video for the concept overview, then work through each lesson section.
By default, every Pod in Kubernetes can talk to every other Pod. This is a massive security risk. In this chapter, we implement a Zero-Trust network model where all traffic is blocked unless explicitly permitted.
1. The Problem: Lateral Movement
A debug pod in the develop namespace is compromised. Without network isolation, an attacker can move laterally to sensitive internal services or production databases. A flat network makes every compromise a potential cluster-wide breach.
2. The Concept: Default Deny & Explicit Allow
We move from “Allow Everything” to “Block Everything by Default.”
- Default Deny: Drop all incoming and outgoing traffic for every Pod.
- Explicit Allow: Open only the specific ports and paths required for the service to function (e.g., DNS, Ingress, Backend API).
3. The Code: The Policy Baseline
Our sre/ repo contains a set of reusable policies that enforce isolation. The allow-backend-ingress.yaml file is our contract for secure service-to-service communication.
Backend allow policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-ingress
spec:
podSelector:
matchExpressions:
- key: app
operator: In
values: [backend, backend-primary]
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchExpressions:
- key: app
operator: In
values: [frontend, frontend-primary]
ports:
- protocol: TCP
port: 8080
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik
ports:
- protocol: TCP
port: 8080
4. The Guardrail: DNS & Infrastructure Paths
The biggest mistake in applying isolation is “going dark” by blocking DNS. We ensure that every workload inherits a baseline policy that allows name resolution and ingress traffic from the cluster’s gateway.
DNS allow policy
Show the DNS allow policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
app.kubernetes.io/name: coredns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
5. Verification: Did I Get It?
Verify your isolation by trying to break the rules:
# Exec into a pod and try to reach an un-labeled or cross-namespace target
kubectl -n develop exec -it deploy/frontend -- curl -I http://production-db:5432
Expected Output: The connection should time out, proving the default-deny is active.