Skip to main content
COSMICBYTEZLABS
NewsSecurityHOWTOsToolsStudyTraining
ProjectsChecklistsAI RankingsNewsletterStatusTagsAbout
Subscribe

Press Enter to search or Esc to close

News
Security
HOWTOs
Tools
Study
Training
Projects
Checklists
AI Rankings
Newsletter
Status
Tags
About
RSS Feed
Reading List
Subscribe

Stay in the Loop

Get the latest security alerts, tutorials, and tech insights delivered to your inbox.

Subscribe NowFree forever. No spam.
COSMICBYTEZLABS

Your trusted source for IT intelligence, cybersecurity insights, and hands-on technical guides.

429+ Articles
114+ Guides

CONTENT

  • Latest News
  • Security Alerts
  • HOWTOs
  • Projects
  • Exam Prep

RESOURCES

  • Search
  • Browse Tags
  • Newsletter Archive
  • Reading List
  • RSS Feed

COMPANY

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CosmicBytez Labs. All rights reserved.

System Status: Operational
  1. Home
  2. HOWTOs
  3. Kubernetes Network Policies: Microsegmentation Guide
Kubernetes Network Policies: Microsegmentation Guide
HOWTOIntermediate

Kubernetes Network Policies: Microsegmentation Guide

Implement network microsegmentation in Kubernetes with Network Policies. Covers default deny, allow rules, namespace isolation, egress policies, and debugging.

Dylan H.

Platform Engineering

February 3, 2026
7 min read

Prerequisites

  • Kubernetes cluster with network policy support (Calico, Cilium, etc.)
  • kubectl access with admin privileges
  • Basic understanding of Kubernetes networking
  • Familiarity with YAML manifests

Overview

Kubernetes Network Policies enable microsegmentation by controlling traffic flow between pods. By default, pods can communicate with any other pod - Network Policies allow you to restrict this and implement a Zero Trust network model within your cluster.

Who Should Use This Guide:

  • Platform engineers securing Kubernetes workloads
  • Security teams implementing Zero Trust in Kubernetes
  • DevOps engineers hardening production clusters
  • Architects designing secure multi-tenant environments

Network Policy Capabilities:

FeatureDescription
Pod SelectorSelect pods by labels to apply policies
Namespace SelectorSelect pods in specific namespaces
Ingress RulesControl incoming traffic to pods
Egress RulesControl outgoing traffic from pods
IP BlocksAllow/deny traffic from CIDR ranges
PortsSpecify allowed ports and protocols

Network Policy CNI Support:

CNI PluginNetwork Policy SupportAdvanced Features
CalicoFullGlobalNetworkPolicy, DNS policies
CiliumFullL7 policies, DNS-aware, Hubble
Weave NetFull-
FlannelNone (requires Calico)-
Azure CNIFull (with Azure NPM)-
AWS VPC CNIPartial (with Calico)-

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│              Kubernetes Network Policy Architecture                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  Namespace: production                Namespace: database           │
│  ┌─────────────────────────────┐     ┌─────────────────────────────┐│
│  │    ┌─────────┐              │     │         ┌─────────┐         ││
│  │    │ Web App │              │     │         │  MySQL  │         ││
│  │    │ Pod     │──────────────┼─────┼────────▶│  Pod    │         ││
│  │    └─────────┘     Allow    │     │  Allow  └─────────┘         ││
│  │         │          3306     │     │  from                        ││
│  │         │                   │     │  production                  ││
│  │         │                   │     │                              ││
│  │         ▼                   │     └─────────────────────────────┘│
│  │    ┌─────────┐              │                                    │
│  │    │ API     │              │     Namespace: monitoring          │
│  │    │ Pod     │              │     ┌─────────────────────────────┐│
│  │    └─────────┘              │     │         ┌─────────┐         ││
│  │         │                   │     │         │Prometheus│         ││
│  │         │ Allow 9090        │     │         │  Pod    │◀────────┼│
│  │         └───────────────────┼─────┼─────────└─────────┘  Scrape ││
│  │                             │     │          from all           ││
│  └─────────────────────────────┘     └─────────────────────────────┘│
│                                                                     │
│  Default: DENY all traffic (with default deny policies)            │
│  Explicit: ALLOW only defined paths                                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Prerequisites Check

Verify Network Policy Support

# Check if CNI supports network policies
kubectl get pods -n kube-system -l k8s-app=calico-node
kubectl get pods -n kube-system -l k8s-app=cilium
 
# For AKS, check Azure NPM
kubectl get pods -n kube-system -l k8s-app=azure-npm
 
# Create test policy to verify support
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
EOF
 
# Verify policy was created
kubectl get networkpolicy test-network-policy
 
# Cleanup test
kubectl delete networkpolicy test-network-policy

Install Calico (If Needed)

# For clusters without network policy support
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml
 
# Verify installation
kubectl get pods -n calico-system
kubectl wait --for=condition=ready pod -l k8s-app=calico-node -n calico-system --timeout=300s

Step 1: Implement Default Deny Policies

Start with a default deny posture, then explicitly allow required traffic.

Default Deny All Ingress (Per Namespace)

# default-deny-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}  # Applies to all pods in namespace
  policyTypes:
  - Ingress
  # No ingress rules = deny all ingress
kubectl apply -f default-deny-ingress.yaml

Default Deny All Egress (Per Namespace)

# default-deny-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  # No egress rules = deny all egress

Default Deny Both (Recommended Starting Point)

# default-deny-all.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Apply to All Namespaces Script

#!/bin/bash
# apply-default-deny.sh
 
# Namespaces to protect (exclude system namespaces)
NAMESPACES=$(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | grep -v -E '^(kube-system|kube-public|kube-node-lease|calico-system)$')
 
for ns in $NAMESPACES; do
  echo "Applying default deny to namespace: $ns"
  kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: $ns
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
EOF
done

Step 2: Allow DNS Traffic

After denying all egress, pods can't resolve DNS. Allow DNS queries.

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

Alternative: Allow DNS by IP (CoreDNS ClusterIP)

# Get CoreDNS ClusterIP
kubectl get svc kube-dns -n kube-system -o jsonpath='{.spec.clusterIP}'
# allow-dns-by-ip.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 10.96.0.10/32  # Replace with your CoreDNS IP
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

Step 3: Create Application-Specific Policies

Web Application Ingress Policy

Allow traffic from ingress controller to web pods.

# web-app-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-to-web
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: web-frontend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
      podSelector:
        matchLabels:
          app.kubernetes.io/name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8080

Allow Web to API Communication

# web-to-api.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web-to-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: web-frontend
    ports:
    - protocol: TCP
      port: 3000

Allow API to Database Communication

# api-to-database.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-to-database
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: mysql
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: production
      podSelector:
        matchLabels:
          app: api-backend
    ports:
    - protocol: TCP
      port: 3306

Egress policy for API pods:

# api-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-backend
  policyTypes:
  - Egress
  egress:
  # Allow DNS
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
  # Allow database access
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: database
      podSelector:
        matchLabels:
          app: mysql
    ports:
    - protocol: TCP
      port: 3306
  # Allow external API calls (optional)
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 10.0.0.0/8      # Block internal
        - 172.16.0.0/12   # Block internal
        - 192.168.0.0/16  # Block internal
    ports:
    - protocol: TCP
      port: 443

Step 4: Namespace Isolation

Isolate namespaces from each other by default.

Deny Cross-Namespace Traffic

# namespace-isolation.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-from-other-namespaces
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}  # Only same namespace

Allow Specific Cross-Namespace Communication

# allow-monitoring-scrape.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-prometheus-scrape
  namespace: production
spec:
  podSelector:
    matchLabels:
      prometheus.io/scrape: "true"
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: monitoring
      podSelector:
        matchLabels:
          app: prometheus
    ports:
    - protocol: TCP
      port: 9090

Step 5: External Traffic Control

Allow External Ingress via LoadBalancer

# allow-external-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-web
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: web-frontend
      expose: external
  policyTypes:
  - Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0
    ports:
    - protocol: TCP
      port: 443

Restrict Egress to Specific External IPs

# restrict-external-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-specific-external
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: payment-service
  policyTypes:
  - Egress
  egress:
  # DNS
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53
  # Payment processor IPs only
  - to:
    - ipBlock:
        cidr: 203.0.113.0/24  # Payment provider range
    ports:
    - protocol: TCP
      port: 443

Step 6: Complete Application Example

Full network policy set for a three-tier application.

# complete-app-policies.yaml
---
# Default deny for production namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
---
# Allow DNS for all pods
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53
---
# Frontend: Allow from ingress, allow to API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
    ports:
    - protocol: TCP
      port: 80
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - protocol: TCP
      port: 8080
---
# Backend: Allow from frontend, allow to database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: database
    ports:
    - protocol: TCP
      port: 5432
---
# Database: Allow from backend only
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: database
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - protocol: TCP
      port: 5432

Step 7: Testing and Validation

Deploy Test Pods

# test-pods.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-client
  namespace: production
  labels:
    role: test
spec:
  containers:
  - name: curl
    image: curlimages/curl:latest
    command: ["sleep", "infinity"]
---
apiVersion: v1
kind: Pod
metadata:
  name: test-server
  namespace: production
  labels:
    role: test
    app: web-frontend
spec:
  containers:
  - name: nginx
    image: nginx:alpine
    ports:
    - containerPort: 80

Test Connectivity

# Apply test pods
kubectl apply -f test-pods.yaml
 
# Wait for pods to be ready
kubectl wait --for=condition=ready pod/test-client -n production --timeout=60s
kubectl wait --for=condition=ready pod/test-server -n production --timeout=60s
 
# Test allowed traffic (should work if policy allows)
kubectl exec -n production test-client -- curl -s --connect-timeout 5 test-server
 
# Test blocked traffic (should timeout)
kubectl exec -n production test-client -- curl -s --connect-timeout 5 http://10.96.0.1
 
# Test DNS resolution
kubectl exec -n production test-client -- nslookup kubernetes.default
 
# Test external connectivity (if allowed)
kubectl exec -n production test-client -- curl -s --connect-timeout 5 https://google.com

Network Policy Testing Script

#!/bin/bash
# test-network-policies.sh
 
NAMESPACE="production"
TEST_POD="test-client"
 
echo "=== Network Policy Testing ==="
 
# Test 1: DNS Resolution
echo -n "DNS Resolution: "
if kubectl exec -n $NAMESPACE $TEST_POD -- nslookup kubernetes.default > /dev/null 2>&1; then
    echo "PASS"
else
    echo "FAIL"
fi
 
# Test 2: Same namespace communication
echo -n "Same Namespace (test-server): "
if kubectl exec -n $NAMESPACE $TEST_POD -- curl -s --connect-timeout 3 test-server > /dev/null 2>&1; then
    echo "PASS (allowed)"
else
    echo "BLOCKED"
fi
 
# Test 3: Cross namespace (kube-system)
echo -n "Cross Namespace (kube-system): "
if kubectl exec -n $NAMESPACE $TEST_POD -- curl -s --connect-timeout 3 http://metrics-server.kube-system > /dev/null 2>&1; then
    echo "ALLOWED (check policy)"
else
    echo "BLOCKED (expected)"
fi
 
# Test 4: External internet
echo -n "External Internet: "
if kubectl exec -n $NAMESPACE $TEST_POD -- curl -s --connect-timeout 3 https://google.com > /dev/null 2>&1; then
    echo "ALLOWED"
else
    echo "BLOCKED"
fi
 
echo "=== Testing Complete ==="

Step 8: Debugging Network Policies

View Applied Policies

# List all network policies in namespace
kubectl get networkpolicies -n production
 
# Describe specific policy
kubectl describe networkpolicy allow-web-to-api -n production
 
# Get policy YAML
kubectl get networkpolicy allow-web-to-api -n production -o yaml

Check Pod Labels

# Verify pod labels match policy selectors
kubectl get pods -n production --show-labels
 
# Check if pod matches a selector
kubectl get pods -n production -l app=api-backend

Calico-Specific Debugging

# View Calico policies
kubectl get networkpolicies.crd.projectcalico.org -A
 
# Check Calico node status
kubectl exec -n calico-system -it $(kubectl get pod -n calico-system -l k8s-app=calico-node -o name | head -1) -- calico-node -bird-live
 
# View Felix logs
kubectl logs -n calico-system -l k8s-app=calico-node -c calico-node | grep -i policy

Cilium-Specific Debugging

# Check Cilium status
kubectl exec -n kube-system -it $(kubectl get pod -n kube-system -l k8s-app=cilium -o name | head -1) -- cilium status
 
# Monitor policy drops
kubectl exec -n kube-system -it $(kubectl get pod -n kube-system -l k8s-app=cilium -o name | head -1) -- cilium monitor --type drop
 
# View endpoint policies
kubectl exec -n kube-system -it $(kubectl get pod -n kube-system -l k8s-app=cilium -o name | head -1) -- cilium endpoint list

Packet Capture

# Capture traffic on a pod (requires debug privileges)
kubectl debug -n production pod/api-pod -it --image=nicolaka/netshoot -- tcpdump -i any -n
 
# Capture specific traffic
kubectl debug -n production pod/api-pod -it --image=nicolaka/netshoot -- tcpdump -i any port 3306 -n

Common Patterns

Allow Internal Load Balancer

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-internal-lb
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: internal-api
  policyTypes:
  - Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 10.0.0.0/8  # Internal network range
    ports:
    - protocol: TCP
      port: 8080

Allow Health Checks

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-health-checks
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  # Allow kubelet health checks
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0  # Node network
    ports:
    - protocol: TCP
      port: 8080  # Health check port
      endPort: 8081

Allow Pod-to-Pod Same Label

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-same-app
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: microservice-a
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: microservice-a

Troubleshooting

Common Issues:

SymptomPossible CauseSolution
All traffic blockedDefault deny without allow rulesAdd required allow policies
DNS not workingForgot DNS egress policyAdd allow-dns policy
Cross-namespace blockedNamespace labels missingAdd kubernetes.io/metadata.name label
Ingress not workingWrong ingress namespace selectorVerify ingress controller namespace
Pods can't reach externalEgress to 0.0.0.0/0 missingAdd external egress rule

Verification Commands:

# Check pod can reach service
kubectl exec -n production test-pod -- nc -zv service-name 80
 
# Check DNS resolution
kubectl exec -n production test-pod -- nslookup kubernetes.default
 
# Check external connectivity
kubectl exec -n production test-pod -- curl -I https://google.com
 
# List all policies affecting a pod
kubectl get networkpolicy -n production -o wide

Verification Checklist

Policy Implementation:

  • Default deny policies applied to sensitive namespaces
  • DNS egress allowed for all pods
  • Application-specific ingress rules created
  • Application-specific egress rules created
  • Cross-namespace policies for allowed communication

Testing:

  • Allowed traffic flows correctly
  • Blocked traffic is denied
  • DNS resolution works
  • External access controlled as expected

Operations:

  • Policy documentation updated
  • GitOps workflow for policy changes
  • Monitoring for policy violations
  • Runbook for debugging connectivity issues

Next Steps

After implementing Network Policies:

  1. Implement Cilium L7 Policies - HTTP/gRPC-aware filtering
  2. Enable Network Policy Logging - Audit denied connections
  3. Integrate with Service Mesh - Combine with Istio/Linkerd
  4. Automate Policy Generation - Use tools like Cilium Editor

References

  • Kubernetes Network Policies Documentation
  • Calico Network Policy Guide
  • Cilium Network Policies
  • Network Policy Editor (Cilium)
  • Network Policy Recipes

Last Updated: February 2026

#Kubernetes#Network Security#Calico#Microsegmentation#Zero Trust#Cloud Native

Related Articles

How to Deploy Falco for Kubernetes Runtime Security Monitoring

Step-by-step guide to deploying Falco as a Kubernetes runtime security engine. Covers Helm installation, custom rule authoring, Falcosidekick alerting...

12 min read

Microsoft Entra PIM: Configuring Just-in-Time Admin Access

Step-by-step guide to deploying Microsoft Entra Privileged Identity Management (PIM) for just-in-time role activation, approval workflows, access reviews,...

12 min read

FortiGate Security Hardening: Best Practices for Enterprise

Complete FortiGate hardening guide covering admin access lockdown, firmware management, interface hardening, DNS/NTP security, certificate management,...

31 min read
Back to all HOWTOs