51学通信论坛2017新版

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2470|回复: 0
打印 上一主题 下一主题

浅谈 Iptables 及其在 kubernetes 中的应用

[复制链接]

 成长值: 15613

  • TA的每日心情
    开心
    2022-7-17 17:50
  • 2444

    主题

    2544

    帖子

    7万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    74104
    跳转到指定楼层
    楼主
    发表于 2017-11-15 21:11:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    Iptables 是一个运行在用户空间的应用软件,通过控制 Linux 内核 netfilter 模块,来管理网络数据包的流动与转送。
    需要用到 ROOT 权限。OSI 模型的二、三、四层。
    主要功能

      防火墙
      NAT

    基本结构
    三个表

      nat:prerouting、output、postrouting
      filter:input、forward、output
      mangle:具有五条链,并且表中的链在包的处理流程中处于比较优先的位置

    五条链

      prerouting:路由前经过这条链,设置 mark 以及 DNAT
      input:主要是 filter 表,设置防火墙规则
      forward:主要是 filter 表,设置防火墙规则
      output:主要是 filter 表,设置防火墙规则
      postrouting:主要是 nat 表,设置 SNAT

    术语解释

      SNAT:在 postrouting 链,修改包的源地址,通常是为了多个内网用户共享一个外网端口来访问外网
      DNAT:在 prerouting 链,修改包的目的地址,通常是为了让外部访问内网中的服务

    状态跟踪机制
    我们在设置规则时经常会用到 ESTABLISHED,RELATED 等关键词,接下来我们来解释一下它们分别是什么含义,到底有什么用处。
    讲这个东西就要简单说一下网络的数据通讯的方式,我们知道,网络的访问是双向的,也就是说一个 Client 与 Server 之间完成数据交换需要双方的发包与收包。在 netfilter 中,有几种状态,也就是 new, established,related,invalid。
    当内网的一台机器访问外网,我们设置了规则允许它出去,但是没有设置允许回来的规则,怎么完成访问呢?这就是 netfilter 的状态机制。当一个 lan 用户通过这个 linux 访问外网的时候,它发送了一个请求包,这个包的状态是 new;当外网回包的时候它的状态就是 established,所以,linux 知道,哦,这个包是我的内网的一台机器发出去的应答包,它就放行了。
    而外网试图对内发起一个新的连接的时候,它的状态是 new,所以 linux 压根不去理会它。这就是我们为什么要加这一句的原因。
    还有那个 related,它是一个关联状态,什么会用到呢?tftp,ftp 都会用到,因为它们的传输机制决定了,它不像 http 访问那样,Client_IP: port-->server:80 然后 server:80-->Client_IP:port,ftp 使用 tcp21 建立连接,使用 20 端口发送数据,其中又有两种方式,一种主动 active mode,一种被动 passive mode。
    主动模式下,client 使用 port 命令告诉 server 我用哪一个端口接受数据,然后 server 主动发起对这个端口的请求。被动模式下,server 使用 port 命令告诉客户端,它用哪个端口监听,然后客户端发起对它的数据传输,所以这对于一个防火墙来说就是比较麻烦的事情,因为有可能会有 new 状态的数据包,但是它又是合理的请求,这个时候就用到这个 related 状态了,它就是一种关联,在 linux 中,有个叫 ftp_conntrack 的模块,它能识别 port 命令,然后对相应的端口进行放行。
    另外,可以考虑一下 SNAT,修改了源地址和源端口号。那么收到回复时怎么知道应该如何转给哪个地址和哪个端口呢?其实就是用到了连接跟踪机制 conntrack。里面存储了很多的映射关系,保存了端口和地址等是如何映射转换的。
    工作流程图示:


    (点击图片放大查看)


    (点击图片放大查看)
    常见应用场景
    简单的 nat 路由器
    场景描述:内网中有一台机器,有内网 IP 10.1.1.254/24 eth0 和外网 IP 60.1.1.1/24 eth1。如何控制内网中的其他机器(只有内网 IP)通过这台机器访问外网的行为。
    分析:

      首先将其他内网机器的网关设置为 10.1.1.254
      打开 Linux 转发功能,并且设置默认的转发策略为 DROP:

    sysctl net.ipv4.ip_forward=1
    iptables -P FORWARD DROP

      设置 NAT 规则

    iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -j SNAT --to 60.1.1.1

      假如允许 10.1.1.9 访问外网

    iptables -A FORWARD -s 10.1.1.9 -j ACCEPT

      假如只允许访问 3.3.3.3 这个 ip

    iptables -A FORWARD -d 3.3.3.3 -j ACCEPT

      但是设置了上面的规则后,并不能正常工作,流量能正常的出去,但是回不来,还需要设置

    iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
    这条规则应该放到第一条,以提高效率。
    端口转发
    场景描述:内网中有一台机器,有内网 IP 10.1.1.254/24 eth0 和外网 IP 60.1.1.1/24 eth1。另一台内网机器上有一个 webserver,地址为 10.1.1.1:80。如何配置规则让外部可以访问到内网的 web 服务器。
    分析:

      打开 Linux 的转发功能

    sysctl net.ipv4.ip_forward=1

      设置默认转发策略

    iptables -P FORWARD DROP

      利用状态跟踪机制,允许 ESTABLISHED,RELATED 连接上的包通过

    iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

      设置 DNAT

    iptables -t nat -A PREROUTING -d 60.1.1.1 -p tcp --dport 80 -j DNAT --to 10.1.1.1:80

      设置 Forward 规则,允许某类型的包通过

    iptables -A FORWARD -d 10.1.1.1 -p tcp --dport 80 -j ACCEPT

      现在仍然不能正常工作,外部流量可以到达 webserver,但是 webserver 并不知道如何将流量转发出去,有两种方式解决:


      设置 webserver 的默认网关为 10.1.1.254
      在转发机器上设置 SNAT

    iptables -t nat -A POSTROUTING -d 10.1.1.1 -p tcp --dport 80 -j SNAT --to 10.1.1.254
    如何让外部访问 kubernetes 的 8080 端口
    场景描述:为了安全考虑,非安全端口 8080 是 bind 到 localhost 的。那么如何设置 iptables 规则,让外部能访问 8080 端口呢。
    分析:

      设置 DNAT

    iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 127.0.0.1:8080

      允许外部访问 localhost

    sysctl -w net.ipv4.conf.all.route_localnet=1
    该设置的解释: Redirect to localhost
    (https://unix.stackexchange.com/questions/111433/iptables-redirect-outside-requests-to-127-0-0-1/112232#112232)
    在 kubernetes 中的应用
    为了支持集群的水平扩展、高可用性,kubernetes 抽象出了 service 的概念。Service 是一组 pod 的抽象,service 和 pod 是通过 label 和 selector 来实现关联的。我们知道 pod 的 ip 地址会随着 pod 的销毁和重建而发生改变,即新 pod 的 ip 地址与旧 pod 的 ip 地址是不同的。而 k8s 在 pod 之上加了一层 service 的概念,service 创建的时候会被分配一个静态的 cluster ip。在 service 的整个生命周期中,service 的 ip 都不会改变。因此,服务发现这个棘手的问题被轻松地解决。
    运行在每个 Node 上的 kube-proxy 进程是一个软件负载均衡器,它通过监控 etcd 中的 service 和 endpoint 资源,创建相应的 iptables 规则,根据 iptables 规则将对 service 的访问请求转发到后端的某个 pod 上,实现了服务的负载均衡和会话保持机制。
    接下来我们看一个实际的例子:
    首先创建一个三副本的 deployment,每个 pod 具有 label "name"= "nginx-79959",并且 nginx 是在 80 端口提供服务:
    {
    "kind": "Deployment",
    "apiVersion": "extensions/v1beta1",
    "metadata": {
    "name": "nginx-79959",
    "namespace": "default"
    },
    "spec": {
    "replicas": 3,
    "selector": {
    "matchLabels": {
    "name": "nginx-79959"
    }
    },
    "template": {
    "metadata": {
    "name": "nginx-79959",
    "namespace": "default",
    "labels": {
    "name": "nginx-79959"
    }
    },
    "spec": {
    "containers": [
    {
    "name": "nginx",
    "image": "hub.c.163.com/public/nginx:1.2.1",
    }
    ],
    "restartPolicy": "Always",
    }
    }
    }
    }
    最终会得到三个 running 的 pod:


    然后创建一个 service,service 的 selector 上上面 pod 的 label 是相同的,即 "name"= "nginx-79959",service 被分配了一个虚拟的 cluster ip,并且定义了转发规则,当访问 service 的 80 端口时,会转发到对应后端 pod 的 80 端口上去:
    {
    "kind": "Service",
    "apiVersion": "v1",
    "metadata": {
    "name": "nginx",
    "namespace": "default"
    },
    "spec": {
    "ports": [
    {
    "protocol": "TCP",
    "port": 80,
    "targetPort": 80
    }
    ],
    "selector": {
    "name": "nginx-79959"
    },
    "clusterIP": "10.0.14.162",
    "type": "ClusterIP",
    "sessionAffinity": "None"
    }
    }
    endpoint controller 通过监控 pod 和 service 资源,会创建跟 service 同名的 endpoint 资源,并且通过 service 的 selector 和 pod 的 label,负责将二者关联起来,将关联信息记录到 endpoint 资源中:


    当上面创建的某个 pod 挂掉的时候,endpoint controller 会将对应的 pod 信息从上面的 endpoint 资源中删除。同理,当同样具有 "name"= "nginx-79959" lable 的 pod 创建出来并 running 的时候,endpoint 会将这个 pod 的信息更新到 endpoint 资源中去。因此,当访问 service 的时候,请求不会转发到已经 Failed 的后端 pod 上去。
    接下来就是 kube-proxy 的工作了,它通过监控 endpoint 资源,创建 iptables DNAT 规则。
    DNAT 是在NAT表的 PREROUTING 链上设置的:
    iptables -t nat -L
    跳转到 KUBE-SERVICES 链:


    当目的 IP 是 10.0.14.162(即 service 的 ip),目的端口是 80 时,跳转到 KUBE-SVC-CCXTCUX4BWMIZHKW 链:


    iptables 的 Round Robin 负载均衡,因为这个 service 后端有三个 pod,因此会等概率跳转到下面三条链中的一条:


    DNAT,修改目的 ip 和目的端口为:10.173.32.10:80 或者 10.173.32.11:80 或者 10.173.32.8:80,其中这三个 ip 分别是三个后端 pod 的 ip 地址:


    参考文献:

      http://xstarcd.github.io/wiki/Linux/iptables_forward_internetshare.html
      http://blog.csdn.net/zm_21/article/details/8508653
      http://www.cnblogs.com/bangerlee/archive/2013/02/27/2935422.html
      https://my.oschina.net/u/156249/blog/32238
      http://blog.chinaunix.net/uid-13423994-id-3212414.html
      https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/sect-Security_Guide-Firewalls-IPTables_and_Connection_Tracking.html
      http://brokestream.com/iptables.html
      http://bbs.chinaunix.net/thread-1926255-1-1.html
      http://andys.org.uk/bits/2010/01/27/iptables-fun-with-mark/
      http://lesca.me/archives/iptables-examples.html

    以上由网易企业信息化服务提供商,湖南领先网络科技整理发布。
    网易企业服务,是网易凭借其20年品牌优势与经验在企业邮箱的基础上,为进一步布局企业市场而打造的企业级产品矩阵,致力于提供一站式企业信息化解决方案。湖南领先网络科技是网易企业产品授权经销商,专业为企业提供网易企业邮箱、网易办公套件等一站式企业信息化专业解决方案。

    声明:本文转载自网络。版权归原作者所有,如有侵权请联系删除。
    扫描并关注51学通信微信公众号,获取更多精彩通信课程分享。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    Archiver|手机版|小黑屋|51学通信技术论坛

    GMT+8, 2025-1-31 19:49 , Processed in 0.066614 second(s), 32 queries .

    Powered by Discuz! X3

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表