Docker 導致 UFW 設定失效

在 Docker host 主機上用 UFW 設定防火牆規則時,會發生 Docker container expose 到 Docker host 上的 port 不被 UFW 設定的規則阻擋。

例如:在 UFW 中設定的規則為

1
2
3
4
5
6
7
8
9
# ufw status verbose
Status: active
Default: deny (incoming), allow (outgoing), allow (routed)
New profiles: skip

To Action From
-- ------ ----
80 ALLOW IN Anywhere
443 ALLOW IN Anywhere

在啟始 Docker container 時 expose port 3000 到 Docker host 上 docker run -p 3000:3000 docker_image ,連接 port 3000 竟然沒有被防火牆阻擋。

1
2
$ nc -z docker-host 3000
Connection to docker-host port 3000 [tcp] succeeded!

Google 了一下該現象,發現有不少人有同樣問題,其中最常被引用的是這篇 The dangers of UFW + Docker

簡單來說,造成這現象的原因是:Docker 會修改 iptables 規則,但 ufw status 並不會列出被 Docker 修改後的規則。

解決方法

設定 UFW

  1. 開啟 /etc/default/ufw 並修改 DEFAULT_FORWARD_POLICYACCEPT

    /etc/default/ufw
    1
    DEFAULT_FORWARD_POLICY="ACCEPT"
  2. allow port 2375 的連線

    1
    # ufw allow 2375/tcp
  3. 重新載入 UFW 設定

    1
    # ufw reload

設定 Docker

  1. 加上 --iptables=false 參數避免 Docker 修改 iptables 規則​

    • Ubuntu:修改 /etc/default/docker ,在 DOCKER_OPTS 加上 --iptables=false

      /etc/default/docker
      1
      DOCKER_OPTS="--iptables=false"
    • Arch Linux:在 /etc/systemd/system/docker.service.d 中新增一個設定檔,如: behind-ufw.conf 然後輸入內容

      /etc/systemd/system/docker.service.d/behind-ufw.conf
      1
      2
      3
      [Service]
      ExecStart=
      ExecStart=/usr/bin/docker --iptables=false daemon -H fd://

      Docker v1.12 後 Docker service 改成執行 /usr/bin/dockerd,設定檔如下:

      /etc/systemd/system/docker.service.d/behind-ufw.conf
      1
      2
      3
      [Service]
      ExecStart=
      ExecStart=/usr/bin/dockerd --iptables=false -H fd://
  2. 重啟 Docker service

    • Ubuntu:

      1
      # service docker restart
    • Arch Linux:

      1
      2
      # systemctl daemon-reload
      # systemctl restart docker.service

設定 Docker 的 NAT 網路

在沒加上 --iptables=false 參數前,Docker 啟動的時候會在 iptables 中設定Docker container 的 NAT 網路,但加上 --iptables=false 參數後,就必須自行在 iptables 中設定給 Docker container 用的 NAT 網路。

開啟 /etc/ufw/before.rules 並在 *filter 前加上

/etc/ufw/before.rules
1
2
3
4
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE
COMMIT

然後就可以重開機試試設定是否生效了。

參考:Running Docker behind the ufw firewall