Sau bài này bạn làm được: viết NetworkPolicy isolate namespace; debug khi pod không connect được service khác; hiểu CNI nào hỗ trợ NetworkPolicy.
Mặc định: mọi pod nói chuyện được với mọi pod
Kubernetes không chặn traffic giữa các pod mặc định. Pod ở namespace A gọi pod ở namespace B → cho phép. Đây là thiết kế đơn giản nhưng không an toàn cho production multi-team.
NetworkPolicy là firewall ở tầng pod: bạn khai báo ai được gọi ai, Kubernetes (qua CNI) enforce.
Yêu cầu: CNI hỗ trợ
Không phải CNI nào cũng enforce NetworkPolicy:
| CNI | NetworkPolicy | Ghi chú |
|---|---|---|
| Calico | ✅ | Phổ biến nhất cho NetworkPolicy |
| Cilium | ✅ | eBPF, hỗ trợ cả L7 policy |
| Weave | ✅ | |
| Flannel | ❌ | Chỉ networking cơ bản |
| AWS VPC CNI | ❌ (cần addon) | Dùng Calico addon |
Tạo NetworkPolicy trên cluster Flannel → resource tồn tại nhưng không được enforce → false sense of security.
# Kiểm tra CNI
kubectl get pods -n kube-system | grep -E "calico|cilium|weave"
NetworkPolicy spec
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-to-db
namespace: production
spec:
podSelector: # Policy áp dụng cho pod nào
matchLabels:
app: postgres
policyTypes:
- Ingress # Kiểm soát traffic VÀO
- Egress # Kiểm soát traffic RA
ingress:
- from:
- podSelector: # Cho phép từ pod có label app=my-api
matchLabels:
app: my-api
ports:
- protocol: TCP
port: 5432
egress:
- to:
- podSelector: {} # Cho phép ra mọi pod trong namespace
ports:
- protocol: TCP
port: 53 # DNS
- protocol: UDP
port: 53
Cách đọc
- podSelector: policy áp dụng cho pod nào (trong cùng namespace).
- policyTypes: Ingress, Egress, hoặc cả hai.
- ingress.from / egress.to: danh sách nguồn/đích cho phép.
- Không match rule nào = DENY (khi policyType được khai báo).
Default deny — pattern quan trọng nhất
Deny all ingress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # {} = tất cả pod trong namespace
policyTypes:
- Ingress
# Không có ingress rules → deny tất cả ingress
Sau policy này, không pod nào trong production nhận traffic từ bên ngoài — trừ khi có NetworkPolicy khác cho phép cụ thể.
Deny all egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
# Không có egress rules → deny tất cả egress
# CẢNH BÁO: bao gồm cả DNS! Pod không resolve được tên.
Cảnh báo: deny egress chặn cả DNS (port 53). Cần allow DNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector: {} # DNS có thể ở kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Pattern: deny all + allow specific
# 1. Deny all ingress + egress
# 2. Allow DNS egress
# 3. Allow specific service-to-service
Đây là mô hình allowlist — an toàn nhất, nhưng cần maintain danh sách allow.
Selectors
podSelector
Chọn pod theo label trong cùng namespace với NetworkPolicy.
namespaceSelector
Chọn pod từ namespace khác:
ingress:
- from:
- namespaceSelector:
matchLabels:
team: frontend # Namespace có label team=frontend
podSelector:
matchLabels:
app: web-app # Pod có label app=web-app
Lưu ý AND vs OR:
# AND: namespaceSelector VÀ podSelector cùng block → phải match CẢ HAI
- from:
- namespaceSelector:
matchLabels:
team: frontend
podSelector: # Cùng dấu - với namespaceSelector
matchLabels:
app: web
# OR: hai block riêng → match BẤT KỲ
- from:
- namespaceSelector:
matchLabels:
team: frontend
- podSelector: # Dấu - riêng → rule riêng
matchLabels:
app: web
Sai indent = sai logic. Đây là nguồn lỗi phổ biến nhất với NetworkPolicy.
ipBlock
Cho phép/chặn CIDR range (traffic ngoài cluster):
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/8
except:
- 10.0.1.0/24
Use cases thực tế
1. Isolate namespace
# Chỉ cho phép traffic trong cùng namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: isolate-namespace
namespace: staging
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {} # Chỉ pod cùng namespace
2. Restrict database access
# Chỉ backend API được gọi database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-access
namespace: production
spec:
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: backend
ports:
- port: 5432
3. Allow Ingress controller
# Cho phép Ingress controller (namespace ingress-nginx) gọi app
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
Debug NetworkPolicy
Triệu chứng: pod không connect được service
# 1. Kiểm tra NetworkPolicy trong namespace
kubectl get networkpolicy -n production
# 2. Describe policy — xem selector và rules
kubectl describe networkpolicy -n production
# 3. Test connectivity
kubectl exec -it source-pod -- curl -v target-service:8080
kubectl exec -it source-pod -- nc -zv target-pod-ip 8080
# 4. Kiểm tra label của source pod
kubectl get pod source-pod --show-labels
# 5. Kiểm tra label của namespace (nếu dùng namespaceSelector)
kubectl get ns production --show-labels
# 6. Nếu dùng Cilium — xem policy status
kubectl -n kube-system exec -it cilium-xxx -- cilium policy get
Tools hỗ trợ
- Cilium Hubble: visualize traffic flow + policy verdict (ALLOWED/DENIED).
- Calico calicoctl:
calicoctl get networkPolicy -o yaml. - kubectl neat: clean up managed fields để đọc policy dễ hơn.
Giới hạn của NetworkPolicy
- Chỉ L3/L4 (IP + port). Không filter HTTP method, path, header.
- Không có deny rule cụ thể — chỉ có “không allow = deny”.
- Không apply cho host network pod.
- CNI phải hỗ trợ — Flannel không enforce.
Nếu cần L7 policy: Cilium NetworkPolicy (CRD riêng) hỗ trợ HTTP method/path filtering. Hoặc service mesh (Istio AuthorizationPolicy) — xem Mạng bài 17.
Tóm tắt
- Mặc định K8s: pod nào gọi pod nào cũng được → không an toàn.
- NetworkPolicy = firewall tầng pod. Cần CNI hỗ trợ (Calico, Cilium).
- Pattern: default deny + allow cụ thể (allowlist).
- AND vs OR trong selector: cùng block = AND, khác block = OR. Sai indent = sai logic.
- Debug: kiểm tra policy → kiểm tra label → test connectivity → xem CNI logs.
Câu hỏi hay gặp
Tạo NetworkPolicy trên cluster Flannel có báo lỗi không?
Trả lời: Không. Resource tạo thành công, nhưng không ai enforce → tất cả traffic vẫn đi qua. Đây là nguy hiểm: bạn nghĩ đã có firewall nhưng thực tế không. Kiểm tra CNI trước khi tin NetworkPolicy.
NetworkPolicy có chặn traffic từ LoadBalancer/NodePort không?
Trả lời: Tuỳ. Traffic qua LoadBalancer/NodePort thường bị SNAT (source IP đổi thành node IP). NetworkPolicy match source IP → có thể không chặn được nếu source IP không đúng. Kiểm tra externalTrafficPolicy: Local để giữ source IP.
Bao nhiêu NetworkPolicy quá nhiều?
Trả lời: Không có con số cụ thể, nhưng mỗi policy thêm iptables/eBPF rules. Vài trăm policy trên cluster lớn hoàn toàn ổn. Vấn đề thường ở logic sai (quên allow DNS, quên allow Ingress controller) hơn là performance.
Bài tiếp theo (Giai đoạn IV): ConfigMap, Secret và Downward API — config đổ vào pod thế nào.