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.