开篇

Istio 流量劫持的文章其实目前可以在servicemesher社区找到一篇非常详细的文章,可查阅:Istio 中的 Sidecar 注入及透明流量劫持过程详解。特别是博主整理的那张“流量劫持示意图”,已经可以很清晰的看出来劫持流程。这里我借着那张图片解释一版该图片的文字版本。在开始文字版前如果对iptables命令如果不是非常了解的话建议先重点看下下面的两篇文章,深入浅出的解释了该命令的概念及用法:

  1. iptables概念 - 以通俗易懂的方式描述iptables的相关概念
  2. iptables指南 - iptables命令用法指南

这里引用iptables的一张报文流向图(版权归原博主所有)

当客户端访问服务器的web服务时,客户端发送报文到网卡,而tcp/ip协议栈是属于内核的一部分,所以,客户端的信息会通过内核的TCP协议传输到用户空间中的web服务中,而此时,客户端报文的目标终点为web服务所监听的套接字(IP:Port)上,当web服务需要响应客户端请求时,web服务发出的响应报文的目标终点则为客户端,这个时候,web服务所监听的IP与端口反而变成了原点。 -- 引用自 zsythink

上面这部分描述相当重要,它是理解sidecar在进行流量劫持的基础之一。

下面我们分析下昨天istio-init启动时执行的istio-iptables命令

nsenter -t 8533 -n iptables -t nat -S

# 默认
# 为PREROUTING/INPUT/OUTPUT/POSTROUTING链设置策略为接收数据包(ACCEPT)
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT # 自定义4个istio的规则链
-N ISTIO_INBOUND
-N ISTIO_IN_REDIRECT
-N ISTIO_OUTPUT
-N ISTIO_REDIRECT # 进入PREROUTING链tcp协议请求全部定向至 ISTIO_INBOUND 自定义链进行规则匹配
-A PREROUTING -p tcp -j ISTIO_INBOUND
# 进入OUTPUT链tcp协议请求全部定向至 ISTIO_OUTPUT 自定义链进行规则匹配
-A OUTPUT -p tcp -j ISTIO_OUTPUT # 入口
# tcp协议请求且请求端口为22/15090/15021/15020的请求停止执行当前链中的后续Rules,并执行下一个链
-A ISTIO_INBOUND -p tcp -m tcp --dport 22 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15090 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15021 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15020 -j RETURN
# tcp协议且端口不是22/15090/15021/15020的请求全部定向至 ISTIO_IN_REDIRECT
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
# 将重定向于此的tcp协议请求流量全部重定向至15006端口(envoy入口流量端口)
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006 # 出口
# 源IP地址为localhost且数据包出口为 ”lo“ 的流量都返回到它的调用点中的下一条链执行(1)
-A ISTIO_OUTPUT -s 127.0.0.6/32 -o lo -j RETURN
# 目的地非localhost,数据包出口为 ”lo“,是istio-proxy用户的流量转发至 ISTIO_REDIRECT (2)
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
# 数据包出口为 ”lo“,非istio-proxy用户的流量都返回到它的调用点中的下一条链执行(1)
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
# istio-proxy 用户的流量都返回到它的调用点中的下一条链执行
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
# 目的地非localhost,数据包出口为 ”lo“,是istio-proxy用户组的流量转发至 ISTIO_REDIRECT(2)
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
# 数据包出口为 ”lo“ 且非istio-proxy用户组流量都返回到它的调用点中的下一条链执行(1)
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
# 到 istio-proxy 用户组的流量都返回到它的调用点中的下一条链执行(1)
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
# 所有目的地为localhost的流量都返回到它的调用点中的下一条链执行(1)
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
# 其他不满足上述rules的流量全部转发到 ISTIO_REDIRECT (2)
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
# 将重定向于此的tcp协议请求流量全部重定向至15001端口(envoy出口流量端口)
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001

-m = --match. istio-proxy 用户身份运行, uid-owner 1337 为用户ID / gid-owner 1337 为用户组,即 sidecar 所处的用户空间,这也是 istio- proxy 容器默认使用的用户。

注意文中打括号的地方

(1) 代表流量会直接执行下一个拦截链,本文中下一个拦截链为POSTROUTING

(2) 代表流量会被重定向至envoy出口流量端口

根据上面的规则小结一下:

ISTIO_INBOUND 链:所有进入Pod但非指定端口(如22)的流量全部重定向至15006端口(envoy入口流量端口)进行拦截处理。

ISTIO_OUTPUT 链:所有流出Pod由 istio-proxy 用户空间发出且目的地不为localhost的流量全部重定向至15001端口(envoy出口流量端口),其他流量全部直接放行至下一个POSTROUTING链,不用被envoy拦截处理。

其实仔细思考下可以看到,流量拦截主要发生在两个地方:

  1. 用户请求到达Pod时对应流量会被拦截至sidecar进行处理,由sidecar请求业务服务
  2. 当业务服务响应用户请求时该响应再次被拦截至sidecar,由sidecar响应用户

再看下iptables nat 表的规则

nsenter -t 8533 -n iptables -t nat -L -v

Chain PREROUTING (policy ACCEPT 3435 packets, 206K bytes)
pkts bytes target prot opt in out source destination
3435 206K ISTIO_INBOUND tcp -- any any anywhere anywhere (1) Chain INPUT (policy ACCEPT 3435 packets, 206K bytes) (5)
pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 599 packets, 54757 bytes)
pkts bytes target prot opt in out source destination
22 1320 ISTIO_OUTPUT tcp -- any any anywhere anywhere Chain POSTROUTING (policy ACCEPT 599 packets, 54757 bytes) (8)
pkts bytes target prot opt in out source destination Chain ISTIO_INBOUND (1 references) (2)
pkts bytes target prot opt in out source destination
0 0 RETURN tcp -- any any anywhere anywhere tcp dpt:22
1 60 RETURN tcp -- any any anywhere anywhere tcp dpt:15090
3434 206K RETURN tcp -- any any anywhere anywhere tcp dpt:15021
0 0 RETURN tcp -- any any anywhere anywhere tcp dpt:15020
0 0 ISTIO_IN_REDIRECT tcp -- any any anywhere anywhere (3) Chain ISTIO_IN_REDIRECT (3 references)
pkts bytes target prot opt in out source destination
0 0 REDIRECT tcp -- any any anywhere anywhere redir ports 15006 (4) Chain ISTIO_OUTPUT (1 references) (6)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- any lo 127.0.0.6 anywhere
0 0 ISTIO_IN_REDIRECT all -- any lo anywhere !localhost owner UID match 1337
0 0 RETURN all -- any lo anywhere anywhere ! owner UID match 1337
22 1320 RETURN all -- any any anywhere anywhere owner UID match 1337
0 0 ISTIO_IN_REDIRECT all -- any lo anywhere !localhost owner GID match 1337
0 0 RETURN all -- any lo anywhere anywhere ! owner GID match 1337
0 0 RETURN all -- any any anywhere anywhere owner GID match 1337
0 0 RETURN all -- any any anywhere localhost
0 0 ISTIO_REDIRECT all -- any any anywhere anywhere Chain ISTIO_REDIRECT (1 references)
pkts bytes target prot opt in out source destination
0 0 REDIRECT tcp -- any any anywhere anywhere redir ports 15001

让我们一起再来仔细看下面这个图片,同步观察上面iptables chain的规则。这里的分析主要针对红色的数字一对一解释:

  1. productpage 服务对reviews 服务发送 TCP 连接请求
  2. 请求进入reviews服务所在Pod内核空间,被netfilter拦截入口流量,经过PREROUTING链然后转发至ISTIO_INBOUND
  3. 在被ISTIO_INBOUND链被这个规则-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT拦截再次转发至ISTIO_IN_REDIRECT
  4. ISTIO_IN_REDIRECT链直接重定向至 envoy监听的 15006 入口流量端口
  5. 在 envoy 内部经过一系列入口流量治理动作后,发出TCP连接请求 reviews 服务,这一步对envoy来说属于出口流量,会被netfilter拦截转发至出口流量OUTPUT
  6. OUTPUT链转发流量至ISTIO_OUTPUT
  7. 目的地为localhost,不能匹配到转发规则链,直接RETURN到下一个链,即POSTROUTING
  8. sidecar发出的请求到达reviews服务9080端口
  9. reviews服务处理完业务逻辑后响应sidecar,这一步对reviews服务来说属于出口流量,再次被netfilter拦截转发至出口流量OUTPUT
  10. OUTPUT链转发流量至ISTIO_OUTPUT
  11. 发送非localhost请求且为istio-proxy用户空间的流量被转发至 ISTIO_REDIRECT
  12. ISTIO_REDIRECT链直接重定向至 envoy监听的 15001 出口流量端口
  13. 在 envoy 内部经过一系列出口流量治理动作后继续发送响应数据,响应时又会被netfilter拦截转发至出口流量OUTPUT
  14. OUTPUT链转发流量至ISTIO_OUTPUT
  15. 流量直接RETURN到下一个链,即POSTROUTING

针对上文其实我还有两个疑问点,还请大家不吝指教:

  • 上面的理解没有写第16点,博主的图中的16点还会再进 ISTIO_REDIRECT链,我们可以看到 ISTIO_REDIRECT链中只有一个改写端口转发的规则,这样岂不是会进入一个死循环?或者是我还没有理解清楚
  • envoy 转发流量是不是自己新建立的tcp 连接请求还是通过修改请求报文地址来实现的。因为对c++了解有限,无法查阅其源码去一探究竟

从整个流量拦截流程大家也可以看出,路径这么长, 在大并发场景下肯定会损失转发性能。目前业界有一些框架在试着缩短这个拦截路径,让大家拭目以待吧。

参考文献

https://www.servicemesher.com/blog/sidecar-injection-iptables-and-traffic-routing/

https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html#REDIRECTTARGET

http://www.zsythink.net/archives/1199

Istio 流量劫持过程的更多相关文章

  1. 如何使用HTTPS防止流量劫持

    何为流量劫持 前不久小米等六家互联网公司发表联合声明,呼吁运营商打击流量劫持.流量劫持最直观的表现,就是网页上被插入了一些乱七八糟的广告/弹窗之类的内容.比如这样: 网页右下角被插入了游戏的广告. 流 ...

  2. 拒绝流量劫持,全面使用 HTTPS!

    最近收到数个 BootCDN 用户的反馈:某些地区的宽带运营商劫持了部分 BootCDN 上的文件,并篡改文件加入了广告代码. 这种方式的流量劫持属于中间人攻击(Man-in-the-Middle A ...

  3. 【流量劫持】躲避 HSTS 的 HTTPS 劫持

    前言 HSTS 的出现,对 HTTPS 劫持带来莫大的挑战. 不过,HSTS 也不是万能的,它只能解决 SSLStrip 这类劫持方式.但仔细想想,SSLStrip 这种算劫持吗? 劫持 vs 钓鱼 ...

  4. 【流量劫持】SSLStrip 的未来 —— HTTPS 前端劫持

    前言 在之前介绍的流量劫持文章里,曾提到一种『HTTPS 向下降级』的方案 -- 将页面中的 HTTPS 超链接全都替换成 HTTP 版本,让用户始终以明文的形式进行通信. 看到这,也许大家都会想到一 ...

  5. WiFi流量劫持—— JS脚本缓存投毒

    在上一篇<WiFi流量劫持—— 浏览任意页面即可中毒>构思了一个时光机原型,让我们的脚本通过HTTP缓存机制,在未来的某个时刻被执行,因此我们可以实现超大范围的入侵了. 基于此原理,我们用 ...

  6. htaccess文件还可以被用来把访问网站的流量劫持到黑客的网站

    看是否有文件上传操作(POST方法), IPREMOVED--[01/Mar/2013:06:16:48-0600]"POST/uploads/monthly_10_2012/view.ph ...

  7. HTTPS-能否避免流量劫持

    流量劫持是什么? EtherDream在一篇科普文章<>中详细介绍了流量劫持途径和方式. 流量劫持是一种古老的攻击方式,比如早已见惯的广告弹窗等,很多人已经对此麻木,并认为流量劫持不会造成 ...

  8. 关于全站https必要性http流量劫持、dns劫持等相关技术

    关于全站https必要性http流量劫持.dns劫持等相关技术 微信已经要求微信支付,申请退款功能必须12月7号之前必须使用https证书了(其他目前为建议使用https),IOS也是2017年1月1 ...

  9. Linux-某电商网站流量劫持案例分析与思考

    [前言] 自腾讯与京东建立了战略合作关系之后,笔者网上购物就首选京东了.某天在家里访问京东首页的时候突然吃惊地发现浏览器突然跳到了第三方网站再回到京东,心里第一个反应就是中木马了. 竟然有这样的事,一 ...

随机推荐

  1. TensorFlow实现时间序列预测

    常常会碰到各种各样时间序列预测问题,如商场人流量的预测.商品价格的预测.股价的预测,等等.TensorFlow新引入了一个TensorFlow Time Series库(以下简称为TFTS),它可以帮 ...

  2. php扩展开发之hello world

    最近在公司做的事情就是php扩展开发,虽然我只负责c++代码的编写,但是了解扩展开发的流程还是很有必要的. (本文介绍的是动态扩展,对静态扩展有兴趣的读者可自行google) php扩展开发环境搭建可 ...

  3. 前端——localStorage详细总结

    一.localStorage简介: 在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的,解决了cookie存储空间不足的问题(cookie中每条cooki ...

  4. 前端【JS】,深拷贝与浅拷贝的区别及详解!

    我是前端小白一枚,为了巩固知识和增强记忆,开始整理相关的知识,方便以后复习和面试的时候看看.OK,让我们进入正题~ 先说说浅拷贝和深拷贝的理解吧,个人是这样理解的:两个对象A.B, A有数据B为空,B ...

  5. 深入理解JS中的对象(一)

    目录 一切皆是对象吗? 对象 原型与原型链 构造函数 参考 1.一切皆是对象吗? 首先,"在 JavaScript 中,一切皆是对象"这种表述是不完全正确的. JavaScript ...

  6. 中文分词工具简介与安装教程(jieba、nlpir、hanlp、pkuseg、foolnltk、snownlp、thulac)

    2.1 jieba 2.1.1 jieba简介 Jieba中文含义结巴,jieba库是目前做的最好的python分词组件.首先它的安装十分便捷,只需要使用pip安装:其次,它不需要另外下载其它的数据包 ...

  7. jquery判断邮箱及密码是否输入正确的表单提交

    jquery我接触的也不是很多,基本就是照着案例然后查相关方法做出来的,基本用了大概半天的时间,手打加查资料实现.具体如下,首先下载一个jquery包,网址是https://jquery.com/do ...

  8. 计算机组成及系统结构-第十章 输入输出(I/O)系统

    输入输出(I/O)系统 一.概述 1.输入输出设备的编址 2.设备控制器(I/O接口)的基本功能 3.I/O设备数据传送控制方式 二.程序中断输入输出方式 1.中断的定义 2.中断的作用 3.中断的产 ...

  9. angular js 页面添加数据保存数据库

    一.编写实体类Controller层返回数据使用 package entity; import java.io.Serializable; public class Result implements ...

  10. VMware Centos7 NAT 无法上网的解决方法

    问题描述: VMware下CentOS7使用NAT上网方式无法连网 解决方案: 网络设置为DHCP自动获取IP 查看主机(不是虚拟机)的相关服务是否打开,主要是VMware DHCP 和VMware ...