🎤Speaking at KubeCon EU 2026Lessons Learned Orchestrating Multi-Tenant GPUs on OpenShift AIView Session
Networking beginner ⏱ 10 minutes K8s 1.25+

NetworkPolicy: Default Deny All Traffic

Implement a zero-trust network security model in Kubernetes by creating a default deny-all NetworkPolicy. Learn how to block all ingress and egress traffic and selectively allow what you need.

By Luca Berton

💡 Quick Answer: Create a zero-trust baseline with podSelector: {} (selects all pods) and both policyTypes: [Ingress, Egress] with no rules—this blocks all traffic. Then add specific allow policies. Always include a DNS egress allow policy after default-deny.

Key config: Empty podSelector + empty rules = deny all for that direction.

Gotcha: After default-deny, pods can’t resolve DNS—immediately add: egress: [{to: [{namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: kube-system}}}], ports: [{port: 53, protocol: UDP}]}].

The Problem

By default, Kubernetes allows all pods to communicate with each other without restrictions. This violates the principle of least privilege and can be a security risk.

The Solution

Create a default deny-all NetworkPolicy in each namespace, then explicitly allow only the traffic you need.

Step 1: Verify NetworkPolicy Support

First, check if your cluster’s CNI supports NetworkPolicies:

# Check the CNI being used
kubectl get pods -n kube-system | grep -E "calico|cilium|weave"

Note: Some CNIs like Flannel do NOT support NetworkPolicies. Consider using Calico or Cilium.

Step 2: Create Default Deny-All Policy

This policy denies all ingress AND egress traffic for pods in the namespace:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: my-namespace
spec:
  podSelector: {}  # Applies to all pods in namespace
  policyTypes:
    - Ingress
    - Egress

Apply it:

kubectl apply -f default-deny-all.yaml

Step 3: Allow Specific Traffic

Now create policies to allow only necessary traffic.

Allow DNS (Required)

Pods need to reach CoreDNS for name resolution:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: my-namespace
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

Allow Traffic Between Specific Pods

Allow frontend pods to reach backend pods:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: my-namespace
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080

Allow External Egress

Allow pods to reach external services:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-egress
  namespace: my-namespace
spec:
  podSelector:
    matchLabels:
      app: api-gateway
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8
              - 172.16.0.0/12
              - 192.168.0.0/16
      ports:
        - protocol: TCP
          port: 443

Testing NetworkPolicies

Deploy Test Pods

# Create a test namespace
kubectl create namespace netpol-test

# Deploy test pods
kubectl run client --image=busybox -n netpol-test -- sleep 3600
kubectl run server --image=nginx -n netpol-test
kubectl expose pod server --port=80 -n netpol-test

Test Connectivity Before Policy

kubectl exec -n netpol-test client -- wget -qO- --timeout=2 http://server
# Should return nginx welcome page

Apply Deny-All and Test Again

# Apply default deny
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: netpol-test
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
EOF

# Test again - should timeout
kubectl exec -n netpol-test client -- wget -qO- --timeout=2 http://server
# wget: download timed out

Common Issues

Pods can’t resolve DNS

You forgot to allow DNS egress. Apply the “allow-dns” policy.

Policy not being enforced

Check if your CNI supports NetworkPolicies:

# Create a test policy and verify
kubectl describe networkpolicy default-deny-all -n my-namespace

Need to allow traffic from Ingress Controller

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-controller
  namespace: my-namespace
spec:
  podSelector:
    matchLabels:
      app: my-web-app
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx

Complete Example

Here’s a complete setup for a typical 3-tier application:

---
# 1. Default deny all
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: my-app
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
---
# 2. Allow DNS for all pods
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: my-app
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
---
# 3. Allow ingress to frontend from ingress controller
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-to-frontend
  namespace: my-app
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
---
# 4. Allow frontend to backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: my-app
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              tier: frontend
      ports:
        - protocol: TCP
          port: 8080
---
# 5. Allow backend to database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend-to-database
  namespace: my-app
spec:
  podSelector:
    matchLabels:
      tier: database
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              tier: backend
      ports:
        - protocol: TCP
          port: 5432

Summary

You’ve learned how to:

  1. Create a default deny-all NetworkPolicy
  2. Allow DNS resolution for pods
  3. Allow specific pod-to-pod communication
  4. Test NetworkPolicy enforcement

Always start with deny-all and add allow rules incrementally.

References


📘 Go Further with Kubernetes Recipes

Love this recipe? There’s so much more! This is just one of 100+ hands-on recipes in our comprehensive Kubernetes Recipes book.

Inside the book, you’ll master:

  • ✅ Production-ready deployment strategies
  • ✅ Advanced networking and security patterns
  • ✅ Observability, monitoring, and troubleshooting
  • ✅ Real-world best practices from industry experts

“The practical, recipe-based approach made complex Kubernetes concepts finally click for me.”

👉 Get Your Copy Now — Start building production-grade Kubernetes skills today!

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.