Stage 5 · Platform
Networking & Service Mesh
NetworkPolicy Design
Default deny, namespace selectors, egress controls, and testing with netshoot.
Design Principles
NetworkPolicy design follows the principle of least privilege: deny all traffic by default, then explicitly allow only what is needed. Start with a default-deny policy in every namespace, then add allow policies for required communication paths.
- Default deny all ingress and egress in every namespace
- Allow DNS egress (required for service discovery)
- Allow traffic only from specific namespaces/pods
- Use namespace selectors for cross-namespace communication
- Test policies before enforcing them
Default Deny Pattern
The default deny pattern blocks all traffic and lets you build allow-lists. Apply these policies in every namespace. The egress policy is critical — without DNS access, pods cannot resolve service names.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53The first policy denies all ingress and egress. The second allows DNS to any namespace (kube-system where CoreDNS runs). Without the DNS policy, pods cannot resolve service names.
Namespace Selectors
Namespace selectors let you control traffic between namespaces. Use labels on namespaces to group them (e.g., tenant, environment). NetworkPolicies can select namespaces by label to allow cross-namespace traffic.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
environment: production
podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
- from:
- namespaceSelector:
matchLabels:
environment: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090This policy allows ingress to api pods from frontend pods in production namespace AND prometheus pods in monitoring namespace. Each 'from' rule is additive — traffic is allowed if any rule matches.
Within a single 'from' rule, conditions are ANDed — all must match. Between multiple 'from' rules, conditions are ORed — any rule matching allows traffic. Use this to build complex access patterns.
Egress Controls
Egress policies control where pods can send traffic. This is critical for security — it prevents compromised pods from exfiltrating data or attacking other services. Allow only the specific destinations and ports needed.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-client-egress
namespace: production
spec:
podSelector:
matchLabels:
app: api-client
policyTypes:
- Egress
egress:
# Allow DNS
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
# Allow database access
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: database
podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# Allow external HTTPS
- 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: 443This egress policy allows: DNS, database access in the database namespace, and external HTTPS (excluding private IPs). The ipBlock with except prevents access to internal networks while allowing external traffic.
Policy Chains
Complex environments use policy chains — multiple NetworkPolicies that combine to create the final access rules. Policies are additive, so you can layer them: base deny, team-specific allow, and application-specific allow.
# Layer 1: Default deny (applied to all namespaces)
# Layer 2: Team-specific allows (per team namespace)
# Layer 3: Application-specific allows (per app)
# Example: monitoring namespace policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: prometheus-scrape
namespace: production
spec:
podSelector:
matchLabels:
prometheus-scrape: "true"
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090
---
# Allow Prometheus to scrape metrics from production
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-prometheus-egress
namespace: monitoring
spec:
podSelector:
matchLabels:
app: prometheus
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
prometheus-scrape: "true"
ports:
- protocol: TCP
port: 9090Prometheus in monitoring namespace can scrape pods labeled prometheus-scrape: true in any namespace. The ingress policy on production pods allows traffic from prometheus. The egress policy on prometheus allows traffic to scrape targets.
Testing Policies
Test NetworkPolicies before enforcing them. Use audit mode (if supported by your CNI), test with netshoot pods, and verify connectivity after applying policies.
# Run netshoot for testing
kubectl run netshoot --image=nicolaka/netshoot --rm -it -- /bin/bash
# Test DNS resolution
nslookup api-service.production.svc.cluster.local
# Test TCP connectivity
nc -zv api-service 8080
# Test HTTP
curl -v http://api-service:8080/health
# Check what network policies apply
kubectl get networkpolicies --all-namespaces
# Use Cilium Hubble for policy visualization
hubble observe --namespace production --verdict DROPPEDnetshoot provides networking tools for debugging. Test connectivity from inside the cluster to verify policies work as expected. Cilium Hubble provides real-time visibility into policy verdicts (ALLOWED/DROPPED).
Cilium logs every policy decision with source/destination pod, port, and verdict. Enable policy-verdict-log in Cilium config. This is invaluable for debugging why traffic is blocked — it shows the exact policy and rule responsible.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.