🎯 Mục tiêu bài học
Hiểu NetworkPolicy để kiểm soát traffic vào/ra khỏi Pods. Implement default-deny pattern, allow specific traffic, và dùng Cilium Network Policies cho L7 control.
1. Tại sao cần NetworkPolicy?
Mặc định Kubernetes cho phép tất cả traffic giữa tất cả Pods trong cluster — mọi Pod đều có thể gọi mọi Pod khác. Đây là rủi ro bảo mật nghiêm trọng.
NetworkPolicy cho phép bạn định nghĩa whitelist rules: chỉ traffic được phép rõ ràng mới được đi qua.
Quan trọng: NetworkPolicy chỉ hoạt động nếu CNI plugin hỗ trợ (Cilium, Calico, Weave). Flannel không hỗ trợ 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
Bắt đầu bằng "deny all", sau đó mở từng luồng traffic cần thiết.
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 (quan trọng nếu deny 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 từ namespace khác
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 VÀ namespace selector
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 chỉ kiểm soát L3/L4 (IP, port). Cilium CiliumNetworkPolicy cho phép L7 control.
5.1 HTTP Method và 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 và 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: áp dụng cho mọi namespace production
- Least privilege: chỉ mở traffic thực sự cần thiết
- Label consistently: NetworkPolicy phụ thuộc label selectors — đặt label nhất quán
- Test trước khi apply production: dùng Hubble audit mode để xem traffic nào sẽ bị block
- Document policies: giải thích tại sao mỗi policy được tạo
Tóm tắt
- NetworkPolicy: whitelist rules cho Pod traffic
- Default-deny pattern: block all → allow specific
- Selectors: podSelector, namespaceSelector (AND logic trong item, OR logic giữa items)
- Cilium CiliumNetworkPolicy: L7 HTTP, DNS-based policies
- Cần CNI hỗ trợ: Cilium, Calico (không phải Flannel)