Lab Guide: NetworkPolicies
Three exercises that build from default-deny to a fully templated Helm NetworkPolicy.
Prerequisites
A running Kubernetes cluster with a CNI that enforces NetworkPolicies (Calico, Cilium, or Weave). If using Minikube, start with minikube start --cni=calico. If using kind, install Calico after cluster creation.
Exercise 1 — Default-Deny and Selective Allow
In this exercise you will deploy two applications, lock down the namespace with a default-deny policy, and then create an allow rule to restore specific connectivity.
Step 1 — Create a test namespace and deploy two apps
# Create the namespace
kubectl create namespace netpol-lab
# Deploy a simple API server
kubectl create deployment api \
--image=hashicorp/http-echo \
--namespace=netpol-lab \
-- -text="Hello from API" -listen=:8080
kubectl expose deployment api \
--port=8080 --namespace=netpol-lab
# Deploy a frontend
kubectl create deployment frontend \
--image=busybox:1.36 \
--namespace=netpol-lab \
-- sleep 3600
kubectl label deployment frontend app=frontend -n netpol-lab --overwrite
Step 2 — Verify connectivity (before any policy)
# Wait for pods to be ready
kubectl wait --for=condition=ready pod -l app=api -n netpol-lab --timeout=60s
kubectl wait --for=condition=ready pod -l app=frontend -n netpol-lab --timeout=60s
# Test: frontend can reach api
kubectl exec -n netpol-lab deploy/frontend -- \
wget -qO- --timeout=3 http://api:8080
# Expected output: "Hello from API"
Step 3 — Apply a default-deny ingress policy
Create a file called default-deny.yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: netpol-lab
spec:
podSelector: {}
policyTypes:
- Ingress
kubectl apply -f default-deny.yaml
Step 4 — Verify connectivity is now blocked
kubectl exec -n netpol-lab deploy/frontend -- \
wget -qO- --timeout=3 http://api:8080
# Expected: timeout / connection refused
Step 5 — Create a policy to allow frontend to reach api
Create allow-frontend.yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: netpol-lab
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
kubectl apply -f allow-frontend.yaml
# Test again -- should work now
kubectl exec -n netpol-lab deploy/frontend -- \
wget -qO- --timeout=3 http://api:8080
# Expected output: "Hello from API"
Step 6 — Confirm other pods are still blocked
# Run a pod without the frontend label
kubectl run rogue --rm -it \
--image=busybox:1.36 \
--restart=Never -n netpol-lab -- \
wget -qO- --timeout=3 http://api:8080
# Expected: timeout (rogue pod is not labeled app=frontend)
Checkpoint
You have a default-deny ingress policy in place. Only pods labeled app: frontend can reach the API on port 8080. All other ingress is blocked.
Exercise 2 — Egress Lockdown with DNS Allow
Lock down egress traffic and ensure DNS still works.
Step 1 — Apply a default-deny egress policy
Create deny-egress.yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: netpol-lab
spec:
podSelector: {}
policyTypes:
- Egress
kubectl apply -f deny-egress.yaml
# Test: frontend cannot resolve or reach anything
kubectl exec -n netpol-lab deploy/frontend -- \
wget -qO- --timeout=3 http://api:8080
# Expected: DNS resolution failure or timeout
Step 2 — Allow DNS and specific egress
Create allow-egress.yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-egress
namespace: netpol-lab
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Egress
egress:
# Allow DNS
- ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# Allow traffic to the API
- to:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 8080
kubectl apply -f allow-egress.yaml
# Test: frontend can reach api again
kubectl exec -n netpol-lab deploy/frontend -- \
wget -qO- --timeout=3 http://api:8080
# Expected: "Hello from API"
# Test: frontend cannot reach external sites
kubectl exec -n netpol-lab deploy/frontend -- \
wget -qO- --timeout=3 http://example.com
# Expected: timeout
Step 3 — Inspect all policies
kubectl get networkpolicy -n netpol-lab
kubectl describe networkpolicy frontend-egress -n netpol-lab
Checkpoint
The frontend pod can resolve DNS and reach the API, but cannot make any other outbound connections.
Exercise 3 — Helm-Templated NetworkPolicy
Create a Helm chart that includes a conditional, configurable NetworkPolicy.
Step 1 — Scaffold the chart
helm create netpol-app
cd netpol-app
Step 2 — Add a NetworkPolicy template
Create templates/networkpolicy.yaml:
{{- if .Values.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "netpol-app.fullname" . }}
labels:
{{- include "netpol-app.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "netpol-app.selectorLabels" . | nindent 6 }}
policyTypes:
{{- range .Values.networkPolicy.policyTypes }}
- {{ . }}
{{- end }}
{{- with .Values.networkPolicy.ingress }}
ingress:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.networkPolicy.egress }}
egress:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
Step 3 — Add default values
Add the following to the end of values.yaml:
networkPolicy:
enabled: false
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 80
egress:
- ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Step 4 — Test with helm template
# Default: networkPolicy.enabled=false, no output expected
helm template myrelease . | grep -A 30 "NetworkPolicy"
# Expected: no output
# Override to enable:
helm template myrelease . \
--set networkPolicy.enabled=true | grep -A 30 "NetworkPolicy"
# Expected: full NetworkPolicy manifest
Step 5 — Install and verify
# Install with policy enabled
helm install myrelease . \
--namespace netpol-lab \
--set networkPolicy.enabled=true
# Check the policy was created
kubectl get networkpolicy -n netpol-lab
# Describe it
kubectl describe networkpolicy myrelease-netpol-app -n netpol-lab
Step 6 — Clean up
helm uninstall myrelease -n netpol-lab
kubectl delete namespace netpol-lab
Checkpoint
You have a Helm chart that conditionally creates a NetworkPolicy based on values. The policy is fully configurable via values.yaml or --set overrides.