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.