Ztunnel 流量重新導向
在 Ambient 模式的上下文中,流量重新導向是指資料平面功能,它攔截傳送到啟用 Ambient 的工作負載和從這些工作負載傳送的流量,並將其路由通過處理核心資料路徑的 ztunnel 節點代理。有時也會使用 流量捕獲 一詞。
由於 ztunnel 旨在透明地加密和路由應用程式流量,因此需要一種機制來捕獲所有進出「網格內」Pod 的流量。這是一項安全關鍵任務:如果可以繞過 ztunnel,則可以繞過授權原則。
Istio 的 Pod 內流量重新導向模型
Ambient 模式中 Pod 內流量重新導向的核心設計原則是,ztunnel 代理具有在工作負載 Pod 的 Linux 網路命名空間內執行資料路徑捕獲的能力。這是通過 istio-cni
節點代理程式和 ztunnel 節點代理之間的功能協作來實現的。此模型的關鍵優點是,它使 Istio 的 Ambient 模式能夠與任何 Kubernetes CNI 外掛程式並行工作,透明地工作,且不會影響 Kubernetes 網路功能。
下圖說明當新的工作負載 Pod 在啟用 Ambient 的命名空間中啟動(或新增至其中)時的事件順序。
istio-cni
節點代理程式會回應 CNI 事件,例如 Pod 建立和刪除,並且也會監看基礎 Kubernetes API 伺服器,以了解事件,例如將 Ambient 標籤新增至 Pod 或命名空間。
istio-cni
節點代理程式還會額外安裝一個鏈式 CNI 外掛程式,此外掛程式會在 Kubernetes 叢集中主要的 CNI 外掛程式執行後,由容器執行時執行。它的唯一目的是在容器執行時於已加入 Ambient 模式的命名空間中建立新的 Pod 時,通知 istio-cni
節點代理程式,並將新的 Pod 環境資訊傳播給 istio-cni
。
一旦 istio-cni
節點代理程式收到需要將 Pod 加入網格的通知(如果 Pod 是全新的,則來自 CNI 外掛程式;如果 Pod 已經在執行但需要加入,則來自 Kubernetes API 伺服器),就會執行以下操作序列:
istio-cni
會進入 Pod 的網路命名空間,並建立網路重新導向規則,使得進出 Pod 的封包被攔截,並透明地重新導向到監聽 眾所周知埠 (15008、15006、15001) 的節點本地 ztunnel 代理程式實例。接著,
istio-cni
節點代理程式會透過 Unix 網域 socket 通知 ztunnel 代理程式,它應該在 Pod 的網路命名空間內建立本地代理程式監聽埠(在埠 15008、15006 和 15001 上),並向 ztunnel 提供代表 Pod 網路命名空間的低階 Linux 檔案描述符。- 雖然通常 socket 是由實際在 Linux 網路命名空間內執行的程序在該網路命名空間內建立,但完全可以利用 Linux 的低階 socket API,允許在一個網路命名空間中執行的程序在另一個網路命名空間中建立監聽 socket,假設目標網路命名空間在建立時已知。
節點本地 ztunnel 會在內部啟動一個新的代理程式實例和監聽埠集合,專用於新加入的 Pod。
一旦 Pod 內的重新導向規則就位,並且 ztunnel 已建立監聽埠,Pod 就會加入網格,並且流量開始流經節點本地 ztunnel。
進出網格中 Pod 的流量預設會使用 mTLS 完全加密。
資料現在會加密地進出 Pod 網路命名空間。網格中的每個 Pod 都有能力強制執行網格原則並安全地加密流量,即使在 Pod 中執行的使用者應用程式對兩者都毫無察覺。
此圖示說明了在新模型中,加密流量如何在 Ambient 網格中的 Pod 之間流動
在 Ambient 模式中觀察和偵錯流量重新導向
如果 Ambient 模式中的流量重新導向無法正常運作,可以進行一些快速檢查來縮小問題範圍。我們建議從 ztunnel 除錯指南中描述的步驟開始進行疑難排解。
檢查 ztunnel 代理程式記錄
當應用程式 Pod 是 Ambient 網格的一部分時,您可以檢查 ztunnel 代理程式日誌,以確認網格正在重新導向流量。如下面的範例所示,與 inpod
相關的 ztunnel 日誌表示已啟用 Pod 內重新導向模式、代理程式已收到關於 Ambient 應用程式 Pod 的網路命名空間 (netns) 資訊,並且已開始為其提供代理服務。
$ kubectl logs ds/ztunnel -n istio-system | grep inpod
Found 3 pods, using pod/ztunnel-hl94n
inpod_enabled: true
inpod_uds: /var/run/ztunnel/ztunnel.sock
inpod_port_reuse: true
inpod_mark: 1337
2024-02-21T22:01:49.916037Z INFO ztunnel::inpod::workloadmanager: handling new stream
2024-02-21T22:01:49.919944Z INFO ztunnel::inpod::statemanager: pod WorkloadUid("1e054806-e667-4109-a5af-08b3e6ba0c42") received netns, starting proxy
2024-02-21T22:01:49.925997Z INFO ztunnel::inpod::statemanager: pod received snapshot sent
2024-02-21T22:03:49.074281Z INFO ztunnel::inpod::statemanager: pod delete request, draining proxy
2024-02-21T22:04:58.446444Z INFO ztunnel::inpod::statemanager: pod WorkloadUid("1e054806-e667-4109-a5af-08b3e6ba0c42") received netns, starting proxy
確認 Socket 的狀態
請按照以下步驟確認埠 15001、15006 和 15008 上的 socket 是開啟且處於監聽狀態。
$ kubectl debug $(kubectl get pod -l app=curl -n ambient-demo -o jsonpath='{.items[0].metadata.name}') -it -n ambient-demo --image nicolaka/netshoot -- ss -ntlp
Defaulting debug container name to debugger-nhd4d.
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 128 127.0.0.1:15080 0.0.0.0:*
LISTEN 0 128 *:15006 *:*
LISTEN 0 128 *:15001 *:*
LISTEN 0 128 *:15008 *:*
檢查 iptables 規則設定
若要檢視在其中一個應用程式 Pod 內設定的 iptables 規則,請執行此命令:
$ kubectl debug $(kubectl get pod -l app=curl -n ambient-demo -o jsonpath='{.items[0].metadata.name}') -it --image gcr.io/istio-release/base --profile=netadmin -n ambient-demo -- iptables-save
Defaulting debug container name to debugger-m44qc.
# Generated by iptables-save
*mangle
:PREROUTING ACCEPT [320:53261]
:INPUT ACCEPT [23753:267657744]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [23352:134432712]
:POSTROUTING ACCEPT [23352:134432712]
:ISTIO_OUTPUT - [0:0]
:ISTIO_PRERT - [0:0]
-A PREROUTING -j ISTIO_PRERT
-A OUTPUT -j ISTIO_OUTPUT
-A ISTIO_OUTPUT -m connmark --mark 0x111/0xfff -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
-A ISTIO_PRERT -m mark --mark 0x539/0xfff -j CONNMARK --set-xmark 0x111/0xfff
-A ISTIO_PRERT -s 169.254.7.127/32 -p tcp -m tcp -j ACCEPT
-A ISTIO_PRERT ! -d 127.0.0.1/32 -i lo -p tcp -j ACCEPT
-A ISTIO_PRERT -p tcp -m tcp --dport 15008 -m mark ! --mark 0x539/0xfff -j TPROXY --on-port 15008 --on-ip 0.0.0.0 --tproxy-mark 0x111/0xfff
-A ISTIO_PRERT -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ISTIO_PRERT ! -d 127.0.0.1/32 -p tcp -m mark ! --mark 0x539/0xfff -j TPROXY --on-port 15006 --on-ip 0.0.0.0 --tproxy-mark 0x111/0xfff
COMMIT
# Completed
# Generated by iptables-save
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [175:13694]
:POSTROUTING ACCEPT [205:15494]
:ISTIO_OUTPUT - [0:0]
-A OUTPUT -j ISTIO_OUTPUT
-A ISTIO_OUTPUT -d 169.254.7.127/32 -p tcp -m tcp -j ACCEPT
-A ISTIO_OUTPUT -p tcp -m mark --mark 0x111/0xfff -j ACCEPT
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -j ACCEPT
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -p tcp -m mark ! --mark 0x539/0xfff -j REDIRECT --to-ports 15001
COMMIT
命令輸出顯示,在應用程式 Pod 網路命名空間內的 netfilter/iptables 中,已將其他特定於 Istio 的鏈加入 NAT 和 Mangle 表中。所有進入 Pod 的 TCP 流量都會重新導向到 ztunnel 代理程式以進行輸入處理。如果流量是純文字 (來源埠 != 15008),則會重新導向到 Pod 內的 ztunnel 純文字監聽埠 15006。如果流量是 HBONE (來源埠 == 15008),則會重新導向到 Pod 內的 ztunnel HBONE 監聽埠 15008。任何離開 Pod 的 TCP 流量都會重新導向到 ztunnel 的埠 15001 以進行輸出處理,然後由 ztunnel 使用 HBONE 封裝傳送出去。