Mạng Linux & Container
20/21
Bài 20 / 21~14 phútKubernetes Networking (nhập môn)Miễn phí… lượt xem

NetworkPolicy — zero-trust giữa các pod

Default allow mọi pod; NetworkPolicy ingress/egress + podSelector/namespaceSelector; cần CNI enforce; pitfall policy YAML xanh nhưng không chặn traffic.

TL;DR: Kubernetes default allow: không có NetworkPolicy chọn pod thì pod non-isolated — mọi chiều ingress/egress được phép (trong model cluster). NetworkPolicy (networking.k8s.io/v1) là luật L3/L4 (TCP/UDP/SCTP): chọn pod bằng podSelector, khai báo policyTypes Ingress/Egress, rồi allow-list from/to (podSelector, namespaceSelector, ipBlock) + ports. Policy additive (union); kết nối A→B cần cả egress phía A và ingress phía B. Object API luôn tạo được; enforcement chỉ khi CNI/plugin hỗ trợ. Pitfall cứng: apply xanh + kubectl get networkpolicies có row, traffic vẫn full-mesh — class “API no-op” giống Ingress thiếu controller.

On-call lab kind: junior apply default-deny-ingress + “chỉ frontend → payment”, kubectl get networkpolicy OK, kubectl exec pod attacker vẫn curl payment. Ticket: “NetworkPolicy K8s hỏng”. Bạn hỏi: “CNI nào? Plugin document enforce NetworkPolicy chưa? Label podSelector khớp pod thật? Có rule DNS egress nếu đã deny egress?” Nhiều cluster lab chỉ lo connectivity — policy object tồn tại, dataplane filter = 0.

Bài 01–02 chốt flat pod IP + CNI. Bài 03–04 chốt đường vào. Bài này chốt ai được nói chuyện với ai sau khi đã vào cluster — micro-segment L4, không thay authn/L7 mesh.

Bài faded: default-deny + allow frontend worked; bạn tự điền selector YAML và tự chẩn class “policy im lặng”.

1. Analogy — Toà mở cửa, rồi mới khóa theo thẻ

Pod model là toà có số máy phẳng: căn nào cũng gọi căn khác được (east-west open). Service/Ingress là tổng đài và lễ tân — chưa phải khóa phòng.

  1. Default allow = chưa gắn thẻ từ chối: mọi căn nói chuyện tự do.
  2. NetworkPolicy = luật khóa từng căn (hoặc cả tầng/namespace): “căn app=payment chỉ nhận cuộc từ căn app=frontend port 8080”.
  3. podSelector = căn nào bị luật này áp (subject).
  4. from / to = ai được gọi vào / gọi ra (peer: thẻ căn, thẻ tầng/namespace, hoặc dải số ngoài).
  5. CNI enforce = bảo vệ thật trên cửa — không có đội bảo vệ (plugin policy) thì tờ luật dán tường không chặn ai.
Đời thườngNetworkPolicy
Toà mở mặc địnhKhông policy → allow all
Luật khóa theo cănNetworkPolicy + podSelector
Chiều vào / raIngress / Egress
Thẻ căn / thẻ tầngpodSelector / namespaceSelector
Dải số ngoài toàipBlock CIDR
Bảo vệ thậtCNI policy engine
💡 Cách nhớ

NetworkPolicy = allow-list sau khi isolated — không phải firewall “deny rule” tường minh từng nguồn. Default cluster mở; bạn cô lập rồi mở có chọn.

2. Default allow — khi nào pod bị cô lập?

2.1 Hai chiều isolation độc lập

Theo Network Policies (Kubernetes docs):

Trạng tháiÝ nghĩa
Non-isolated (ingress)Mọi inbound connection được phép (chiều vào)
Isolated (ingress)Chỉ connection allow bởi ít nhất một policy Ingress áp pod + traffic từ node của pod (luôn được phép theo model)
Non-isolated (egress)Mọi outbound được phép
Isolated (egress)Chỉ outbound match allow-list egress của policy áp pod

Default: pod non-isolated cả hai chiều cho đến khi có NetworkPolicy vừa chọn pod (spec.podSelector) vừa khai báo chiều đó trong policyTypes (hoặc suy ra theo rule egress — xem dưới).

2.2 Isolation không tuyệt đối “cấm hết mọi protocol”

NetworkPolicy nhắm TCP/UDP/SCTP (L4 connection). Hành vi ARP/ICMP… không đảm bảo đồng nhất giữa plugin — đừng assume “deny-all = im lặng ping”.

2.3 Cả hai phía phải allow

Gói từ pod A → pod B:

  1. Nếu A isolated egress → cần egress rule trên policy của A cho phép tới B (peer + port).
  2. Nếu B isolated ingress → cần ingress rule trên policy của B cho phép từ A.
  3. Một phía deny (không match allow-list) → connection không thành.

Đây là nguồn bug “policy frontend đúng nhưng payment vẫn timeout”: bạn mở ingress payment, quên egress frontend (hoặc ngược).

Nguyên tắc NetworkPolicy: Cần Allow cả hai chiều

3. Cấu trúc NetworkPolicy — subject, type, rules

3.1 Skeleton tối thiểu (minh hoạ)

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-payment
  namespace: shop
spec:
  podSelector:
    matchLabels:
      app: payment
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080
FieldViệc
metadata.namespacePolicy sống trong ns; subject là pod cùng ns (trừ peer cross-ns qua namespaceSelector)
spec.podSelectorSubject — pod nào bị policy áp. {} = mọi pod trong ns
policyTypesIngress, Egress, hoặc cả hai — chiều cô lập
ingress[]Allow-list vào subject
egress[]Allow-list ra từ subject
from / toPeer (OR trong một rule khi nhiều phần tử mảng)
portsTCP/UDP/SCTP + port (hoặc range endPort nếu plugin support)

policyTypes rỗng / omit: docs — mặc định luôn coi có Ingress; Egress chỉ được set nếu policy có rule egress. Production: khai tường minh policyTypes để khỏi “tưởng deny egress”.

3.2 Default deny ingress (namespace)

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: shop
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  # no ingress rules → isolated, zero allow-list

Sau object này, mọi pod trong shop isolated ingress — chỉ traffic node→pod + rule allow khác còn sống.

3.3 Default deny egress — nhớ DNS

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: shop
spec:
  podSelector: {}
  policyTypes:
    - Egress

Deny-all egress cũng chặn DNS tới CoreDNS (thường ns kube-system). Workload curl payment-api.shop.svc fail từ resolve trước cả TCP app — triệu chứng hay bị gán nhầm “Service hỏng”.

Allow DNS (minh hoạ — label CoreDNS/cluster thực tế có thể khác; đo trên cluster bạn):

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: shop
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

Lưu ý: một entry from/to có cả namespaceSelector và podSelector = AND (pod trong ns khớp). Hai phần tử mảng riêng = OR. Sai indent YAML đổi hẳn nghĩa — kubectl describe networkpolicy để đối chiếu.

3.4 Faded — viết allow frontend → payment

Tự điền

Namespace shop. Subject: pod app=payment. Chỉ Ingress. Cho phép từ pod cùng ns app=frontend, TCP 8080.
Viết podSelector subject + một rule ingress.from + ports (không cần full file).
Sau default-deny-ingress, chỉ policy này — pod app=order curl payment được không?

Đáp án kỳ vọng:

YAML
spec:
  podSelector:
    matchLabels:
      app: payment
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080

Pod order không match from → bị chặn (nếu CNI enforce + default-deny/isolation đã bật).

4. Selector peer — pod, namespace, ipBlock

4.1 Ba loại peer

PeerChọnGhi chú nhập môn
podSelector (một mình trong entry)Pod cùng namespace policyLabel workload, không “tên Service”
namespaceSelector (một mình)Mọi pod trong ns khớp labelCross-ns rộng — cẩn thận
namespaceSelector + podSelector (cùng entry)Pod khớp trong ns khớpCross-ns hẹp
ipBlockCIDR (+ optional except)IP ổn định ngoài / đặc biệt; đừng pin pod IP ephemeral

NetworkPolicy không target Service by name. Target label pod (backend thật) hoặc ns/CIDR. Service chỉ là VIP — filter thường nhìn pod identity / IP sau rewrite tùy plugin (edge case Service external — ngoài depth bài).

4.2 OR vs AND trong from

YAML
# OR: frontend local HOAC moi pod ns label team=payments
ingress:
  - from:
      - podSelector:
          matchLabels:
            app: frontend
      - namespaceSelector:
          matchLabels:
            team: payments
YAML
# AND: chi pod app=client TRONG ns user=alice
ingress:
  - from:
      - namespaceSelector:
          matchLabels:
            user: alice
        podSelector:
          matchLabels:
            app: client

4.3 Namespace theo tên

API không có field “namespace name” thuần. Control plane gắn label bất biến kubernetes.io/metadata.name=<tên-ns> — dùng trong namespaceSelector khi cần target đúng một ns theo tên.

4.4 Traffic node và hostNetwork

  • Traffic từ node hosting pod → pod: model docs luôn allow (probe/kubelet path) — không “deny hết kể cả node”.
  • Pod hostNetwork: true: hành vi NetworkPolicy undefined / implementation-defined — nhiều plugin coi như traffic node. Đừng thiết kế zero-trust giả định hostNetwork bị filter như pod network.

4.5 Faded — đọc policy “có chặn attacker không?”

Tự chẩn trước đáp án

Có default-deny-ingress + policy allow from.podSelector app=frontend tới app=payment:8080.
(1) Pod app=frontend curl payment:8080?
(2) Pod app=frontend curl payment:9090?
(3) Pod app=attacker cùng ns curl 8080?
(4) Pod frontend ns khác (label khác) curl 8080?
Giả sử CNI có enforce.

Đáp án kỳ vọng: (1) allow. (2) deny (sai port). (3) deny. (4) deny — podSelector alone = cùng ns policy; cross-ns cần namespaceSelector.

5. Additive policy — union, không “conflict ghi đè”

5.1 Nhiều policy cùng subject

Nếu nhiều NetworkPolicy áp cùng pod cùng chiều: allow-list là hợp (union) các rule. Không có “policy sau ghi đè policy trước”. Order apply không đổi kết quả allow.

Hệ quả:

  • Policy “hep” không thu hẹp policy “rộng” đã allow-all ingress (ingress: [{}]).
  • Muốn siết: đừng để allow-all song song; review toàn bộ policy chọn pod.

5.2 Allow-all ingress (mở lại cả ns)

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
  namespace: shop
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - {}   # empty rule = allow all ingress

Với object này, không policy khác trong ns còn deny được inbound tới subject (union luôn include “all”).

5.3 Worked path — design tối thiểu shop

Mục tiêu: payment chỉ nhận frontend; order gọi payment; DNS ok; default deny còn lại.

  1. default-deny-ingress + default-deny-egress trên ns shop (hoặc deny từng chiều có chủ đích).
  2. allow-dns-egress (UDP/TCP 53 → CoreDNS).
  3. Ingress payment: from frontend + from order (hai peer hoặc hai policy), port app.
  4. Egress frontend/order: to payment (và DNS đã cover).

Production còn probe, ingress-controller ns, metrics — bài nhập môn dừng ở mental model; checklist ops dài hơn recipes cộng đồng.

Mô hình Default Deny: Cách ly Namespace và Mở Chọn Lọc

6. Pitfall — policy YAML xanh, traffic vẫn full-mesh

6.1 Class cứng: không có implementation

Docs Kubernetes: Creating a NetworkPolicy resource without a controller that implements it will have no effect.

Quan sátÝ nghĩa
kubectl get networkpolicies có objectChỉ etcd/API
kubectl describe rule đúngVẫn chỉ control-plane view
Pod A vẫn curl pod B mọi portKhông enforce hoặc selector/rule sai
CNI kindnet / Flannel-style labThường connectivity-only

Verify hướng:

Bash
# What CNI / policy engine?
kubectl get pods -A | grep -iE 'calico|cilium|weave|kube-router|antrea|kindnet|flannel'
kubectl -n kube-system get ds,deploy 2>/dev/null | head

# Policy objects (API only)
kubectl get networkpolicies -A
kubectl describe networkpolicy -n shop allow-frontend-to-payment

# Effect test from a real client pod
kubectl exec -n shop deploy/attacker -- curl -sS -m 3 http://payment:8080/ || echo "blocked-or-fail"

Cùng class CNI bài 02 và Ingress without controller: API desire ≠ dataplane.

6.2 Selector / label drift

  • podSelector không khớp label Deployment → policy không isolate đúng pod (pod vẫn non-isolated bởi policy đó).
  • Peer app=fronted typo → allow-list trống thực tế → “chặn nhầm” frontend hợp lệ.
  • Đổi label rolling update → peer/subject lệch tạm thời.

6.3 Chỉ mở một phía

Isolated cả hai đầu nhưng chỉ viết ingress payment, frontend deny-all egress → timeout. Checklist: egress client + ingress server + DNS.

6.4 Nhầm NetworkPolicy với authn / L7

  • NetworkPolicy không TLS, không user identity HTTP, không “Service name ACL” đầy đủ.
  • Không log “blocked connection” chuẩn API — quan sát thường bằng probe fail / metric CNI (Hubble…) / tcpdump.
  • Ingress L7 không thay east-west zero-trust pod-to-pod.

6.5 Faded — ticket “policy không ăn”

Tự chẩn class

Triệu chứng: get networkpolicy OK; describe rule frontend→payment; mọi pod ns vẫn curl payment.
Cluster: kind + CNI mặc định lab (không Calico/Cilium).
(A) Sai port trong rule? (B) CNI không enforce? (C) Quên DNS?
Chọn class chính + một lệnh/câu hỏi xác nhận.

Đáp án kỳ vọng: (B) — full-mesh mọi source (kể cả attacker) trỏ no implementation hơn “sai port” (sai port thì frontend đúng port vẫn có thể OK). Xác nhận: docs/CNI feature NetworkPolicy; test có/không engine; không “restart API server”.

Lưu đồ chẩn đoán sự cố NetworkPolicy

📚 Deep Dive — tài liệu gốc

📚 Deep Dive — tài liệu gốc

Spec / docs:

Nội bộ OLHub:

Liên hệ các bài khác

Tóm tắt

  • Default allow khi không isolated; policy + policyTypes → allow-list only.
  • Design: subject podSelector, peer from/to, ports; cả hai phía connection.
  • Union policies; allow-all ingress: [{}] “bẻ” nỗ lực siết khác.
  • CNI phải enforce — object API xanh ≠ traffic bị chặn.
  • Deny egress → DNS; label typo → no-op hoặc over-block.

7. Tự kiểm tra

Tự kiểm tra
0/7 câu đã trả lời
  1. Q1
    Pod không bị NetworkPolicy nào chọn — ingress từ pod lạ trong cluster được phép không? 'Default deny' đến từ đâu nếu admin chưa apply gì?
  2. Q2
    A isolated egress, B isolated ingress. A→B: điều kiện nào? Chỉ mở ingress B, A đang default-deny-egress — triệu chứng?
  3. Q3
    Phân biệt from gồm hai phần tử mảng (podSelector + namespaceSelector riêng) với một phần tử có cả hai field. OR hay AND?
  4. Q4
    Vì sao kubectl get networkpolicy + describe rule đẹp chưa chứng minh traffic bị chặn? Liệt kê dependency dataplane + một test effect.
  5. Q5
    default-deny-egress xong app không resolve Service DNS. Root class? Hướng policy tối thiểu (không cần YAML đầy đủ production)?
  6. Q6
    Hai NetworkPolicy cùng chọn app=payment: một allow from frontend, một allow from order. Frontend còn vào được không sau khi thêm policy order? Vì sao?
  7. Q7
    Design tối thiểu: ns shop, payment chỉ nhận frontend:8080, còn lại deny ingress. Liệt kê object/policyTypes cần (tên logic). CNI lab không policy — expected effect?

Bài tiếp theo: Tổng kết module — Kubernetes Networking

Bài này có giúp bạn hiểu bản chất không?

Bài này đáng gửi cho bạn học cùng?

Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.

Thảo luận & góp ý

Hỏi đáp về bài này

Bài tiếp theo

Tổng kết module & track Networking