Docker と iptables

Linux 上では、 Docker は ネットワークの分離(network isolation) のために iptables ルールを操作します。これは実装の詳細であり、 Docker が追加する iptables ポリシーを変更すべきではありません。しかしながら、 Docker によって管理されている追加されたポリシーを、自分自身で変更したい場合には、いくつかの影響が発生する可能性があります。

Docker を実行しているホストをインターネット上に公開している場合、コンテナやホスト上で実行しているサービスに対する教科のない接続を防ぐように、おそらく何らかの iptables ポリシーを追加しようとするでしょう。これをどのようにして行うか、そして、気を付けるべき警告について、このページで扱います。

iptables ポリシーは Docker 用ルールの前に追加

Docker は2つのカスタム iptables チェイン(chain) を追加します。チェインの名前は DOCKER-USERDOCKER です。そして、常に入力側のパケットは、これら2つのチェインによるチェックが第一に行われます。

Docker の iptables 全ルールは DOCKER チェインに追加されます。このチェインは手動で操作しないでください。Docker のルールを読み込む前にルールの追加が必要な場合は、 DOCKER-USER チェインにルールを追加しミズ合う。これらのルールは Docker が自動的に作成するルールより前に適用されます。

ルールは FORWARD チェインにも追加されます。手動で、あるいは他の ipables をベースとするファイアウォールによって追加されたものは、これらの( Docker が追加した)チェインの後で処理されます。つまり、Docker を通してポートを公開している場合、ファイアウォールによってどのようなルールが追加されていても、ポート公開に何ら問題ありません。Docker を通して公開しているポートに対し、何らかのルールを適用したい場合は、 DOCKER-USER チェインに「必ず」追加する必要があります。

Docker ホストに対する接続を制限

デフォルトでは、全ての外部ソース IP アドレスから Docker ホストに接続できます。コンテナに対して特定の IP アドレスもしくはネットワークからのみ許可するには、 DOCKER-USER フィルタ チェインの一番上に 無効化(negated) ルールを追加します。たとえば、以下のルールは 192.168.1.1 を除く全ての外部アクセスを制限します。

$ iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.1 -j DROP

注意点として、 ext_if をホスト上での実際の外部インターフェースと一致するように変更が必要です。(IPアドレスの代わりに)ソース となるサブネットでも指定できます。以下の例はサブネット 192.168.1.0/24 からのアクセスを許可するルールです。

$ iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.0/24 -j DROP

最後に、 --src-range を使って IP アドレス範囲を指定できます( --src-range--dst-range を使う場合も、 -m iprange が追加されますので、覚えておいてください)。

$ iptables -I DOCKER-USER -m iprange -i ext_if ! --src-range 192.168.1.1-192.168.1.3 -j DROP

送信元(source>`と :ruby:`送信先 ) の両方を制御するため、 -s または --src-range-d または --dst-range を一緒に使えます。たとえば、 Docker デーモンが 192.168.1.9910.1.2.3 の両方をリッスンする場合、 10.1.2.3 に対してルールを追加するものの、 192.168.1.99 は開いたままにできます。

iptables は複雑であり、より複雑なルールは、このトピックの範囲外です。更なる詳しい情報は Netfilter.org HOWTO をご覧ください。

ルータ上の Docker

Docker は FORWARD チェインに DROP するポリシーも追加出来ます。Docker ホストがルータとしても機能している場合は、このポリシーを追加した結果、あらゆるトラフィックが転送されなくなる可能性があります。システムがルータとしても機能し続けたい場合は、 DOCKER-USER チェインで ACCEPT ルールを追加し、許可を明示する必要があります。

$ iptables -I DOCKER-USER -i src_if -o dst_if -j ACCEPT

Docker からの iptables 操作を回避するには

Docker エンジンの /etc/docker/daemon.json 設定ファイルで、 iptables キーを false に設定できます。ですが、このオプションは大部分のユーザにとって適切ではありません。Docker によって作成された iptables ルールを完全に回避できないだけでなく、作成後のルールは、極めて複雑かつ命令範囲が広まってしまう懸念があります。 iptablesfalse にする設定とは、Docker Engine のコンテナネットワークへ通信を遮断するような場合に使います。

Docker ランタイムを他のアプリケーションと構築し、システム統合したい場合には、 moby プロジェクト をお探しください。

コンテナ用のデフォルト バインド アドレスを指定

デフォルトでは、 Docker デーモンは 0.0.0.0 アドレス上、つまり、ホスト上のあらゆるアドレスにポートを公開します。もしもこの挙動を変更し、特定の内部 IP アドレスだけ公開したい場合には、 --ip オプションを使って別の IP アドレスが指定可能です。一方で、 --ip が変更できるのは「デフォルト」だけであり、サービスごとの IP アドレスは制限できません。

Firewalld との統合

Docker バージョン 20.10.0 以上を実行中で、 --iptables を有効にし、システム上で firewalld を使っている場合、 Docker は自動的に docker という名称の firewalld ゾーンを作成し、作成されている全てのネットワークインタフェース(例: docker0 )を docker ゾーン内に追加し、シームレスなネットワーク通信を可能にします。

docker インタフェースを zone から削除するには、以下の firewalld コマンドの実行を考えます。

# 適切な zone や docker インタフェースに置き換えてください
$ firewall-cmd --zone=trusted --remove-interface=docker0 --permanent
$ firewall-cmd --reload

参考

Docker and iptables
https://docs.docker.com/network/iptables/