🎯 Lesson Objective
Understand NetworkPolicy to control traffic in/out of Pods. Implement default-deny pattern, allow specific traffic, and use Cilium Network Policies for L7 control.
1. Why do we need NetworkPolicy?
By default, Kubernetes allows all traffic between all Pods in the cluster — every Pod can call every other Pod. This is a serious security risk.
NetworkPolicy allows you to define whitelist rules: only explicitly allowed traffic will pass.
Important: NetworkPolicy only works if CNI plugin supports it (Cilium, Calico, Weave). Flannel does not support NetworkPolicy.
2. NetworkPolicy Anatomy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: my-policy
namespace: production
spec:
podSelector: # áp dụng cho Pods nào?
matchLabels:
app: backend
policyTypes:
- Ingress # kiểm soát traffic VÀO pods được chọn
- Egress # kiểm soát traffic RA KHỎI pods được chọn
ingress:
- from: # allow traffic từ đâu?
- podSelector:
matchLabels:
app: frontend # chỉ cho phép từ frontend pods
ports:
- protocol: TCP
port: 8080
egress:
- to: # allow traffic đến đâu?
- podSelector:
matchLabels:
app: database # chỉ cho phép đến database pods
ports:
- protocol: TCP
port: 5432
3. Default-Deny Pattern — Best Practice
Start with "deny all", then open each necessary traffic stream.
3.1 Default Deny All Ingress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # {} = apply to ALL pods in namespace
policyTypes:
- Ingress
# ingress không được khai báo = deny all ingress
3.2 Default Deny All Egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
# egress không được khai báo = deny all egress
3.3 Allow DNS (important if denying egress)
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
4. Allow Specific Traffic Patterns
Frontend → Backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Cross-namespace: Allow from other namespace__HTMLTAG_98___
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-monitoring
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
# Chỉ cho phép từ namespace "monitoring"
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9090 # Prometheus scrape
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-monitoring
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
# Chỉ cho phép từ namespace "monitoring"
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9090 # Prometheus scrape
Combined: Pod selector AND namespace selector__HTMLTAG_100___
ingress:
- from:
# Pod phải có label app=prometheus VÀ trong namespace monitoring
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
podSelector: # LƯU Ý: cùng item (AND logic)
matchLabels:
app: prometheus
Khác với:
from:
Pod trong namespace monitoring HOẶC pod có label app=prometheus (OR logic)
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
podSelector: # LƯU Ý: item riêng biệt (OR logic)
matchLabels:
app: prometheus
ingress:
- from:
# Pod phải có label app=prometheus VÀ trong namespace monitoring
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
podSelector: # LƯU Ý: cùng item (AND logic)
matchLabels:
app: prometheus
Khác với:
from:
Pod trong namespace monitoring HOẶC pod có label app=prometheus (OR logic)
- namespaceSelector: matchLabels: kubernetes.io/metadata.name: monitoring
podSelector: # LƯU Ý: item riêng biệt (OR logic) matchLabels: app: prometheus
5. Cilium Network Policies — L7
Standard Kubernetes NetworkPolicy only controls L3/L4 (IP, port). Cilium CiliumNetworkPolicy allows L7 control.
5.1 HTTP Method and Path
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-l7-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
# Chỉ cho phép GET /api/v1/users
- method: GET
path: "^/api/v1/users.*"
# Chỉ cho phép POST /api/v1/orders
- method: POST
path: "^/api/v1/orders"
# Không cho phép GET /admin/* (không match → deny)
5.2 DNS-based Policies
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-external-dns
spec:
endpointSelector:
matchLabels:
app: backend
egress:
# Chỉ cho phép kết nối đến api.stripe.com
- toFQDNs:
- matchName: "api.stripe.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
# Chỉ cho phép *.amazonaws.com
- toFQDNs:
- matchPattern: "*.amazonaws.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
6. Verify and Debug NetworkPolicy
# Test connectivity từ pod này đến pod khác kubectl exec -n production frontend-pod -- curl http://backend-service:8080/apiNếu bị block:
kubectl exec -n production frontend-pod -- curl --connect-timeout 5 http://backend-service:8080
curl: (28) Connection timed out
Cilium: xem dropped packets
cilium monitor --type drop
Hubble: theo dõi traffic
hubble observe --namespace production --verdict DROPPED hubble observe --pod frontend-pod --protocol tcp
7. Best Practices
- Start with default-deny: applies to all production namespace
- Least privilege: only open traffic that is absolutely necessary
- Label consistent: NetworkPolicy depends on label selectors — set label consistently
- Test before applying to production: use Hubble audit mode to see which traffic will be blocked
- Document policies: explains why each policy was created
Summary
- NetworkPolicy: whitelist rules for Pod traffic
- Default-deny pattern: block all → allow specific
- Selectors: podSelector, namespaceSelector (AND logic within items, OR logic between items)
- Cilium CiliumNetworkPolicy: L7 HTTP, DNS-based policies
- Need CNI support: Cilium, Calico (not Flannel)