【问题标题】:Docker ignores iptable rules when using "-p <port>:<port>"Docker 在使用“-p <port>:<port>”时忽略 iptable 规则
【发布时间】:2015-08-26 12:02:16
【问题描述】:

几天前才意识到 Docker 似乎绕过了我的 iptable 规则。我对 Docker 和 iptables 的经验并不令人难以置信。最近几天尝试了很多不同的东西。还看到最近的 docker 版本有很大的变化,有一个特殊的 DOCKER 链,应该允许我这样做。但是不确定我做错了什么,但它永远不会像我期望的那样做。

所以我想要的很简单。我希望它表现得像预期的那样。如果我有一个 ACCEPT-Rule 要通过,如果没有它就会被阻止。

我的 iptable 最初看起来是这样的(所以在我多次尝试不成功之前):

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -s 1.2.3.4 -p tcp -m tcp --dport 123 -j ACCEPT
-A INPUT -j DROP
COMMIT

希望它完全符合我的要求。只允许访问端口 22 和 80,还允许来自 ip 1.2.3.4 的端口 123。但是,如果我使用“-p 123:123”创建一个容器,每个人都可以访问它。谁能帮助我并告诉我如何更改上述文件?

谢谢!

Docker-版本:1.6.2

编辑:

最初我的不同尝试是为了不使问题过于复杂。但是,至少添加其中一个可能会有所帮助。

*nat
:PREROUTING ACCEPT [319:17164]
:INPUT ACCEPT [8:436]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [16:960]
:DOCKER - [0:0]
COMMIT


*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER -s 1.2.3.4 -p tcp -m tcp --dport 123 -j ACCEPT
-A DOCKER -j DROP
-A INPUT -j DROP
COMMIT

以上类型的作品。但是会遇到很多其他问题。例如,我是否遇到容器链接问题、DNS 不再工作等等。所以最终添加了许多额外的规则来解决这些问题,但我永远不会达到它正常运行的状态。所以我想大多数情况下都有更好、更简单的解决方案。

解决方案:

最终或多或少地按照 larsks 所说的那样做。只是没有加到 FORWARD 链上,我把它加到了 DOCKER 链上。 FORWARD 链的问题在于 Docker 在第一个位置重新启动时会在其中添加它的东西。这导致我的规则被推倒并且没有任何效果。然而对于 DOCKER 链,Docker 似乎只附加了额外的规则,所以我的规则仍然有效。因此,当我保存规则然后重新启动服务器时,一切仍然正常。

所以现在看起来或多或少是这样的:

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]
# That I can access from IP 1.2.3.4
-A DOCKER -s 1.2.3.4/32 -p tcp -m tcp --dport 123 -j ACCEPT
# That I can access from other Docker containers
-A DOCKER -o docker0 -p tcp -m tcp --dport 123 -j ACCEPT
# Does not allow it for anything else
-A DOCKER -p tcp --dport 123 -j DROP

-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -j DROP
COMMIT

【问题讨论】:

    标签: docker iptables


    【解决方案1】:

    您的 iptables 配置现在看起来有点损坏,就好像您在没有重新启动 Docker 的情况下在某个时候将其清除了一样。例如,您在 filternat 表中都有一个 DOCKER 链可用,但没有引用它的规则,因此放置在该链中的规则不会产生任何影响。

    一般来说,如果你想实现影响 Docker 容器的 iptables 规则,它们需要进入filter 表的FORWARD 链。每个容器都有其自己的 IP 地址,这意味着您的主机只是接受数据包,然后FORWARD将它们发送到容器地址。

    INPUT 链中的规则仅适用于最终目的地为主机全局网络命名空间中接口地址的数据包。

    但是,我不确定 iptables 是否真的是您的问题。

    如果您尝试在容器中公开服务以便它们可用于其他系统,则需要使用-p 标志将这些端口发布到docker run。您可以阅读更多相关信息 在文档的this section 中。

    如果您想通过具体示例来更新您的问题,我可以提供更有针对性的答案。

    更新

    确实,当您使用-p 发布容器端口时,它通常可用于任何源IP 地址。为了限制对已发布端口的访问,您需要向 FORWARD 链添加新规则。例如,如果我启动一个 Web 服务器:

    docker run --name web -p 80:8080 larsks/mini-httpd
    

    容器中的 Web 服务器现在可以在我的主机上的 8080 端口上使用。如果我想阻止对这个端口的访问,我需要在FORWARD 链中插入一条规则来阻止对容器ip 上的80 端口的访问。所以首先我需要容器ip地址:

    $ web_ip=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' web)
    $ echo $web_ip
    172.17.0.5
    

    我在FORWARD 链中创建的规则需要 docker 创建的规则之前,所以我需要指定一个明确的位置:

    iptables -I FORWARD 1 -d $web_ip -p tcp --dport 80 \! -s 192.168.1.10 -j DROP
    

    这将阻止来自 192.168.1.10 以外主机的所有流量。

    如果你想让规则应用于所有容器,而不是特定容器,你可以将它绑定到docker0接口而不是特定的ip地址:

    -A FORWARD -o docker0 -p tcp --dport 80 \! -s 192.168.1.10 -j DROP
    

    这将禁止访问任何容器上的端口 80。

    【讨论】:

    • 谢谢!就像我写的那样,遗憾的是,我对 iptables 并没有太多的了解。我自己只是简单地创建了上述文件,因为我认为它可能会以某种方式工作。但实际上并不是很重要,只是把它作为我尝试过的许多事情之一的例子。我想要的是它就像预期的那样工作。 docker-container-ports 的行为与所有其他端口相同。我没有列入白名单的所有内容都会被阻止。目前,只要我使用“-p 123:123”启动一个容器,端口 123 就会向世界开放(而不是因为 drop-all 规则而被阻止)。
    • 太棒了,谢谢你似乎正是我正在寻找的。但想知道是否有办法避免对 IP 地址进行硬编码。因为我必须将以上内容添加到启动脚本中。当我现在停止并启动一些容器时,它将不再工作,因为 IP 地址现在完全不同,然后我将不得不再次编辑 iptables,如果我忘记了,我会将它向世界开放。为了让它更简单。我可以有一个像上面这样的规则,它只适用于所有 docker-containers 而不是特定的吗?
    【解决方案2】:

    我不是 iptables 方面的专家,但我知道如果您使用 -p 127.0.0.1:123:123 运行容器,那么端口将不会在所有接口上公开,只会在环回上公开。

    【讨论】:

    • 但这是否意味着除非我设置某种反向代理,否则我只能从 localhost 访问它?所以我仍然希望外部世界可以访问端口。但只有当我这么说的时候。我目前的解决方案不是我想要的 100%,因为它默认是打开的,我必须手动关闭,但已经足够接近了。
    【解决方案3】:

    最终或多或少地按照 larsks 所说的那样做。只是没有添加 将其添加到 FORWARD 链中,我将其添加到 DOCKER 链中。

    我在文档中找到了相同的内容:https://docs.docker.com/v1.5/articles/networking/#the-world

    Docker 不会删除或修改任何预先存在的规则 DOCKER 过滤器链。这允许用户提前创建任何 进一步限制对容器的访问所需的规则。

    Docker 的转发规则默认允许所有外部源 IP。 到 只允许特定 IP 或网络访问容器,插入 DOCKER 过滤器链顶部的否定规则。例如,要 限制外部访问,只有源 IP 8.8.8.8 可以访问 容器,可以添加以下规则:

    $ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP
    

    【讨论】:

      【解决方案4】:

      鉴于: Debian stretch、docker 18.06 和一个通过

      创建的 docker 进程
      docker run ... -p 5678:1234 ...
      

      必需:对 docker 容器的访问仅限于多个外部子网。

      解决方案:(使用一些示例子网)

      iptables -I DOCKER-USER                  -p tcp --dport 1234 -j REJECT
      iptables -I DOCKER-USER -s 18.204.0.0/16 -p tcp --dport 1234 -j RETURN
      iptables -I DOCKER-USER -s 34.192.0.0/16 -p tcp --dport 1234 -j RETURN
      iptables -I DOCKER-USER -s 35.153.0.0/16 -p tcp --dport 1234 -j RETURN
      iptables -I DOCKER-USER -s 13.56.63.0/24 -p tcp --dport 1234 -j RETURN
      

      使用 iptables-save 保持更改的规则:

      iptables-save > /etc/iptables/rules.v4
      

      结果:

      iptables -L DOCKER-USER -n -v --line-numbers
      
      Chain DOCKER-USER (1 references)
      pkts bytes target     prot opt in     out     source               destination
      0     0 RETURN     tcp  --  *      *       13.56.63.0/24        0.0.0.0/0            tcp dpt:1234
      0     0 RETURN     tcp  --  *      *       35.153.0.0/16        0.0.0.0/0            tcp dpt:1234
      0     0 RETURN     tcp  --  *      *       34.192.0.0/16        0.0.0.0/0            tcp dpt:1234
      0     0 RETURN     tcp  --  *      *       18.204.0.0/16        0.0.0.0/0            tcp dpt:1234
      0     0 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:1234 reject-with icmp-port-unreachable
      

      背景 1:规则

      所有规则都按照当前 docker 文档的建议添加到链 DOCKER-USER

      第一条规则以REJECT 为目标,并将作为最后一条规则结束,因为其他规则添加在顶部(选项-I 没有位置编号对应于在位置1 添加规则)。目的端口为 1234 的所有包都将被拒绝。

      其他规则以RETURN为目标,即来自给定子网之一的目标端口为1234和源IP的包将返回到调用链,即FORWARD链。

      iptables -L FORWARD -n -v
      Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
      pkts bytes target     prot opt in     out     source               destination
      16471 4568K DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
      16413 4565K DOCKER-ISOLATION-STAGE-1  all  --  *      *       0.0.0.0/0            0.0.0.0/0
      7173 2060K ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
      45  2340 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
      

      来自FORWARD 链,它将由DOCKER 链处理,并根据需要转发到 docker 容器:

      iptables -L DOCKER -n -v
      Chain DOCKER (1 references)
      pkts bytes target     prot opt in     out     source               destination
      45  2340 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.2           tcp dpt:1234
      

      背景二:端口值

      我们不在转发规则中使用外部端口值 5678,因为目标端口是通过 docker 自动创建的规则更改的,并在执行转发链之前应用。请参阅 /etc/iptables/rules.v4 的顶部:

      -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
      ...
      -A DOCKER ! -i docker0 -p tcp -m tcp --dport 5678 -j DNAT --to-destination 172.17.0.2:1234
      

      【讨论】:

        【解决方案5】:

        要在 docker 容器的已发布端口上使用 iptables,您需要结合以下各项:

        • DOCKER-USER 表:docker 将此表用于影响容器的 iptables 规则,并专门为用户提供的规则保留,这些规则在重新启动时不会被 docker 引擎覆盖。
        • conntrack:端口转发可以在一个端口上发布并转发到容器中的另一个端口。您可以让多个容器都侦听端口 80,并在主机上使用不同的已发布端口。

        要使用这些,生成的 iptables 规则如下所示:

        iptables -I DOCKER-USER -i eth0 -s 10.0.0.0/24 -p tcp \
          -m conntrack --ctorigdstport 8080 -j ACCEPT
        iptables -I DOCKER-USER -i eth0 ! -s 10.0.0.0/24 -p tcp \
          -m conntrack --ctorigdstport 8080 -j DROP
        

        这会处理对已发布端口 8080/tcp 的请求(即在主机上,容器可能正在侦听 80 或任何其他端口),并且只接受来自 10.0.0.0/24 子网的请求。该子网之外的所有内容都将被丢弃。

        请注意,DOCKER-USER 表有一个立即返回的默认规则,因此所有更改都应插入到表中该默认规则之前。

        【讨论】:

          猜你喜欢
          • 2020-05-12
          • 1970-01-01
          • 2020-05-13
          • 2016-12-22
          • 2021-12-02
          • 2013-01-13
          • 1970-01-01
          • 2012-04-05
          相关资源
          最近更新 更多