docker-compose で起動させた Docker コンテナから送出するパケットを iptables で制限する

# 背景

Docker コンテナで WEB アプリケーションを公開する際、docker-compose を用いてポートを ports オプションで publish し、別途用意してあるリバースプロキシを介して外部公開させました。

外部からコンテナへの通信は publish されたポートのみアクセスできるよう制限されているものの、コンテナから外部への通信は制限されていません。

そこで、万一アプリケーションの脆弱性によりアプリケーションから悪意のある通信が行われた場合に備えて、コンテナが通信できるプライベート IP は任意のもののみに制限することにしました。

本記事はその際に調べた Docker ネットワークと iptables の詳細と、コンテナから外部への通信を制限した際の設定内容を記述します。

# Docker ネットワークとは

Docker ネットワークは Docker コンテナがホストと通信をするため、または別のコンテナ、そして異なるネットワークと通信するために利用されます。

Docker ネットワークには 3 種類の動作が異なるドライバが用意されており、**bridge**, **host**, **none** が存在します。

公式マニュアルでの Networking や、Docker Tutorials and Labs の Docker Networking 資料による具体例を元にした説明が役に立ちます。

参考情報: [GitHub - docker/labs](https://github.com/docker/labs/tree/master/networking
参考情報: [docker docs > Networking overview](https://docs.docker.com/network/)

# Docker ネットワークの詳細

bridge, host, none ネットワークの詳細を説明します。

尚、書かれている内容は Docker v18.03 における情報を参考にしました。

## bridge ネットワークドライバの詳細

bridge はデフォルトのネットワークドライバです。

ブリッジネットワークはアプリケーションがスタンドアロンコンテナで動作する際に、コミュニケーションをとるために使われます。(参考情報: [Use bridge networks](https://docs.docker.com/network/bridge/))

* ネットワーク用語において bridge とは、ネットワーク間のトラフィックをフォワードする Link Layer デバイスである
    * bridge はハードウェア又は kernel で動作するソフトウェアとして実装される
* Docker 用語において bridge はソフトウェア bridge を指す
* 同一 bridge ネットワークに接続されているコンテナが通信できる
* bridge ネットワークに接続していないコンテナとは通信できない
* 上記ルールは自動でインストールされる(Linux では Docker host の iptables にルールが追加される)
* bridge ネットワークは同一 Docker ホスト上で適用され、異なる Docker ホスト間は OS レベルのルーティング又は overlay ネットワークで通信させることが出来る
* `--link` オプションを使わない限り、ブリッジネットワーク内のコンテナはお互いを IP アドレスでアクセスする
* ユーザ定義の bridge ネットワークではコンテナは名前又はエイリアスで互いに解決できる
* コンテナ実行中にユーザ定義のネットワークへ接続・切断が出来る
* デフォルトの bridge ネットワークは iptables と MTU を共有しており、それらの設定を行うことが出来るがコンテナ外部で設定されるため、Docker を再起動する必要があります
* `docker network create` でユーザ定義ネットワークを作成することが出来る
* デフォルトの bridge ネットワークでは環境変数を共有できない
    * `--link` オプションを使うことで共有することが出来る
    * ユーザ定義 bridge ネットワークでは環境変数を共有できない
    * 複数コンテナで共有できる方法は次の 3 つです
        * Docker volume でファイルやディレクトリ等の共有情報を複数のコンテナでマウントさせる
        * docker-compose で複数のコンテナを一緒に開始させる
        * スタンドアロンコンテナの代わりに swarm サービスを使う

```json:bridgeネットワークの詳細
[
    {
        "Name": "bridge",
        "Id": "ad7fcb93799ce4bf7cd65db271feacdfd16e62e8579d2c14f3b3026f1d94ed3a",
        "Created": "2018-09-30T14:27:42.551956224Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "e02ca3ee8d40b03cfa4503c0b5bc6a103909b5c2d13bbfc0c03cbf0a4005ab6a": {
                "Name": "gallant_volhard",
                "EndpointID": "e885851033138b7748d252afb0da13826360fb8802445536a80c0e97de44138b",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
```

## host ネットワークの詳細

スタンドアロンコンテナの場合、host ネットワークはコンテナと Docker ホスト間のネットワークを共有します。

例えばポート 80 にバインドするコンテナを実行してホストネットワークを使用する場合、コンテナのアプリケーションはホストの IP アドレスのポート 80 で使用できる。

host ネットワークドライバは Linux ホストでのみ動作し、Docker for MAC, Docker for Windows または Docker EE for Windows Server ではサポートされていません。

```json:hostネットワークの詳細
[
    {
        "Name": "host",
        "Id": "84e49cbca104637ee19edf06c6f15c0171efcadc2a08da2d4e6d6daaaccef26c",
        "Created": "2018-01-18T02:08:37.994752736Z",
        "Scope": "local",
        "Driver": "host",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
```

## none ネットワークの詳細

none ネットワークはネットワーク機能が全く必要としないコンテナに対して設定するためのネットワークドライバです。

none ネットワークを使用してコンテナを起動すると、ネットワーク機能は完全に無効化されます。


```json:noneネットワークの詳細
[
    {
        "Name": "none",
        "Id": "3793b20ebb28b8d256f042f449023750de9569fda9dec5e512434d9e65491080",
        "Created": "2018-01-18T02:08:37.988729433Z",
        "Scope": "local",
        "Driver": "null",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
```

## Docker デーモン起動時に追加される iptables の設定

Docker デーモンが起動すると次のように iptables に Docker コンテナ用の設定が追加されていることが分かります。

```
Chain INPUT (policy ACCEPT 36612 packets, 271M bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
   24  2960 DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   24  2960 DOCKER-ISOLATION  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   12  2040 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
   12   920 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0

Chain OUTPUT (policy ACCEPT 26829 packets, 1329K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain DOCKER (1 references)
 pkts bytes target     prot opt in     out     source               destination

Chain DOCKER-ISOLATION (1 references)
 pkts bytes target     prot opt in     out     source               destination
   24  2960 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination
   24  2960 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0
```

# docker-compose におけるネットワーク

docker-compose では docker-compose.yml に記述された services が所属する bridge network が作成されます。

そのため、コンテナへのアクセスを許可するには `-p` オプションと同様に ports オプションでポートを公開する必要があります。

また、bridge ネットワークに所属しているためコンテナに割り当てられる IP アドレスは bridge ネットワークのセグメントのものとなります。

```json:docker-composeアプリケーションのnetwork詳細例(app_defaultの詳細)
[
    {
        "Name": "app_default",
        "Id": "388e266f99936126b073c0e6d66a1e6ecc0eaf7e8c96ff5dc5f608eb26f71e8c",
        "Created": "2018-09-30T17:07:24.415316566Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "2fb05af8bd06597631f8dba72a7530b7762b9cc7a740a3b0115015121bfd1970": {
                "Name": "app_app_1",
                "EndpointID": "e5921d8f559503282906a2b6856d3d96745b382b05ed590c96207b97cc2b52dd",
                "MacAddress": "02:42:ac:12:00:04",
                "IPv4Address": "172.18.0.4/16",
                "IPv6Address": ""
            },
            "61072fd28a1c0e8783ad44d878a7d52924da6d3437ad72edfd014e632db4f1ef": {
                "Name": "app_elasticsearch_1",
                "EndpointID": "f097dfaec1a0310df215dd9faa3b9e0e817e1c32a942536aa6ef560c4abdaf12",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "dd4588c652dd96254f90953be7dc835393a259f8ad61f235fa8eabce3496d1d6": {
                "Name": "app_mongo_1",
                "EndpointID": "6ebe62c253492d9a170d3985b71a9e8cbfcdf252269792d63365ffc40004ee03",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "app"
        }
    }
]
```

docker-compose によりコンテナを起動させた後の iptables を見ると次のとおり★が付いた箇所が変化しています。

```
Chain INPUT (policy ACCEPT 355 packets, 19816 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
 1391 1084K DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
 1391 1084K DOCKER-ISOLATION  all  --  *      *       0.0.0.0/0            0.0.0.0/0
 1278 1078K ACCEPT     all  --  *      br-388e266f9993  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED (★1)
   19  1140 DOCKER     all  --  *      br-388e266f9993  0.0.0.0/0            0.0.0.0/0 (★2)
   94  4566 ACCEPT     all  --  br-388e266f9993 !br-388e266f9993  0.0.0.0/0            0.0.0.0/0 (★3)
   19  1140 ACCEPT     all  --  br-388e266f9993 br-388e266f9993  0.0.0.0/0            0.0.0.0/0 (★4)
   18  2544 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
   18  1424 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0

Chain OUTPUT (policy ACCEPT 202 packets, 19112 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     tcp  --  !br-388e266f9993 br-388e266f9993  0.0.0.0/0            172.18.0.4           tcp dpt:3000 (★5)

Chain DOCKER-ISOLATION (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       all  --  docker0 br-388e266f9993  0.0.0.0/0            0.0.0.0/0 (★6)
    0     0 DROP       all  --  br-388e266f9993 docker0  0.0.0.0/0            0.0.0.0/0 (★7)
 1427 1088K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination
 1427 1088K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0
```

まず、br-388e266f9993 は Docker ホストに追加されたインタフェースです。
コンテナのデフォルトゲートウェイとなります。

以下、★x についての説明を記述します。
尚、説明において br-388e266f9993 に所属するコンテナネットワークをコンテナネットワークと呼ぶことにします。

* (★1) 外部からコンテナネットワークへの通信で、ステータスが RELATED 又は ESTABLISHED のものを許可する (コンテナと接続完了した通信は許可する)
* (★2) DOCKER チェーンが許可する通信であれば、外部からコンテナネットワークへの通信を許可する
* (★3) コンテナネットワークからコンテナネットワーク以外への通信を許可する
* (★4) コンテナネットワーク間の通信を許可する
* (★5) 外部からコンテナネットワークへの 172.18.0.4:3000 に対する TCP 通信を許可する
* (★6) Docker ホストからコンテナネットワークへの通信を拒否する
* (★7) コンテナネットワークから Docker ホストへの通信を拒否する

★5に書かれている設定が docker-compose.yml に ports で書かれた内容が反映された設定です。

```yaml:docker-compose.yml
version: '3'

services:
  app:
    ports:
      - 3000:3000
  : <snip>
```

このように、docker-compose によりコンテナを起動すると、既存の FORWARD チェーンにルールが追加され、その設定によってコンテナと外部ネットワーク間の通信が制御されます。

ここで、FORWARD チェーンに追加されるルールは DOCKER-USER, DOCKER-ISOLATION よりも下で docker0 に関する設定より上に位置するように挿入されるようでした。

# iptables について

参考情報：[Linux 2.4 Packet Filtering HOWTO](http://www.netfilter.org/documentation/HOWTO//packet-filtering-HOWTO.html)
参考情報：[Iptables Tutorial 1.2.2](https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html)
参考情報：`man iptables`

iptables はパケット処理（パケット送受信やルーティング、NAT 等）をする際に、特定のフィルタ処理（パケット破棄・DNAT/SNAT・パケットロギング 等）を行うことが出来るソフトウェアです。

iptables ではパケット処理を行う目的に応じて、複数のフィルタルールをまとめて**テーブル**と呼ばれる名前で管理する。（正しくはフィルタルールではなく、それらを複数まとめて処理フェーズの名前で管理する**チェーン**を管理するのがテーブルである）
テーブルは既定されているもののみ扱うことができ、テーブルの追加や削除はできない。

先に紹介した通り、Linux の場合 Docker コンテナの通信は iptables によって制御されています。

テーブルには次のものがある。（iptables v1.6 にて確認）

- filter テーブル（オプションでテーブルを指定しなかった場合のデフォルト値）
    - 受信・送信・ルーティングするパケットに対して設定するフィルタルールを管理するテーブルである。
    - 受信後フィルタとして **INPUT チェイン**、送信後フィルタとして **OUTPUT チェイン**、ルーティング時フィルタとして **FORWARD チェイン**が既定で用意されている。
- nat テーブル
    - ネットワークアドレス変換（DNAT / SNAT / MASQURADE / REDIRECT）やポートフォワード等、パケットの送信元・送信先情報を変更する目的で、パケットに対して設定するフィルタルールを管理するテーブルである。
    - 受信後フィルタとして **PREROUTING チェイン**、変更後のパケットの送信前フィルタとして **OUTPUT チェイン**、変更後のパケットの送信後フィルタとして **POSTROUTING チェイン**が既定で用意されている。
    - nat テーブルでは DROP アクションを持つフィルタルールは登録できない。（あくまでネットワークアドレスの書き換えに使う）
- mangle テーブル
    - TOS / TTL 等を書き換えるような特別な目的でパケットに対して設定するフィルタルールを管理するテーブルである。
    - POSTROUTING チェーン、OUPUT チェーン、INPUT チェーン、FORWARD チェーン、PREROUTING チェーンが既定で用意されている。（Linux Kernel 2.4.18 以降）
        - Linux Kernel 2.4.17以前：PREROUTING チェーン、OUTPUT チェーン のみであった
        - Linux Kernel 2.4.18以降：INPUT チェーン、FORWARD チェーン、POSTROUTING チェーン が追加された
- raw テーブル
    - コネクション追跡を行わないよう NOTRACK ターゲットを適用するためのフィルタルールを管理するテーブルである。NOTRACK ターゲットが適用されると、conntrack は該当のパケットに対するコネクション追跡を行わなくなる。（参考情報：[Iptables Tutorial 1.2.2 - The conntrack entries](https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html#THECONNTRACKENTRIES)）
    - PREROUTING チェーンと、OUTPUT チェーンしかない。（conntrack が処理される前段階のものがこの 2 つだけ）
- security テーブル
    - 強制アクセスコントロール（Mandatory Access Control）を行う目的でパケットに対して設定するフィルタルールを管理するテーブルである。SELinux で実装されている。
    - INPUT チェーン、OUTPUT チェーン、FORWARD チェーンが既定で設定されている。

上記テーブルのフィルタ処理は次のフローで処理されます。

![tables_traverse.jpg](https://www.frozentux.net/iptables-tutorial/images/tables_traverse.jpg)
(Iptables Tutorial 1.2.2 より引用)

# docker-compose で起動させた Docker コンテナから送出するパケットを制限する

これまで見てきた内容を踏まえて、Docker コンテナから送出するパケットを制御する方法として次の手法を取ることにしました。

* docker-compose は systemd の Unit として自動起動させる (参考 [URL](https://gist.github.com/skomma/c4514e84b6a1dcd22d31516f7acc9c2e))
    * 但し、docker network は停止時に破棄しないよう設定する (`ExecStop=/usr/local/bin/docker-compose down` は指定しない)
    * ※ docker network が作成されるタイミングで iptables の FORWARD チェーンに最優先のルールが追加されるため、パケット制御するルールを優先させるために network を破棄しないようにする
* docker-compose で作成する network の IP アドレスは subnet で指定する (仮に 172.20.0.0/16 とします)
    * ※ subnet を指定しない場合、172.18.0.0/16, 172.19.0.0/16, ... と自動設定されます
    * ※ subnet が既に使われている場合は、その IP アドレスを避けて自動設定されます
    * ※ 固定指定された場合に subnet が同じ場合はコンテナが起動しません
* Docker デーモンが起動した後に FORWARD チェーンにルールを追加する
    * ルールが最優先されるように 1 番目に挿入する
        * ※ Docker デーモンが起動する前にルールを追加すると、Docker デーモンが起動した際に追加されるルールが優先されます
    * ルールを追加するため、Systemd で docker service に対して `ExecStartPost` を設定する
* FORWARD チェーンに挿入するルールは IP アドレスをベースとする

以下、手順です。

```bash:Systemdのdocker.serviceに起動後設定を追加するよう設定する
$ sudo systemctl edit docker
```

下記内容を記述して保存する。(/etc/systemd/system/docker.service.d/override.conf に保存される)

```/etc/systemd/system/docker.service.d/override.conf(例としてプライベートアドレスに関しては192.168.100.[12]への通信のみを許可している)
[Service]
ExecStartPost=/sbin/iptables -N DOCKER-OUTBOUND-FILTER
ExecStartPost=/sbin/iptables -A DOCKER-OUTBOUND-FILTER -s 172.20.0.0/16 -d 172.20.0.0/16 -j ACCEPT -m comment --comment "Accept packets between Docker containers"
ExecStartPost=/sbin/iptables -A DOCKER-OUTBOUND-FILTER -s 172.20.0.0/16 -d 192.168.100.1 -j ACCEPT -m comment --comment "Accept packets between Docker containers and HTTP Proxy Server"
ExecStartPost=/sbin/iptables -A DOCKER-OUTBOUND-FILTER -s 172.20.0.0/16 -d 192.168.100.2 -p udp --dport 53 -j ACCEPT -m comment --comment "Accept packets between Docker containers and DNS Server"
ExecStartPost=/sbin/iptables -A DOCKER-OUTBOUND-FILTER -s 172.20.0.0/16 -d 192.168.0.0/16 -j DROP -m comment --comment "Drop packets from Docker containers to Private Network Address"
ExecStartPost=/sbin/iptables -A DOCKER-OUTBOUND-FILTER -j RETURN
ExecStartPost=/sbin/iptables -I FORWARD 1 -j DOCKER-OUTBOUND-FILTER
```

```bash:コンテナを起動させる(例として/etc/docker-compose/some-compose-app/docker-compose.ymlを起動している)
$ sudo systemctl start docker-compose@some-compose-app
$ sudo systemctl enable docker-compose@some-compose-app
```

以上で次回 OS 起動時に Docker コンテナから送出するパケットを制御できます。

尚、OS 起動後に docker-compose で 2 種類のコンテナ群が起動した際の iptables の結果を参考に記載します。

```
Chain INPUT (policy ACCEPT 45 packets, 4833 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
   23  1172 DOCKER-OUTBOUND-FILTER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   23  1172 DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   23  1172 DOCKER-ISOLATION  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0
   12   512 ACCEPT     all  --  *      br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABL
ISHED
   11   660 DOCKER     all  --  *      br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br-ccaef8da7d18 !br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0
   11   660 ACCEPT     all  --  br-ccaef8da7d18 br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  *      br-3b054d11a74d  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABL
ISHED
    0     0 DOCKER     all  --  *      br-3b054d11a74d  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br-3b054d11a74d !br-3b054d11a74d  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br-3b054d11a74d br-3b054d11a74d  0.0.0.0/0            0.0.0.0/0

Chain OUTPUT (policy ACCEPT 27 packets, 4481 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain DOCKER (3 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     tcp  --  !br-ccaef8da7d18 br-ccaef8da7d18  0.0.0.0/0            172.19.0.4           tcp dpt:3000


Chain DOCKER-ISOLATION (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       all  --  br-ccaef8da7d18 docker0  0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  docker0 br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  br-3b054d11a74d docker0  0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  docker0 br-3b054d11a74d  0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  br-3b054d11a74d br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  br-ccaef8da7d18 br-3b054d11a74d  0.0.0.0/0            0.0.0.0/0
   23  1172 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain DOCKER-OUTBOUND-FILTER (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     all  --  *      *       172.20.0.0/16        172.20.0.0/16        /* Accept packets between Docke
r containers */
    0     0 ACCEPT     all  --  *      *       172.20.0.0/16        192.168.100.1        /* Accept packets between Docke
r containers and HTTP Proxy Server */
    0     0 ACCEPT     udp  --  *      *       172.20.0.0/16        192.168.100.2        udp dpt:53 /* Accept packets be
tween Docker containers and DNS Server */
    0     0 DROP       all  --  *      *       172.20.0.0/16        192.168.0.0/16       /* Drop packets from Docker con
tainers to Private Network Address */
   23  1172 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination
   23  1172 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0
```

# 最後に

紹介した方法では docker-compose が作成する network が再作成されたタイミングでルールの優先度が変わり、送出パケットの制御が出来なくなる点が問題です。(下記のように docker-compose コンテナ用に作成した network 用のルールが DOCKER-OUTBOUND-FILTER より優先されます)

```
Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 DOCKER-ISOLATION  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  *      br-c4d330f8b3c3  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 DOCKER     all  --  *      br-c4d330f8b3c3  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br-c4d330f8b3c3 !br-c4d330f8b3c3  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br-c4d330f8b3c3 br-c4d330f8b3c3  0.0.0.0/0            0.0.0.0/0
 1688  189K DOCKER-OUTBOUND-FILTER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0
 1669  188K ACCEPT     all  --  *      br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
   19  1140 DOCKER     all  --  *      br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br-ccaef8da7d18 !br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0
   19  1140 ACCEPT     all  --  br-ccaef8da7d18 br-ccaef8da7d18  0.0.0.0/0            0.0.0.0/0
```

コンテナのバージョンアップ時などは docker-compose down を実施せずに、docker-compose stop, rm でコンテナのみを削除して network は削除しないようにするなど配慮が必要である。

もっと良い方法があれば追記します。