web-dev-qa-db-ja.com

iptablesを使用してDockerコンテナーへの外部接続を制限する手順は?

私の目標は、DockerコンテナーへのアクセスをいくつかのパブリックIPアドレスに制限することです。私の目標を達成するためのシンプルで繰り返し可能なプロセスはありますか? Dockerのデフォルトオプションを使用しているときにiptablesの基本のみを理解していると、非常に難しいことに気づきました。

コンテナーを実行し、パブリックインターネットから見えるようにしたいのですが、選択したホストからの接続のみを許可します。デフォルトのINPUTポリシーをREJECTに設定して、ホストからの接続のみを許可することを期待しています。しかし、DockerのNATルールとチェーンが邪魔になり、入力ルールが無視されます。

誰かが次の仮定の下で私の目標を達成する方法の例を提供できますか?

  • Eth0でパブリックIP 80.80.80.80をホストする
  • Eth1のホストプライベートIP 192.168.1.10
  • docker run -d -p 3306:3306 mysql
  • ホスト4.4.4.4および8.8.8.8以外のホスト/コンテナ3306へのすべての接続をブロックします

コンテナーをローカルIPアドレスのみにバインドしても問題ありませんが、Dockerプロセスとホストが再起動しても生き残るiptables転送ルールを適切に設定する方法の説明が必要になります。

ありがとう!

23
GGGforce

Dockerのファイアウォールルールを使用する場合は、次の2つの点に注意してください。

  1. Dockerによってルールが破壊されないようにするには、_DOCKER-USER_チェーンを使用します
  2. DockerはPREROUTINGテーブルのnatチェーンでポートマッピングを行います。これはfilterルールの前に発生するため、_--dest_および_--dport_はコンテナーの内部IPおよびポートを参照します。元の宛先にアクセスするには、_-m conntrack --ctorigdstport_を使用できます。

例えば:

_iptables -A DOCKER-USER -i eth0 -s 8.8.8.8 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP
_

注:_--ctdir ORIGINAL_がない場合、これは、コンテナから他のサーバーのポート3306への接続で返される応答パケットにも一致します。私のように最初のルールが_-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT_の場合、これは厳密には必要ありません。すべての応答パケットを処理するためですが、それでも_--ctdir ORIGINAL_を使用する方が安全です。

20
SystemParadox

Docker v.17.06には、DOCKER-USERと呼ばれる新しいiptablesチェーンがあります。これはカスタムルール用です: https://docs.docker.com/network/iptables/

チェーンDOCKERとは異なり、コンテナーの構築/開始時にリセットされません。したがって、Dockerをインストールしてコンテナを起動する前でも、サーバーをプロビジョニングするためにこれらの行をiptables構成/スクリプトに追加できます。

-N DOCKER
-N DOCKER-ISOLATION
-N DOCKER-USER
-A DOCKER-ISOLATION -j RETURN
-A DOCKER-USER -i eth0 -p tcp -m tcp --dport 3306 -j DROP
-A DOCKER-USER -j RETURN

これで、Dockerが世界のポートを開いたとしても、MySQLのポートは外部アクセス(eth0)からブロックされます。 (これらのルールは、外部インターフェースがeth0であることを前提としています。)

最終的には、iptablesをクリーンアップして、最初にdockerサービスを再起動する必要があります。

8
ck1

UPDATE:この回答はまだ有効ですが、DOCKER-USER--ctorigdstportと組み合わせて使用​​する@SystemParadoxによる回答の方が優れています。

これは、再起動の間も持続し、internalポートではなくexposedポートに影響を与えることができるソリューションです。

iptables -t mangle -N DOCKER-mysql
iptables -t mangle -A DOCKER-mysql -s 22.33.44.144/32 -j RETURN
iptables -t mangle -A DOCKER-mysql -s 22.33.44.233/32 -j RETURN
iptables -t mangle -A DOCKER-mysql -j DROP
iptables -t mangle -A PREROUTING -i eth0 -p tcp -m tcp --dport 3306 -j DOCKER-mysql

このメソッドを使用して、環境変数を使用するか、etcdで動的に(またはその両方を使用して)、iptablesを自動的に管理するDockerイメージを作成しました。

https://hub.docker.com/r/colinmollenhour/confd-firewall/

4
ColinM

[〜#〜] update [〜#〜]:2015年には有効でしたが、このソリューションはもはや正しい方法ではありません。

答えは、Dockerのドキュメント https://docs.docker.com/articles/networking/#the-world にあるようです

Dockerの転送ルールでは、デフォルトですべての外部ソースIPが許可されます。特定のIPまたはネットワークのみがコンテナーにアクセスできるようにするには、DOCKERフィルターチェーンの先頭に否定ルールを挿入します。たとえば、ソースIP 8.8.8.8のみがコンテナーにアクセスできるように外部アクセスを制限するには、次のルールを追加できます:iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

私がやったことは:

iptables -I DOCKER -i eth0 -s 8.8.8.8 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER -i eth0 -s 4.4.4.4 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER 3 -i eth0 -p tcp --dport 3306 -j DROP

--iptablesまたは--iccオプションには触れませんでした。

4
GGGforce