通过envoy实现透明代理

什么是透明代理

透明代理的意思是客户端根本不需要知道有代理服务器的存在,它改变你的请求报文,并会转发至真实I服务器。

为什么需要透明代理

案例1监控某个应用,甄别非法返回值。案例2对应用的url进行鉴权,让不合法的url实现跳转。以上两个案例如果按照传统做法肯定要在特定应用中的http请求管道中增加filter,拦截请求和响应报文,这种做法侵入性太强,如果应用比较多,又是由不同的语言开发的,想完成它是一件比较困难的事情,做的不好还可能影响到原有业务逻辑。这个时候透明代理就显得尤为重要:进程外架构,语言无关性,流量透明化,完全契合了现阶段火热的服务网格的理念,是解决同类问题的最佳方式。

实现透明代理的选择-Envoy

Envoy是一个现代的为面向服务架构而设计的七层代理和通讯总线,该项目的设计初衷是:对于应用程序而言,网络应该是透明的,当发生网络和应用程序故障时,能够很容易定位出问题的根源。Envoy 的核心是一个 L3/L4 网络代理,结合防火墙技术就可以充当一个透明代理,拦截入栈和出栈流量,实现完美定制网络流量和应用。

Envoy实现透明代理的两种方式

为了更好的对比流量拦截前后,连接的建立方式,我们首先远程请求10.1.44.202:8001,连接状态如下:

1、redirect利用以下命令更改防火墙规则

#!/bin/bashiptables -t nat -A PREROUTING -p tcp --dport 8001 -j REDIRECT --to-ports 15001iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner 1000 -j RETURN

该命令生效后会把所有8001端口的流量转发到15001端口,用户标识为1000的出口流量不做拦截,否则会出现流量在iptables中循环,不过超过固定次数后流量会被自动抛弃(未验证多少次),此时再次请求10.1.44.202:8001,连接状态如下:

从连接状态上可以看出,从10.1.44.91向10.1.44.202:8001发起的请求不再直接和8001端口建立连接而是和15001端口建立了连接,客户端对此毫无察觉。

流量被拦截到15001之后,我们就可以通过envoy的filter机制对http请求定制和转发,此时的envoy配置文件如下:

envoy.listener.original_dst

           根据iptables转换之前的dst port,查找到真实的Listener,查找到Listener会根据新的Listener的配置继续处理,如果未找到匹配的Listener,将匹配0.0.0.0+端口的Listener,如果仍未找到则直接转发至cluster-default集群

original_dst cluster

           根据iptable转换之前的ip port直接转发,必须和负载均衡策略ORIGINAL_DST_LB配合使用该模式的优点是拦截方式相对简单,缺点是服务端看不到客户端ip

2、tproxy

tproxy允许"模仿"用户的访问ip,就像proxy不存在一样,后端看到的是真实的客户端ip地址,我们可以利用以下命令更改防火墙规则

#!/bin/bashiptables -t mangle -A PREROUTING ! -d 127.0.0.1/32 -p tcp --dport 8001 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 15001ip rule add fwmark 1 lookup 100ip route add local 0.0.0.0/0 dev lo table 100

上面的脚本目的是为了让所有进入网桥设备的mangle表的包都打上标记,通过高级路由规则将这些打了标记的数据包发送至本地回环接口进行处理。

我们从客户端10.1.44.91发起浏览器请求:8001/sz/basic/cityrouterequest

此时的连接状态如下:

从连接状态中可以发现10.1.44.91和10.1.44.202直接建立了连接,代理完全透明化了。

envoy配置如下

transparent选项设置之后可以bind一个不属于本机的IP地址,作为客户端,它可以使用一个不属于本机地址的IP地址作为源IP发起连接,作为服务端,它可以侦听在一个不属于本机的IP地址

总结

通过以上两种模式的对比,第二种模式使网络更加透明,方便问题跟踪和排查,推荐。现阶段比较火热的服务网格就是通过上面的原理来实现流量劫持和流量转发的,我们可以通过修改防火墙规则拦截入口和出口流量,再通过envoy的动态配置功能实现服务网格的数据面板和控制面板,这部分的实现可以参考istio。

参考文献

https://www.envoyproxy.io/docs/envoy/v1.14.1/configuration/listeners/listener_filters/original_dst_filter

https://www.kernel.org/doc/Documentation/networking/tproxy.txt