Docker起動時のiptables設定について調べてみた
Docker起動時のiptables設定について調べてみた内容をまとめました。
natテーブルしか書いてません。
テーブル
- filter パケットの許可、破棄、拒否などのフィルタリングをする
- nat 送信元、送信先のIPアドレスとポート番号の変換
その他はあまり使わないらしいので省略
テーブル
- PREROUTING パケットがネットワークインターフェースで受信された直後に、宛先のIPアドレスとポート番号を変更する。外部からのトラフィックを内部の特定のIPアドレスにリダイレクトしたりする。
- OUTPUT ローカルシステムから発信されるトラフィックに適用される。自分のシステムから外部へのリクエストのコントロールに用いられる。
- POSTROUTING ルーティングの決定後、パケットがネットワークインターフェースから送信される直後に適用され、送信元のIPアドレスとポート番号を変更する。外部のシステムに対して自身のシステムがどのように見える化を制御する。
ターゲット
- MASQUERADE 外部ネットワークにアクセスするときに、プライベートIPアドレスからパブリックIPアドレスへの変換(NAT)を行う技術。
- DNAT 宛先のIPアドレスを別のIPアドレスに変換する処理。ファイアウォール、ルーター、プロキシサーバーなどで利用される。ssl(443)で受けて、アプリケーションサーバー(80)に転送するなどできる。
filterテーブルの設定内容
後日。
Dockerでサーバーを立ち上げていると、Dockerで指定したポートへのアクセスはDOCKER-USERチェーンに流される。
-A INPUT -i lo -j ACCEPT
ループバックインターフェイス(主にlocalhost)への接続をすべて許可する
-A DOCKER-USER -s 172.17.0.0/16 -p tcp -m tcp --dport 5432 -j ACCEPT
Dockerネットワーク内の任意のホストから5432ポートへのアクセスを許可する
※ 172.17.0.0/16は、DockerのデフォルトブリッジネットワークのIPの範囲。
-A DOCKER-USER -p tcp -m tcp --dport 8443 -j ACCEPT
8443ポートへのアクセスを許可する。
-A DOCKER-USER -j REJECT --reject-with icmp-port-unreachable
DOCKER-USERの一番最後に設定して、設定のないポートを全て拒否し、それを通知する。
※ REJECTとDROPの違いは、REJECTは拒否メッセージを返すが、DROPは返さない。
※ --reject-withは、拒否メッセージを指定するために使用される。
※ icmp-port-unreachableは、ポートが接続不能であることを示すメッセージを返す。
natテーブルの設定内容
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
PREROUTINGチェーンにルールを追加。宛先タイプ(--dst-type)がLOCALのパケットをDOCKERチェーンにジャンプ(-j)させる。
※ --dst-type LOCALとは、ローカルホストアドレス(127.0.0.0/8)宛のパケット、ネットワークインターフェースがeth0, wlan0などのパケットなどが当てはまる。
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
OUTPUTチェーンにルールを追加。宛先が127.0.0.0/8でない、かつ宛先タイプ(--dst-type)がLOCALのパケットをDOCKERチェーンにジャンプ(-j)させる。
※ 127.0.0.0/8とは、ローカルホストまたはループバックアドレスのこと。
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
POSTROUTINGチェーンにルールを追加。ソースアドレスが172.17.0.0/16で、アウトバウンドインターフェースがdocker0でないパケットにMASQUERADEのアクションを適用する
=docker0インターフェースから出力されるトラフィックをマスクして、DockerホストのIPアドレスに変換する
※ 172.17.0.0/16は、DockerのデフォルトブリッジネットワークのIPの範囲。
※ docker0は、デフォルトブリッジネットワークのインターフェースで、新しく作成されたコンテナはこのネットワークに接続される。
※ ブリッジネットワークとは、物理的に異なる2つ以上のネットワークセグメントを接続し、それらを1つのネットワークとして動作させる概念。Dockerの文脈ではコンテナ間の通信を可能にするため使用される。
※ アウトバウンドインターフェースとは、特定のコンテナから外部ネットワークへのトラフィック処理するネットワークインターフェース。
-A POSTROUTING -s 172.18.0.0/16 ! -o br-d9618c0af0c4 -j MASQUERADE
POSTROUTINGにルールを追加。ソースアドレスが172.18.0.0/16で、アウトバウンドインターフェースが br-d9618c0af0c4でないパケットにMASQUERADEのアクションを適用する。
※ 172.18.0.0/16は、Dockerが追加で作成したブリッジネットワーク。
-A POSTROUTING -s 172.18.0.2/32 -d 172.18.0.2/32 -p tcp -m tcp --dport 5432 -j MASQUERADE
POSTROUTINGにルールを追加。送信元も宛先もIPが172.18.0.2/32で、宛先ポートが5432のパケットにMASQUERADEのアクションを適用する。コンテナ内部通信の変換。
-A DOCKER -i docker0 -j RETURN
-A DOCKER -i br-d9618c0af0c4 -j RETURN
アウトバウンドインターフェースがdocker0またはbr-d9618c0af0c4であるパケットをRETURNする(親のチェーンに戻す)アクション。
-A DOCKER ! -i br-805add1a2aac -p tcp -m tcp --dport 5432 -j DNAT --to-destination 172.18.0.2:5432
ネットワークインターフェースがbr-805add1a2aacでなく、宛先ポートが5432のTCPパケットに、DNATアクションを適用する。送信先のアドレスを172.18.0.2:5432に書き換える。
あとがき
何に使われているかわからない設定も多かったが、Dockerのネットワークの理解が少し深まった。
便利なコマンド
sudo systemctl restart docker
Dockerデーモンを再起動する。これでIPテーブルの設定が再設定される。
docker network inspect bridge
DockerのデフォルトブリッジネットワークのIPの範囲を調べる。(Subnetを使う)
watch "sudo iptables -nvL"
filterテーブルの設定をリアルタイムで確認する。
watch "sudo iptables -nvL -t nat"
natテーブルの設定をリアルタイムで確認する。
sudo iptables -L --line-numbers
iptablesの設定を番号付きで確認する。削除するのに便利。
sudo iptables -D INPUT 1
INPUTチェーンの1番目のルールを削除する。番号は適切なのに変える。
sudo iptables -I INPUT 2 -p tcp -m tcp --dport 22 -j ACCEPT
INPUTチェーンの2番目にルールを追加する。以降のルールが繰り下がる。
sudo iptables -Z
パケットカウンタをリセットする。
sudo iptables-save > iptables.rule
iptablesの設定をファイルに保存する。
sudo iptables-restore < iptables.rule
iptablesの設定をファイルから読み込む。
Tips
iptables-restoreで書き込むとブリッジネットワーク名に変更が入ってバグったりするので、dev環境以外は-Iとかで逐一丁寧に設定したほうがいい。
よさげな記事
Discussion