iT邦幫忙

2025 iThome 鐵人賽

DAY 11
0
DevOps

30 天挑戰 CKAD 認證!菜鳥的 Kubernetes 學習日記系列 第 11

【Day11】網路如何管制?Network Policy 安全防護實戰

  • 分享至 

  • xImage
  •  

gh

前情提要

昨天我們看了 Service,他解決了 Pod IP 不固定的問題。透過 NodePort 對外曝光、ClusterIP 提供 Cluster 內穩定入口,再加上 Endpoints 的動態更新,讓服務彼此能可靠通訊,也自帶簡單的負載平衡。

但是現在叢集內所有 Pod 都能互相連線,預設是「完全開放」。在生產環境裡,這樣代表前端 Pod 可以直連資料庫,甚至不同團隊的服務都能互訪,這是一個很大的安全風險。

所以今天要來看看 Network Policy,它能幫我們設定哪些 Pod 可以互通、哪些該被擋下,讓 Cluster 網路變得更安全、可控。

Network Policy 介紹

在 Kubernetes 裡,預設所有 Pod 都可以互相通訊,任何 Pod 都能對任何 Pod 發送流量。不管是前端、後端還是資料庫,全部都是開放的。這雖然在小型開發環境很方便,但在生產環境卻是一個大大的隱患。

流量 (Traffic) 分成兩種類型:

  • Ingress:控制哪些流量「可以進來」Pod
  • Egress:控制 Pod「可以出去」哪些地方

一個簡單的架構例子

gh

我們來看一個簡單的應用架構,如上圖:

  • 使用者 → Web Pod Ingress(Port 80)
  • Web Pod Egress → API Pod Ingress(Port 5000)
  • API Pod Egress → Database Pod Ingress(Port 3306)

從流量 (Traffic) 角度來看:

  • Web Pod:Ingress(允許 80)、Egress(允許送到 API Pod:5000)
  • API Pod:Ingress(允許 5000)、Egress(允許送到 DB Pod:3306)
  • DB Pod:Ingress(允許 3306)

Policy 設定方式

所以在預設情況下,是沒有設定上述的 Ingress 和 Egress 限制的話,其實在 Web 這邊可以直接發送請求到 Database 這邊,顯然這不是我們所樂見的情況。為了防止這種情況的發生,這就是我們設定 Network Policy 的時候。

gh

所以我們這邊以 Database 的角度來看,我們只能允許 API Pod 可以向 Database 發送請求,其他的一律都 Block 掉。如上圖,我們制定了一個 Policy 是「只允許來自 API Pod 並且是 Port 3306 的入口流量」。啟用這個 Policy 之後,我們限制只有 API Pod 能訪問 DB,其餘到 Database Pod 的流量都會被阻擋掉。

對於 Network Policy 要套用在哪個 Pod 上面,或者是允許哪個 Pod 的流量,跟 Deployment、Service 一樣,靠 labels 與 selectors 來綁定。

實戰 🔥

Pod 限制

gh

我們拿上面提到的例子設定的 Policy 來看看,只有帶有 name=api-pod 標籤的 Pod,可以存取 role=db 的 Pod,並且只能用 TCP 3306 port。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          name: api-pod
    ports:
    - protocol: TCP
      port: 3306

搭配 Namespace 限制

如果叢集裡有很多個 api-pod(例如 dev/test/prod namespace 各有一份),單純用 podSelector 會讓所有 API Pod 都能連到 DB。

這時就要搭配 namespaceSelector,只允許 prod namespace 的 API Pod,但記得 prod namespace 要記得設定 labels 標籤喔!

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          name: api-pod
      namespaceSelector:
        matchLabels:
          name: prod
    ports:
    - protocol: TCP
      port: 3306

允許外部 IP 存取(ipBlock)

假設我們現在有一台外部備份伺服器 IP:192.168.5.10,也要能連進 DB。
這時候就不能用 Pod/Namespace 選擇器,而是改用 ipBlock 來開白名單:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          name: api-pod
      namespaceSelector:
        matchLabels:
          name: prod
    - ipBlock:
        cidr: 192.168.5.10/32
    ports:
    - protocol: TCP
      port: 3306

List 條件邏輯:OR 與 AND 的差異

ingressfrom 區塊裡面,底下其實是一個 list

  • 不同 list 元素之間是 OR 的關係
    也就是說,只要符合其中任意一個條件,就能通過 Policy。
  • 同一個 list 元素裡的條件是 AND 的關係
    如果一個元素裡同時包含 podSelectornamespaceSelector,那就代表必須同時滿足 Pod 的標籤Namespace 的標籤,才能被允許通過。

以下圖為例:

  • 左邊:podSelectornamespaceSelector 在同一組內,代表 必須同時符合 Pod 與 Namespace 的條件(AND)。
  • 右邊:兩個選擇器是分開的 list 元素,因此是 任一符合即可(OR)。換句話說,只要符合 Pod 條件 Namespace 條件,就能通過 Policy。

gh

加上 Egress 規則

我們繼續沿用前面有一台外部備份伺服器 IP:192.168.5.10,而我們如果要讓 DB Pod 主動把資料推送到外部備份伺服器(Port 80),就要加上 Egress

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          name: api-pod
      namespaceSelector:
        matchLabels:
          name: prod
    - ipBlock:
        cidr: 192.168.5.10/32
    ports:
    - protocol: TCP
      port: 3306
  egress:
  - to:
    - ipBlock:
        cidr: 192.168.5.10/32
    ports:
    - protocol: TCP
      port: 80

Lab 💻

建立一個 Network Policy,讓 Internal 應用程式只能對 payroll-service:8080db-service:3306 發送 Egress 流量。使用下方給定的規格。

  • Policy Name:internal-policy
  • Policy Type:Egress
  • Egress Allow:payroll
  • Payroll Port:8080
  • Egress Allow:mysql
  • Payroll Port:3306
# np-def.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: internal-policy
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector:
        matchLabels:
          name: payroll
    - podSelector:
        matchLabels:
          name: mysql
    ports:
    - protocol: TCP
      port: 8080
    - protocol: TCP
      port: 3306
kubectl create -f np-def.yaml

總結

今天我們實作了 Network Policy,看到它如何幫助我們在叢集內建立「網路防火牆」。從最基礎的 ingress/egress 控制,到更進階的 namespaceSelector、ipBlock,都能靈活組合,讓 Pod 之間的通訊更安全、更可控。讓我們能真正落實「最小權限原則」,避免服務之間互相亂串。

回顧這幾天的學習路線:從 Pod、Deployment、Service 到今天的 Network Policy,我們一步步把應用「跑起來」並且「安全起來」。不過,Pod 除了網路需要規範外,它該跑在哪台 Node 上,其實也很關鍵。GPU Pod 要落在有 GPU 的 Node,資料庫 Pod 不能隨便被排到低效能的 Node。明天我們就來看 Taints & Tolerations、Node Selector、Node Affinity,如何決定 Pod 的最佳落點。

下一篇文章:Pod 調度策略實戰:Taints & Tolerations、Node Affinity、Node Selector


上一篇
【Day10】服務要曝光:Service 入門實戰
系列文
30 天挑戰 CKAD 認證!菜鳥的 Kubernetes 學習日記11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言