DNS and a Default Deny Egress Policy

Why does a Pod stop resolving names the moment it gets an egress policy? Once a NetworkPolicy selects a Pod for Egress, the Pod may open only the connections an egress rule allows, and a lookup to the cluster DNS Service is not one of them until a rule says so, so name resolution fails while the addresses the policy allows still connect. The rule that repairs it selects the DNS Pods by namespace and Pod labels, and it lists port 53 for both UDP and TCP.

Play the animation 6 steps, animated, best on a wide screen

DNS and a Default Deny Egress Policy diagram: What a NetworkPolicy does to name resolution

DNS and a Default Deny Egress Policy, step by step

  1. No NetworkPolicy selects any of these Pods, so Pod web is non-isolated for egress and no egress rule limits it. The app looks up db.shop, the query leaves on UDP port 53 for the kube-dns Service address in resolv.conf, and the CoreDNS Pods behind that Service answer with the address of Pod db-0.

    Play from step 1
  2. One NetworkPolicy selects app=web for Egress, and its only rule allows app=db on port 5432. Selecting the Pod is what raises the boundary: from here the only connections out of web are the ones an egress rule allows. The lookup is not one of them, so the query dies on the way out and the name never resolves.

    Play from step 2
  3. Nothing else changed, which is what makes this hard to read from inside the Pod. A connection to the address of Pod db-0 on 5432 matches the one rule and goes straight out, while the same lookup dies at the boundary. The address still works and the name does not, so the workload looks half broken rather than blocked.

    Play from step 3
  4. A second NetworkPolicy allows egress to the cluster DNS Service. Its one entry names the namespace by the kubernetes.io/metadata.name label and the Pods behind that Service by k8s-app=kube-dns, on port 53 with no protocol. Protocol defaults to TCP, so the door opens for TCP alone and the UDP query is still refused.

    Play from step 4
  5. With 53/UDP and 53/TCP both listed the query passes the boundary, the CoreDNS Pods answer, and the reply comes back without a rule of its own, because replies on an allowed connection are allowed implicitly. Policies are additive, so this rule adds to the database rule rather than replacing it.

    Play from step 5
  6. The TCP half of that rule is not decoration. An answer too large for a UDP reply comes back with the truncation flag set, and a resolver that retries over TCP asks the same question again on port 53 TCP. That retry is a fresh connection out of Pod web, so without the TCP port in the rule the large answer never arrives.

    Play from step 6

Sources