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:

CNINetworkPolicyGhi chú
CalicoPhổ biến nhất cho NetworkPolicy
CiliumeBPF, hỗ trợ cả L7 policy
Weave
FlannelChỉ 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

  1. podSelector: policy áp dụng cho pod nào (trong cùng namespace).
  2. policyTypes: Ingress, Egress, hoặc cả hai.
  3. ingress.from / egress.to: danh sách nguồn/đích cho phép.
  4. 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.