Right, let’s talk about the single most important concept in securing your Kubernetes cluster’s network: starting from a position of “absolutely nothing is allowed.” This isn’t just a good idea; it’s the only sane way to begin. You wouldn’t build a castle and just leave the drawbridge down with a welcome mat, would you? Default Deny All is that raised drawbridge. It’s the security baseline that says, “Until I explicitly say a pod can talk to something, it lives in solitary confinement.”

The moment you create a NetworkPolicy with the deny-all label, you flip the entire security model of your cluster’s CNI (Container Network Interface) from an allow-by-default free-for-all to a secure, deny-by-default posture. Any pod that doesn’t have a NetworkPolicy explicitly allowing traffic suddenly finds itself in digital lockdown. No incoming traffic. No outgoing traffic. It’s isolated. This feels draconian because it is, and that’s the point. You then carve out precise, surgical exceptions for the traffic that must happen.

The Anatomy of a Default Deny All Policy

Here’s what the magic spell looks itself. You’ll apply this to a namespace to batten down the hatches.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: your-critical-namespace
spec:
  podSelector: {} # This empty map is the key. It selects EVERY pod in the namespace.
  policyTypes:
  - Ingress
  - Egress

Let’s break down why this works. The podSelector: {} is the genius (or obvious, depending on your mood) part. An empty selector doesn’t mean “select nothing,” it means “select every single pod that exists in this namespace.” It’s a wildcard. The policyTypes: [Ingress, Egress] tells the CNI that this policy applies to both incoming and outgoing traffic. The result? Total communication blackout for every pod in the namespace.

The Immediate Aftermath: “Why Did My Pods Just Break?”

You apply this policy and suddenly, your monitoring alerts light up like a Christmas tree. Your application is broken. Congratulations, you’ve done it correctly! This is not a mistake; it’s a diagnostic tool. You’ve just discovered all the implicit traffic your application was relying on that you never explicitly defined. This is the entire purpose of the exercise. Now the real work begins: whitelisting the necessary traffic without creating a policy so loose it’s basically a sieve.

Carving Out Exceptions: Allowing DNS

The most common “oh crap” moment is when you realize you’ve just killed all DNS resolution (kube-dns, core-dns). Pods can’t egress to anything, including the DNS server in the kube-system namespace. Without DNS, most applications grind to a halt. So your first exception is almost always an egress rule to allow DNS on port 53.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: your-critical-namespace
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to: # Where are we allowed to egress to?
    - namespaceSelector: # Select namespaces that match this selector
        matchLabels:
          kubernetes.io/metadata.name: kube-system # The namespace where CoreDNS lives
      podSelector: # Select pods within that namespace that match this selector
        matchLabels:
          k8s-app: kube-dns # The label for the CoreDNS pods
    ports: # On what port?
    - protocol: UDP # DNS primarily uses UDP, but sometimes falls back to TCP
      port: 53
    - protocol: TCP
      port: 53

Notice we use a combination of namespaceSelector and podSelector to be incredibly specific. We’re not just allowing egress to any IP on port 53; we’re allowing it only to the pods labeled k8s-app: kube-dns in the kube-system namespace. This is the precision you should aim for.

Best Practices and Pitfalls

  1. Namespace Isolation: Apply your default deny policy per namespace. You rarely want to lock down kube-system itself with this, as it would break system components. Start with your application namespaces.
  2. Order of Operations: Apply the default-deny-all policy first. Then, apply your allow policies. The network policy controller evaluates them additively. A deny-all plus an allow results in the allow winning.
  3. The Label Gambit: Network policies rely heavily on pod labels. If your pods don’t have consistent, well-defined labels, you’re going to have a bad time. Your allow policies will literally not work. This is the most common “it’s not working!” issue I see.
  4. Testing is Non-Negotiable: After applying a policy, kubectl exec into a pod and try to curl another service. Then try to curl something external. Then try nslookup. Test both the connectivity you want and the connectivity you don’t want to ensure your rules are tight. It’s tedious. It’s also what prevents a breach.

Embrace the lockdown. The temporary pain of everything breaking is far better than the permanent pain of a compromised cluster. This is the foundation. Build your secure network on top of it.