注意事项

注意事项

只需设置一个 ElasticSearch 容器,与公司的 Laravel 应用程序一起使用即可。创建 docker-compose.yml 并运行它是完美且直接的,但当我想对此进行防火墙保护,以便只能从所述 Laravel 应用程序的一个特定 IP 访问它时,就会出现问题。

在研究过程中,我注意到很多人都遇到了这些问题,即 Docker 转发的端口流量完全暴露给公众,并且他们无法正确地对其进行防火墙保护。

我找到了几个解决方案在过去的 6 小时内,没有一个工作正常。我认为这与 Docker 处理/转发入站流量的方式有关,而且我对 iptables 的了解并不多,因此我无法自己理解发生了什么。

这是我的 docker-compose.yml (物有所值):

version: '3.4'

services:

  elasticsearch:
    image: khezen/elasticsearch:6.1.1
    container_name: elasticsearch

    environment:
      NETWORK_HOST: 0.0.0.0
      HOSTS: 127.0.0.1
      CLUSTER_NAME: fd-es
      NODE_NAME: node-1
      HEAP_SIZE: 31g
      HTTP_SSL: "true"
      ELASTIC_PWD: "somepasswd"
      HTTP_CORS_ENABLE: "true"
      HTTP_CORS_ALLOW_ORIGIN: /https?:\/\/localhost(:[0-9]+)?/

    ulimits:
      memlock:
       soft: -1
       hard: -1

    volumes:
      - ./config/elasticsearch.yml:/elasticsearch/config/elasticsearch.yml
      - ./data:/elasticsearch/data
      - ./logs:/elasticsearch/logs

    ports:
      - 9200:9200

    networks:
      - es-network

    restart: always

networks:
  es-network:
    driver: bridge

这些是我当前使用的 iptables 规则,它们在某种程度上是我想要的,但来自任何客户端到端口 9200 的所有流量仍然可以通过,而不仅仅是从我的应用程序访问:

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]
-A DOCKER -s xxx.xxx.xxx.xxx -p tcp -m tcp --dport 9200 -j ACCEPT
-A DOCKER -o docker0 -p tcp -m tcp --dport 9200 -j ACCEPT
-A DOCKER -p tcp --dport 9200 -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p udp -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp -m tcp --dport 44344 -j ACCEPT
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
-A INPUT -j DROP

我尝试禁用 Docker 的 iptables 支持并禁用桥接网络,并调整了 iptables 规则几十次,但都无济于事。

我将非常感激任何建议和帮助,因为我对这个问题没有想法和搜索结果。

提前致谢!

答案1

对于每个寻求此问题解决方案的人来说,答案是这样的:

*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:FILTERS - [0:0]
:DOCKER-USER - [0:0]

-F INPUT
-F DOCKER-USER
-F FILTERS

-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp --icmp-type any -j ACCEPT
-A INPUT -j FILTERS

-A DOCKER-USER -i ens33 -j FILTERS

-A FILTERS -m state --state ESTABLISHED,RELATED -j ACCEPT
-A FILTERS -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A FILTERS -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A FILTERS -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT
-A FILTERS -j REJECT --reject-with icmp-host-prohibited

COMMIT

在这里找到:https://unrouted.io/2017/08/15/docker-firewall/

运行完美。

答案2

我将解释我已经测试过的您想要实现的目标的场景。

我启动了一个 Docker 容器,其中端口 9010 转发到端口 8080:

docker run -p 9010:8080 swaggerapi/swagger-editor

Docker 为 PREROUTING 链创建 DNAT 规则,将流量从端口 9010 转发到端口 8080:

DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:9010 to:172.17.0.5:8080

Docker 还在 DOCKER 链中创建一条规则,允许发送到容器的 IP 地址和端口 8080 的所有流量。

ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.5           tcp dpt:8080

DOCKER 链用于 FORWARD 链,其中发送到 docker0 网桥的所有流量都经过 DOCKER 链中的规则处理。

DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0

现在我想过滤发送到端口 8080 的流量(发送到端口 9010 的流量已由 PREROUTING 处理,现在是发送到端口 8080 的流量),阻止所有 IP 地址,同时允许来自 IP 192.168.1.142 的流量。当然,可以将容器的 IP 地址添加到这些规则中以增加粒度。

我在开头添加了以下规则向前链。或者,你可以用 DOCKER 替换 FORWARD。

iptables -I FORWARD -p tcp --dport 8080 -j DROP
iptables -I FORWARD -p tcp -s 192.168.1.142 --dport 8080 -j ACCEPT

由于这些规则,只有 IP 192.168.1.142 可以访问容器使用的 8080 端口。

对于那些访问此答案的人,如果您只想允许一个特定的 IP 地址访问容器,请使用Docker 文档

答案3

我认为添加这一行可以解决你的问题:

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]

**-A INPUT -p tcp -m tcp --dport 9200 -j DOCKER**

-A DOCKER -s xxx.xxx.xxx.xxx -p tcp -m tcp --dport 9200 -j ACCEPT

答案4

我对接受的答案有一点小问题,那就是它允许访问容器端口,而不考虑已发布的端口。理想情况下,它会起作用,您可以执行以下操作:-p 80:80-p 8080:8080

如果出现这种情况-p 8080:80,您必须遵循此处的评论:https://github.com/moby/moby/issues/22054#issuecomment-466663033

基本上,NAT 发生在过滤之前,因此--dport不起作用,就像这个人问的那样:https://github.com/moby/moby/issues/22054#issuecomment-426655503

因此,我修改了接受的答案如下,按照这个例子

*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:FILTERS - [0:0]
:DOCKER-USER - [0:0]

-F INPUT
-F DOCKER-USER
-F FILTERS

# BASIC Allow
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp --icmp-type any -j ACCEPT

# Chain to FILTERS
-A INPUT -j FILTERS
-A DOCKER-USER -i eth0 -j FILTERS

# ALLOW outgoing traffic
-A FILTERS -m state --state ESTABLISHED,RELATED -j ACCEPT

# COMMON FIREWALL RULES

# ALLOW SSH ON THE HOST
-A FILTERS -p tcp -m multiport --dports 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# ALLOW the following ports on the containers as well.
-A FILTERS -p tcp -m conntrack --ctstate NEW,ESTABLISHED --ctorigdstport 80 -j ACCEPT
-A FILTERS -p tcp -m conntrack --ctstate NEW,ESTABLISHED --ctorigdstport 443 -j ACCEPT

# DENY something
#-A FILTERS -p icmp --icmp-type echo-request -j REJECT

# FINAL REJECT
-A FILTERS -j REJECT

COMMIT

注意事项

(因为为什么不呢)

如果您在主机级别允许一个端口,如我上面允许 SSH 的示例一样。

请注意,这将允许在同一端口上运行的任何容器(无论发布的端口是什么)可供所有人访问。

例如:

如果我允许端口 8080,您可以通过运行 ncat 容器进行测试,docker run --rm -p 8081:8080 subfuzion/netcat -l 8080然后从另一台机器使用 ncat,ncat <docker container host public ip>:8081您将看到连接通过。

一个解决方法可能是(我还没有测试过)只允许使用端口,--ctorigdstport但我不确定它是否会将你锁定在你的机器之外,就像这样(这没有经过测试):

-A FILTERS -p tcp -m conntrack --ctstate NEW,ESTABLISHED --ctorigdstport 22 -j ACCEPT

相关内容