Chapter 5. Kubernetes Network Policies

— Default-Deny (with Tests)

Prereqs

  • Your app is deployed in namespace ship, Service name app (adjust if different).
  • Your Minikube profile has a CNI that enforces NetworkPolicies (e.g., Cilium or Calico).

If you haven’t enabled one yet, run a CNI addon that supports NetworkPolicy. (Minikube supports popular CNIs; pick one available on your setup.)

1) Capture service info

export NS=ship
export SVC=app
# Replace with your service port if not 8080:
export PORT=8080

kubectl -n $NS get svc $SVC -o wide

2) Apply a namespace default-deny

Create infra/k8s/netpol-default-deny.yaml:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: ship
spec:
  podSelector: {}                   # all Pods in namespace
  policyTypes: ["Ingress","Egress"] # deny everything by default
mkdir -p artifacts/netpol-manifests
kubectl apply -f infra/k8s/netpol-default-deny.yaml | tee artifacts/netpol-manifests/apply.txt

3) Launch a test client and try to curl (should be blocked)

# A temporary debug pod without any special labels
kubectl -n $NS run netshoot --restart=Never --image=nicolaka/netshoot -it --rm -- \
  /bin/sh -lc "apk add --no-cache curl >/dev/null 2>&1 || true; \
               echo 'curling cluster service…'; \
               curl -sS --max-time 5 http://$SVC.$NS.svc.cluster.local:$PORT/healthz || echo 'BLOCKED'"

Save output:

kubectl -n $NS run netshoot --restart=Never --image=nicolaka/netshoot --command -- sleep 5 2>/dev/null || true
kubectl -n $NS delete pod netshoot 2>/dev/null || true

Append your curl attempt (stdout/stderr) to ./artifacts/netpol-test.txt:

echo -e "\n--- BLOCK attempt $(date) ---" >> artifacts/netpol-test.txt
# (paste the curl output from the interactive run here)

Expected: timeout or connection refused → blocked.

4) Allow traffic only from labeled clients to the app Pods

Label your app Pods (if not already):

kubectl -n $NS label deploy/$SVC app=$SVC --overwrite

Create infra/k8s/netpol-allow-app-from-labeled.yaml:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-app-from-labeled
  namespace: ship
spec:
  podSelector:
    matchLabels:
      app: app          # target: your app Pods (adjust label if needed)
  policyTypes: ["Ingress"]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              access: allowed
      ports:
        - protocol: TCP
          port: 8080    # adjust to your app containerPort/Service port

Apply it:

kubectl apply -f infra/k8s/netpol-allow-app-from-labeled.yaml \
  | tee -a artifacts/netpol-manifests/apply.txt

5) Test again (first blocked, then allowed)

Create an unlabeled client (still blocked):

kubectl -n $NS run np-client --restart=Never --image=nicolaka/netshoot -- \
  /bin/sh -lc "apk add --no-cache curl >/dev/null 2>&1 || true; \
               curl -sS --max-time 5 http://$SVC.$NS.svc.cluster.local:$PORT/healthz || echo BLOCKED" \
  | tee -a artifacts/netpol-test.txt
kubectl -n $NS delete pod np-client --now

Create an allowed client and label it:

kubectl -n $NS run np-allowed --restart=Never --image=nicolaka/netshoot -- /bin/sh -lc "sleep 3600" >/dev/null 2>&1 &
sleep 2
kubectl -n $NS label pod np-allowed access=allowed --overwrite
kubectl -n $NS exec np-allowed -- /bin/sh -lc \
  "apk add --no-cache curl >/dev/null 2>&1 || true; \
   curl -sS --max-time 5 http://$SVC.$NS.svc.cluster.local:$PORT/healthz" \
  | tee -a artifacts/netpol-test.txt
kubectl -n $NS delete pod np-allowed --now

Expected: first attempt BLOCKED, second attempt 200 OK.


Makefile helpers (optional)

netpol-apply:
	kubectl apply -f infra/k8s/netpol-default-deny.yaml
	kubectl apply -f infra/k8s/netpol-allow-app-from-labeled.yaml

netpol-test:
	@NS=ship SVC=app PORT=8080 bash -lc '\
	kubectl -n $$NS run np-client --restart=Never --image=nicolaka/netshoot -- /bin/sh -lc "apk add --no-cache curl >/dev/null 2>&1 || true; curl -sS --max-time 5 http://$$SVC.$$NS.svc.cluster.local:$$PORT/healthz || echo BLOCKED" | tee -a artifacts/netpol-test.txt; \
	kubectl -n $$NS delete pod np-client --now; \
	kubectl -n $$NS run np-allowed --restart=Never --image=nicolaka/netshoot -- /bin/sh -lc "sleep 3600" >/dev/null 2>&1 & sleep 2; \
	kubectl -n $$NS label pod np-allowed access=allowed --overwrite; \
	kubectl -n $$NS exec np-allowed -- /bin/sh -lc "apk add --no-cache curl >/dev/null 2>&1 || true; curl -sS --max-time 5 http://$$SVC.$$NS.svc.cluster.local:$$PORT/healthz" | tee -a artifacts/netpol-test.txt; \
	kubectl -n $$NS delete pod np-allowed --now; \
	echo "Wrote artifacts/netpol-test.txt"'

Checklist

  • Your Minikube profile has a CNI that enforces NetworkPolicy
  • default-deny applied for Ingress+Egress
  • Labeled allow-rule works (blocked → allowed)
  • artifacts/netpol-test.txt saved with both outcomes