ubuntu ファイアーウォール :Docker が UFW 管理外のポートを開けてしまう問題
UFW とは ファイアーウォールを設定・管理するツールで、Ubuntuでは標準的に利用します。このツールを使用すれば、iptables を使うよりはるかに簡単にファイアーウォールを構築できます。
UFW - Community Help Wiki
Docker はご存知ですね。
Docker - Build, Ship, and Run Any App, Anywhere
遭遇した問題
今回 UFW と docker の両方を使用するサーバで、UFW で許可していないポート番号がいつのまにか空いてしまった問題に遭遇しました。 次のような感じです。
- ubuntu xenial サーバに対し、UFW で 22番と443番だけアクセス可能、その他は遮断というファイアーウォールをセットアップ
- 同サーバに Docker 入れて、nginx コンテナ起動、この時 “-p 80:80” オプションを付与
- 外部からこのサーバにアクセスしたら、UFW で開けていないはずの 80番ポートのページが見れてしまった
- UFW の設定を再確認してみたが、やっぱし 80番ポートは Allow してない
なんだかやばい感じです。
ちな、UFW の設定内容は以下の通りです。
$ sudo ufw status verbose Status: active Logging: on (low) Default: deny (incoming), allow (outgoing), deny (routed) New profiles: skip To Action From -- ------ ---- 443 ALLOW IN Anywhere 22 LIMIT IN Anywhere 443 (v6) ALLOW IN Anywhere (v6) 22 (v6) LIMIT IN Anywhere (v6)
問題の原因
Docker の問題
調査したところ、ひとつの原因は … Docker でした。docker run の -p や -P オプションでコンテナを起動すると、Docker は、その指定されたポート番号について、ファイアーウォールに穴を開ける処理をします。
UFWの問題
では、どうして UFW で確認できなかったのでしょうか? それは … 直接 iptables のルール一覧を確認すれば分かるかもしれません。
$ sudo iptables -L Chain INPUT (policy DROP) target prot opt source destination ufw-before-logging-input all -- anywhere anywhere ufw-before-input all -- anywhere anywhere ufw-after-input all -- anywhere anywhere ufw-after-logging-input all -- anywhere anywhere ufw-reject-input all -- anywhere anywhere ufw-track-input all -- anywhere anywhere Chain FORWARD (policy DROP) target prot opt source destination DOCKER-USER all -- anywhere anywhere DOCKER-ISOLATION all -- anywhere anywhere ... 省略 ... Chain DOCKER (2 references) target prot opt source destination ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:https ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:http Chain DOCKER-ISOLATION (1 references) target prot opt source destination DROP all -- anywhere anywhere DROP all -- anywhere anywhere RETURN all -- anywhere anywhere Chain DOCKER-USER (1 references) target prot opt source destination RETURN all -- anywhere anywhere Chain ufw-after-forward (1 references) target prot opt source destination ... 省略 ... Chain ufw-user-input (1 references) target prot opt source destination ACCEPT tcp -- anywhere anywhere tcp dpt:https ACCEPT udp -- anywhere anywhere udp dpt:https ... 省略 ...
UFW が設定したルールには、"ufw-[hogehoge]“ という名前が付いています。一方、"DOCKER” で始まるチェーンも見ることができますが、こちらは明らかに Docker によって追加されたルールですね。
どうやら UFW は 自分が設定したルール、すなわち “ufw-[hogehoge]” についてのみ管理対象としているようです。従って、Docker など他のプログラムや、手作業で追加したルールについては関与していません。これこそがもう一つの原因であり、運用する上で大変注意が必要である事項であります。
ちなみに、Docker が勝手にポートを開けるのを抑える方法
ubuntu の場合だと、”/etc/default/docker” の ”DOCKER_OPTS" オプションに、"–iptables=false" を追加すればいいようです。
DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4 --iptables=false"
なお、オプションを有効にするため Docker の再起動を忘れないようにしてください。
まとめ
-p や -P オプション(also EXPOSE)をつけて “docker run” すると Docker が 該当するポートを許可する設定を iptables に追加する。
UFW は自分で設定したルール以外は関与しない。このため、UFW で確認できる設定内容がファイアーウォールの全てではないことに注意すること。
ファイアーウォールについて、最終的には iptables コマンドでも確認した方が良いと思われます。