Envoy透明代理流量劫持部署与调试 - 第3节

3.1 流量劫持基础概念

流量劫持(Traffic Hijacking)是云原生服务网格与透明代理体系中的核心机制。它指在不修改应用代码的前提下,通过操作系统或网络层的拦截手段,将原本发往目标地址的网络数据包重定向到代理进程(如 Envoy)的监听端口,从而实现对流量的拦截、观测、路由与策略执行。

核心目标:让应用无感知地接入代理层,实现零侵入的服务治理。

3.1.1 流量劫持的典型场景

  • 入站劫持(Inbound Hijack):将到达 Pod/VM 的入站请求重定向到 Envoy 的入站监听器(通常为 15006 端口)。
  • 出站劫持(Outbound Hijack):将应用进程发出的出站连接重定向到 Envoy 的出站监听器(通常为 15001 端口)。
  • DNS 劫持:将 DNS 查询重定向到 Envoy 的 DNS 代理,实现基于服务名的路由。
注意:Envoy 本身不执行数据包重定向操作,它依赖操作系统底层机制(如 iptables、eBPF、tproxy)完成劫持,Envoy 只负责接收被重定向过来的流量。
流量劫持核心流程 应用进程 (无感知) iptables 劫持层 NAT / REDIRECT / TPROXY Envoy 代理 15001 / 15006 端口 原始数据包 重定向后 目标服务 (上游) 转发 关键点:应用进程只感知到目标 IP:Port,实际连接被 iptables 规则透明地重定向到 Envoy 监听端口。 Envoy 完成策略执行后,再与真实目标建立新连接。

3.2 透明代理与显式代理的区别

在代理架构中,透明代理(Transparent Proxy)与显式代理(Explicit Proxy)是两种截然不同的工作模式。Envoy 在服务网格场景下主要采用透明代理模式。

对比维度 透明代理 显式代理
应用感知 应用完全无感知,无需任何配置 应用必须显式配置代理地址(如 HTTP_PROXY 环境变量)
劫持方式 通过 iptables / eBPF 等内核机制重定向流量 应用主动将请求发送给代理服务器
目标地址可见性 代理可以获取原始目标 IP:Port(通过 SO_ORIGINAL_DST 或 TPROXY) 代理从请求头(如 HTTP Host)或 CONNECT 方法中获取目标
协议支持 支持 TCP/UDP 全协议(四层透明) 通常只支持 HTTP/HTTPS(七层代理)
配置复杂度 需要配置 iptables 规则,对运维要求较高 只需在应用中配置代理地址,部署简单
典型场景 服务网格 Sidecar、透明网关 企业正向代理、浏览器代理设置
重要:Envoy 在 Istio/服务网格中作为 Sidecar 运行时,必须使用透明代理模式。因为微服务应用(如 Java、Go、Python 服务)通常不会主动配置代理,透明劫持是实现零侵入服务治理的唯一可行方式。

3.2.1 透明代理的核心挑战

  • 原始目标地址获取:被 iptables REDIRECT 的目标地址会被替换为本机地址,Envoy 需要通过 SO_ORIGINAL_DST 套接字选项获取原始目标。
  • 环路避免:Envoy 发出的连接必须绕过劫持规则,否则会形成无限递归(Envoy 发出的包又被劫持回自身)。
  • UDP 透明代理:UDP 无连接特性使得劫持更加复杂,通常需要 TPROXY 模式支持。
透明代理 vs 显式代理 工作模式对比 透明代理模式 应用 (无配置) iptables 透明劫持 Envoy 代理 显式代理模式 应用 (配置代理地址) 显式代理 HTTP CONNECT 目标服务器

3.3 iptables 基础回顾

iptables 是 Linux 内核的包过滤框架,也是 Envoy 透明代理劫持中最常用的底层工具。理解 iptables 的表(Table)、链(Chain)和规则(Rule)是配置透明代理的前提。

3.3.1 核心概念

概念 说明 透明代理相关
表(Table) 按功能分类:filter(过滤)、nat(地址转换)、mangle(修改)、raw(原始包) nat 表用于 REDIRECT/TPROXY;mangle 表用于标记连接
链(Chain) 数据包在内核中的检查点:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING PREROUTING(入站劫持)、OUTPUT(出站劫持)
规则(Rule) 匹配条件 + 动作(-j TARGET),按顺序逐条匹配 -j REDIRECT / -j TPROXY / -j ACCEPT / -j RETURN
匹配条件 -p 协议、--dport 目标端口、-s 源地址、-d 目标地址、-m owner(进程所有者) -m owner --uid-owner 匹配 Sidecar 用户,用于排除 Envoy 自身流量

3.3.2 透明代理中的关键 iptables 动作

  • REDIRECT:将目标端口重定向到本机另一个端口。仅支持 TCP,且会丢失原始目标地址(需通过 SO_ORIGINAL_DST 恢复)。
  • TPROXY:透明代理专用动作,支持 TCP 和 UDP,保留原始目标地址,无需特殊套接字选项。需要策略路由配合。
  • DNAT:修改目标地址,可用于将流量导向 Envoy 所在节点。
  • RETURN:跳过当前链的后续规则,用于排除特定流量(如 Envoy 自身发出的包)。

3.3.3 典型劫持规则示例

# 1. 创建自定义链,便于管理
iptables -t nat -N ISTIO_INBOUND
iptables -t nat -N ISTIO_OUTBOUND

# 2. 入站劫持:将非 localhost 的入站 TCP 流量重定向到 15006
iptables -t nat -A PREROUTING -p tcp -j ISTIO_INBOUND
iptables -t nat -A ISTIO_INBOUND -p tcp --dport 80 -j REDIRECT --to-port 15006

# 3. 出站劫持:将应用发出的 TCP 流量重定向到 15001
iptables -t nat -A OUTPUT -p tcp -j ISTIO_OUTBOUND
# 排除 Envoy 自身流量(假设 Envoy 以 uid 1337 运行)
iptables -t nat -A ISTIO_OUTBOUND -m owner --uid-owner 1337 -j RETURN
# 排除保留地址和已建立的连接
iptables -t nat -A ISTIO_OUTBOUND -d 127.0.0.1/8 -j RETURN
iptables -t nat -A ISTIO_OUTBOUND -m state --state ESTABLISHED -j RETURN
# 重定向剩余出站流量
iptables -t nat -A ISTIO_OUTBOUND -p tcp -j REDIRECT --to-port 15001
实践建议:在生产环境中,建议使用 iptables-save 和 iptables-restore 批量管理规则,避免逐条添加带来的性能开销和原子性问题。Istio 的 istio-iptables.sh 脚本就是基于此原理实现。

3.3.4 环路避免机制

透明代理配置中最容易出现的错误是劫持环路(Hijack Loop):Envoy 发出的数据包又被 iptables 规则重定向回自身。标准解决方案如下:

方法 实现方式 优点 缺点
UID 排除 使用 -m owner --uid-owner 匹配 Envoy 进程的用户 ID,执行 RETURN 简单可靠,最常用 需要确保 Envoy 以独立用户运行
GID 排除 使用 -m owner --gid-owner 匹配 Envoy 进程的组 ID 适合容器场景 组 ID 可能被共享
端口排除 排除 Envoy 监听端口(如 15001、15006)的出站流量 不依赖进程信息 端口可能被其他进程占用
连接标记 在 mangle 表中为 Envoy 发出的连接打标记,在 nat 表中跳过 精细控制 配置复杂,多表联动
避坑指南:如果忘记配置环路避免规则,Envoy 启动后会出现连接超时或 CPU 飙升。排查方法:在 Envoy 节点上执行 iptables -t nat -L -n -v 查看计数器,如果 OUTPUT 链的 REDIRECT 规则计数远大于预期,说明存在环路。