【IstioCon 2021】如何在Istio中进行源地址保持?

【IstioCon 2021】如何在Istio中进行源地址保持?

北京时间2月23日,在全球首届社区峰会IstioCon 2021中,华为云原生开源团队核心成员徐中虎发表了《Preserve Original Source Address within Istio》主题演讲。

演讲主要包含三部分的内容:

  • 源地址的使用场景
  • 常用的源地址保持方式
  • Istio源地址保持的方案

源地址的使用场景

源地址使用场景多种多样,比如说:

1)简单的会话保持,可以根据客户端的地址,基于源IP做负载均衡,将来自同一个客户端的请求,转发到同一个服务实例;

2)用于安全策略控制,常用的黑白名单设置;

3)访问日志和监控统计,访问日志和监控指标中包含真实的源地址,有助于开发人员分析和Debug;

4)IP电话(VoIP)和流媒体服务的典型代表技术SIP中继链接是一种基于IP地址区分用户的方式,源IP地址对于SIP来说至关重要。

我们可以看到不同的技术场景对源IP的依赖程度不一,对于某些强依赖的场景,如果不能实现源地址的保持,那么Istio则不能应用于此场景。


常见的源IP保持方式及背景知识

在Istio等服务网格技术出现以前,典型的服务访问模型如图所示。开发者一般将应用服务部署在企业负载均衡设备后面,以应对高并发、高可用的需求。企业通过负载均衡设备提供服务的统一访问入口,常见的负载均衡设备有硬件负载均衡F5,软件负载均衡LVS、HaProxy、Nginx等。不同负载均衡器提供的源IP地址保持的方式不尽相同。

我们常用的源IP保持的方式从OSI网络模型L3-L7主要分为:


1. L3

LVS,是内核层的软负载,从原理上看属于一次连接,性能属于软负载中最高的,也是业界使用最为广泛的L3负载均衡器。LVS工作模型有NAT模式、DR模式、隧道模式。我们主要基于NAT模式看一下LVS的源地址保持。

(1)当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。此时报文的源IP为CIP,目标IP为VIP。

(2) PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链, LVS主要工作在INPUT链。

(3) IPVS比对数据包请求的服务是否为集群服务,若是,修改数据包的目标IP地址为后端服务器IP,然后将数据包发至POSTROUTING链。此时报文的源IP为CIP,目标IP为RIP ,在这个过程完成了目标IP的转换(DNAT),而源地址始终没变。

(4) POSTROUTING链通过选路,将数据包发送给Real Server。

HAProxy透明传输模式也是一种L3层的源地址保持方式,但是它工作在用户空间,是典型的两次连接模型。1)用户首先与HAProxy建立一条连接,当用户请求到达HAProxy时,HAProxy获取客户端的IP地址。

2)HAProxy工作在透明传输模式下,根据负载均衡策略选择一个真实的后端服务,然后绑定客户端的IP地址,与后端服务建立新的连接。透明代理依赖socket的IP_TRANSPARENT

3)真实服务器响应数据包必须经过HAProxy代理,因此,透明传输还得依赖个性化路由的配置以及TPROXY。


2. L4

TOA, TOA插件是基于四层协议(TCP)获取真实源IP的方法,本质是将源IP地址插入TCP协议的Options字段。华为云提供了TOA插件,用户只要在在内核中安装TOA模块,在使用时即可以系统调用的方式获取源IP地址。


Proxy Protocol是另外一种四层的源地址保持方式,协议标准最早由HAProxy社区发展而来。其工作原理特别简单,要求客户端在TCP连接建立之后,应用数据发送之前,首先发送一个Proxy Protocol协议头,服务器通过解析协议头获取真实的客户端IP地址。Proxy Protocol标准要求客户端和服务端同时支持代理协议。这里Client在真实世界中可以是Envoy、HAProxy、Nginx等支持代理协议的负载均衡器。

3. L7

七层源地址保持的方式相对而言最为简单,最具代表性的是HTTP头x-forwarded-for,x-forwarded-for中可以包含原始用户的IP地址,高级语言HTTP库基本都能自动获取源地址。


另外,开发者可以自定义协议类型,将客户端的源IP地址塞到协议帧。


Istio源地址保持困境

我们从服务网格东西向和南北向分别来看一下,当前Istio服务网格中源地址获取的障碍。

1)服务网格东西向服务访问时,由于Sidecar的注入,所有进出服务的流量均被Envoy拦截代理,当svcA访问svcB时,svcB的Sidecar Envoy与svcB建立一条连接,源地址是127.0.0.1,目的地址也是127.0.0.1(未来是PodIP)。单纯从TCP通信的角度来看,svcB只能获取到客户端地址是127.0.0.1。

2)Istio南北向服务访问中,用户请求首先通过ELB服务代理转发到Istio的Ingress Gateway,然后Ingress Gateway再将请求负载均衡到真实的服务实例。由图中可见,中间经过的网络节点更多,同时包含ELB和Istio。源地址的保持更加困难。


如何在Istio服务网格中获取源地址

我们先来看一下Envoy中与源地址保持相关的基础能力,然后尝试借助这些基本能力实现Istio服务网格中端到端的源地址保持方案。


Envoy提供了两个监听器级别的过滤器:源地址过滤器(“envoy.filters.listener.original_src”)和代理协议过滤器(“envoy.filters.listener.proxy_protocol”)。


1)源地址过滤器作用在Envoy的Inbound监听器,其工作原理是获取下游连接的客户端地址,并以客户端地址为源地址与上游服务建立新的连接。本质上是IP_TRANSPARENT透明传输,这一点对TCP源地址的获取非常重要。前面我们介绍到透明传输还必须解决IP包回程的问题,这一点我们留在后面再讲。2)代理协议过滤器也作用于监听器,主要职责为解析Proxy Protocol协议,可在服务端获取源地址,特别适合Ingress服务源地址获取。3)Proxy Protocol Transport Socket,是Envoy与上游通过Proxy Protocol进行源IP保持的一种方式,其主要构造代理协议头,并主动发送给上游支持代理协议的服务。4)HTTP XFF(x-forwarded-for)自动注入,envoy可以根据LDS HTTP连接管理配置自动添加最近的下游客户端的IP地址到XFF中。

1. HTTP类协议源IP保持

那么可以看到,东西向七层HTTP类协议可以非常容易的通过添加XFF的方式,方便服务端获取客户端真实IP。其典型的配置如下:

Ingress服务访问场景,ELB提供的方案可以分为TOA和Proxy Protocol两种。在TOA模式下,必须在Ingress Gateway所在的节点安装TOA内核模块才能使Ingress Gateway获取原始客户端IP地址。在Proxy Protocol场景下,必须通过配置envoy.filters.listener.proxy_protocol 过滤器才能使Ingress Gateway获取真实客户IP。详细配置如下,当然使能此过滤器必须非常小心,前提是确保所有进入Ingress Gateway的流量一定是Proxy Protocol。

两种模式下,都需要配置Ingress gateway使其支持XFF自动添加, 另外可以通过xff_num_trusted_hops额外配置Envoy信任的代理跳数,详细参考envoyproxy.io/docs/envo

2. TCP源IP保持

Istio TCP源地址保持必须依赖透明传输和TPROXY,此特性直到Istio 1.9才由我提供了完整的支持。其使用方法也非常简单,用户只需设置Pod的Annotation 为sidecar.istio.io/interc TPROXY。

Istio主要通过以下配置确保svcB和Sidecar Envoy之间通过svcA的地址通信。

1)配置源地址过滤器,Envoy就能绑定下游客户端的地址(10.244.0.20)svcB建立连接。

2)配置TPROXY和个性化路由,确保svcB发送到10.244.0.20的数据包被Envoy接收。主要是对数据包打标记,然后根据自定义路由,将非本地的数据包通过本地lo路由。

-A PREROUTING -p tcp -m mark --mark 0x539 -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff

-A OUTPUT -p tcp -m connmark --mark 0x539 -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff

ip -f inet rule add fwmark 1337 lookup 133

ip -f inet route add local default dev lo table 133  

Ingress TCP源地址保持相对更复杂,理论上除以上规则外,需要额外增加Proxy Protocol协议的支持。在Ingress Gateway上配置Proxy Protocol,

在svcB上配置envoy.filters.listener.proxy_protocol,保证Envoy监听器获取原始客户端IP。

本文小结

源IP保持并不是一个新鲜的话题,然而我们在Istio服务网格中发现很多成熟的方案都黯然失效。说到底,这与Istio Sidecar的代理有莫大的关系,Istio Sidecar 自动注入直接导致了我们不能直接以个性化配置解决源地址保持的问题。而是要结合Istio的配置管理,实现统一的配置方案。

本文根据本人在IstioCon 2021的分享整理而来,相关的案例demo都可以在github.com/hzxuzhonghu/

找到,希望对大家有所启发。

欢迎点击下列链接关注容器魔方,我们将为你提供:

  • 我们每日更新关于云原生技术动态、实战进阶、应用案例等;
  • 入群与行业技术大牛,1万+云原生爱好者一起链接学习;
  • 不定期邀请云原生OG级技术大咖分享技术实战
  • …………
发布于 2021-03-23 11:14