CertGrid CertGrid
Hands-on Lab·Kubernetes and Cloud Native Security Associate

NetworkPolicy Default Deny and DNS

Isolation techniques is a Domain 1 competency and NetworkPolicy is the one you will be asked about. This guide applies a default-deny to a namespace and then watches DNS stop working, because egress means all egress including port 53.

Cloud Native Security Guide 8 of 42 Intermediate

Written against the versions above. Enforced by Cilium 1.18.1. The manifest is the generic `networking.k8s.io/v1` kind, which is what KCSA asks about and what works under any CNI that implements policy - the behaviour shown here is not Cilium-specific.

The cka5001 cluster: one control plane and 3 schedulable workers, on Cilium.
Server NameIP AddressOSRolesCPURAMHDD
CKA5001192.168.0.41Ubuntu 26.04 LTSControl Plane Node (tainted NoSchedule)2 Core4 GB50 GB
CKA5001-NODE01192.168.0.42Ubuntu 26.04 LTSWorker Node2 Core4 GB50 GB
CKA5001-NODE02192.168.0.43Ubuntu 26.04 LTSWorker Node2 Core4 GB50 GB
CKA5001-NODE03192.168.0.44Ubuntu 26.04 LTSWorker Node2 Core4 GB50 GB

Before you start

  1. Before: a Pod that can resolve and reach things

    Establish the baseline, so the change is attributable.

    bash Example session
    kubectl -n kcsa-open exec plain -- nslookup kubernetes.default.svc.cluster.local 2>&1 | tail -2; echo "--- DNS works before the policy"  --- DNS works before the policy

    Expected resultThe lookup returns without error - the trailing lines are blank, but the next step's failure is unambiguous by contrast.

    Success conditionYou have a before state.

  2. Seven lines that deny everything

    An empty podSelector, and both policy types.

    bash Example session
    printf 'apiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  name: default-deny-all\nspec:\n  podSelector: {}\n  policyTypes: ["Ingress","Egress"]\n' | kubectl -n kcsa-open apply -f - 2>&1 | tail -1networkpolicy.networking.k8s.io/default-deny-all createdkubectl -n kcsa-open get networkpolicy default-deny-all -o custom-columns='NAME:.metadata.name,TYPES:.spec.policyTypes'; echo "--- an EMPTY podSelector selects every Pod in the namespace"NAME               TYPESdefault-deny-all   [Ingress Egress]--- an EMPTY podSelector selects every Pod in the namespace

    Expected resultnetworkpolicy.networking.k8s.io/default-deny-all created, then TYPES [Ingress Egress].

    Success conditionYou can write the policy every namespace should probably start with.

  3. After: DNS is gone, and so is everything else

    The same lookup that worked two steps ago.

    bash Example session
    kubectl -n kcsa-open exec plain -- nslookup kubernetes.default.svc.cluster.local 2>&1 | tail -3; echo "--- DNS is egress too, and default-deny took it with everything else";; connection timed out; no servers could be reached command terminated with exit code 1--- DNS is egress too, and default-deny took it with everything elsekubectl -n kcsa-open exec plain -- sh -c 'wget -q -O- --timeout=4 https://kubernetes.default.svc/version 2>&1 | head -1'; echo "--- and the apiserver is gone as well"wget: bad address 'kubernetes.default.svc'--- and the apiserver is gone as well

    Expected result;; connection timed out; no servers could be reached, then wget: bad address 'kubernetes.default.svc'.

    Success conditionYou know the first thing a default-deny breaks.

Troubleshooting

Official sources