# Demonstration: Default-Deny, Before and After ## Before: everything can reach everything ``` $ kubectl run test-pod --image=busybox --rm -it -- wget -qO- --timeout=2 http://backend-svc ``` Any Pod in the namespace can reach `backend-svc`, regardless of what it is or who deployed it — this is the un-configured default the ROOT 07 lesson described, now made concrete from a security angle. ## Applying a default-deny policy ``` $ kubectl apply -f default-deny.yaml networkpolicy.networking.k8s.io/default-deny created ``` ```yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: ["Ingress"] ``` ## After: the same request, now blocked ``` $ kubectl run test-pod --image=busybox --rm -it -- wget -qO- --timeout=2 http://backend-svc wget: download timed out ``` No error naming a permission (that's RBAC's job, a different layer) — just a timeout, because the packets are being dropped at the network layer before they ever reach the Pod. This is a DIFFERENT failure signature than an RBAC denial, worth being able to tell apart: RBAC denials are explicit and immediate; NetworkPolicy denials look like the destination is simply unreachable. ## Explicitly allowing only what's needed ```yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-frontend-to-backend spec: podSelector: matchLabels: { app: backend } ingress: - from: - podSelector: matchLabels: { app: frontend } ``` ``` $ kubectl run frontend-test --labels="app=frontend" --image=busybox --rm -it -- wget -qO- --timeout=2 http://backend-svc $ kubectl run other-test --labels="app=other" --image=busybox --rm -it -- wget -qO- --timeout=2 http://backend-svc wget: download timed out ``` Same destination, same request — the ONLY difference is the caller's label. This is least-privilege network access made concrete: reachability now reflects an explicit decision, not an accident of both Pods existing in the same cluster. ## Instructor Notes **Demo script:** Run all three states live if a real cluster is available — the timeout (not an error) for the denied case is worth calling out explicitly, since it looks identical to a genuinely broken/unreachable service from the caller's perspective. **Approximate timing:** 8-10 minutes live; 5-7 minutes self-paced. **Common misconception to preempt:** students sometimes expect a NetworkPolicy denial to produce a clear "forbidden" error like RBAC does. It doesn't — reinforce that a NetworkPolicy- caused timeout is genuinely hard to distinguish from an actual network/DNS problem without already suspecting NetworkPolicy, which is exactly why checking existing policies is a real diagnostic step worth knowing. **Optional extension:** ask how a student would distinguish "blocked by NetworkPolicy" from "the backend Pod is actually down" purely from the caller's side (answer: check the backend Pod's own status/logs directly — if it's healthy and Ready, but still unreachable from one caller and reachable from another with a different label, NetworkPolicy is the likely cause).