Ztunnel 流量重定向
在环境模式的上下文中,流量重定向 指的是数据平面功能,该功能会拦截发送到和从启用环境模式的工作负载发出的流量,并将其通过处理核心数据路径的 ztunnel 节点代理路由。
由于 ztunnel 旨在透明地加密和路由应用程序流量,因此需要一种机制来捕获进入和离开“网格内”吊舱的所有流量。这是一个安全关键任务:如果可以绕过 ztunnel,则可以绕过授权策略。
Istio 的吊舱内流量重定向模型
环境模式下,ztunnel 代理能够在工作负载 Pod 的 Linux 网络命名空间内捕获数据路径,这是环境模式流量重定向的核心设计原则。该功能是通过 istio-cni
节点代理 与 ztunnel 节点代理之间的协作实现的。这种模式的一个关键优势是它使 Istio 的环境模式能够透明地与任何 Kubernetes CNI 插件并行工作,而不会影响 Kubernetes 网络功能。
下图展示了在启用环境模式的命名空间中启动(或添加到)新的工作负载 Pod 时事件的顺序。
istio-cni
节点代理响应 CNI 事件,例如 Pod 创建和删除,并监控底层 Kubernetes API 服务器以获取事件,例如将环境标签添加到 Pod 或命名空间。
istio-cni
节点代理还会安装一个链式 CNI 插件,该插件在 Kubernetes 集群中主要 CNI 插件执行后由容器运行时执行。它的唯一目的是在容器运行时在已注册环境模式的命名空间中创建新的 Pod 时通知 istio-cni
节点代理,并将新 Pod 上下文传播到 istio-cni
。
一旦 istio-cni
节点代理收到需要将 Pod 添加到网格的通知(无论是来自 CNI 插件,如果是全新的 Pod,还是来自 Kubernetes API 服务器,如果是正在运行但需要添加的 Pod),它将执行以下操作序列
istio-cni
进入 Pod 的网络命名空间并建立网络重定向规则,以便进入和离开 Pod 的数据包被拦截并透明地重定向到监听 知名端口 (15008、15006、15001) 的节点本地 ztunnel 代理实例。然后,
istio-cni
节点代理通过 Unix 域套接字通知 ztunnel 代理,它应该在 Pod 的网络命名空间内(端口 15008、15006 和 15001 上)建立本地代理监听端口,并向 ztunnel 提供一个表示 Pod 网络命名空间的低级 Linux 文件描述符。- 虽然套接字通常是在 Linux 网络命名空间中由实际在该命名空间中运行的进程创建的,但完全可以利用 Linux 的低级套接字 API 允许在另一个网络命名空间中运行的进程在另一个网络命名空间中创建监听套接字,前提是在创建时已知目标网络命名空间。
节点本地 ztunnel 在内部启动一个新的代理实例和监听端口集,专门用于新添加的 Pod。
一旦 Pod 内的重定向规则到位,并且 ztunnel 建立了监听端口,Pod 就会被添加到网格中,并且流量开始通过节点本地 ztunnel 流动。
默认情况下,进出网格中 Pod 的流量将使用 mTLS 进行完全加密。
现在数据将以加密形式进入和离开 Pod 网络命名空间。网格中的每个 Pod 都能够执行网格策略并安全地加密流量,即使 Pod 中运行的用户应用程序对此一无所知。
该图展示了加密流量在新的模型中如何进出环境网格中的 Pod。
观察和调试环境模式下的流量重定向
如果环境模式中的流量重定向工作不正常,可以进行一些快速检查以帮助缩小问题范围。我们建议从 ztunnel 调试指南 中描述的步骤开始进行故障排除。
检查 ztunnel 代理日志
当应用程序 Pod 是环境网格的一部分时,您可以检查 ztunnel 代理日志以确认网格正在重定向流量。如下面的示例所示,与 inpod
相关的 ztunnel 日志表明启用了 Pod 内重定向模式,代理已收到有关环境应用程序 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
确认套接字的状态
按照以下步骤确认端口 15001、15006 和 15008 上的套接字已打开并处于监听状态。
$ 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 中的 NAT 和 Mangle 表中添加了额外的 Istio 特定链。进入 Pod 的所有 TCP 流量都被重定向到 ztunnel 代理以进行入站处理。如果流量是明文(源端口 != 15008),它将被重定向到 Pod 内的 ztunnel 明文监听端口 15006。如果流量是 HBONE(源端口 == 15008),它将被重定向到 Pod 内的 ztunnel HBONE 监听端口 15008。离开 Pod 的任何 TCP 流量都会被重定向到 ztunnel 的端口 15001 以进行出站处理,然后由 ztunnel 使用 HBONE 封装发送出去。