iptablesでdockerコンテナーへの外部接続を制限する手順は?


20

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

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

以下の仮定を前提として、誰かが私の目標を達成する方法の例を提供できますか?

  • 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アドレスのみにバインドできてうれしいですが、ドッカープロセスとホストの再起動に耐えるiptables転送ルールを適切に設定する方法についての指示が必要です。

ありがとう!

回答:


15

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とにかく使用する方が安全です。


これを含む ように編集する必要があり--ctdirますか?私が使用する-m conntrack --ctstate NEW --ctorigdstport 3306 --ctdir ORIGINAL
19:41にlonix

@Ionix、はい、そうする必要がありますが、なぜそれが私を混乱させているのかだけを解決しました。説明を少し追加しました。
SystemParadox

1
デフォルトのDOCKER-USERテーブルには次のエントリが含まれています:-A DOCKER-USER -j RETURNを使用すると、上記の前に実行されます-A。解決策は、でルールを逆順で先頭に挿入すること-Iです。
BMitch

@BMitchまたは、さらに良いことに、すべてのルールを新しいFILTERSチェーンに追加し、-I(あなたが言ったように)新しいルールを挿入して、それにジャンプします。-I INPUT -j FILTERSそして-I DOCKER-USER -i eth0 -j FILTERS
lonix

@BMitchしかし、私は自分のサーバーをチェックしましたが、戻り規則はありません。おそらく最新のdockerバージョンはそれを挿入しませんか?-Iただし、安全のために使用することをお勧めします。
lonix

8

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

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

-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

現在、MySQLのポートは外部アクセス(eth0)からブロックされています。これは、Dockerが世界のポートを開くと考えられている場合でも同様です。(これらのルールは、外部インターフェースがeth0であると仮定しています。)

最終的には、ポートをロックダウンしようとしてあまりにもめちゃくちゃになった場合、最初にiptablesをクリーンアップしてからdockerサービスを再起動する必要があります。


このDOCKER-USERテーブルが他のユーザーが追加したテーブルと異なる理由がわかりません。フィルタが事前に適用されていないため、インターフェイス名を自分で指定する必要があります。「MY-CHAIN」を作成し、それをFORWARDチェーンに挿入すると、同じ結果になりますか?
ColinM

はい、違いがあります。DockerはDOCKER-USERチェーンをFORWARDチェーンに挿入するからです。 -A FORWARD -j DOCKER-USER -A FORWARD -j DOCKER-ISOLATION そのため、カスタム命令はDOCKERチェーンの前に実行されます。
ck1

--dportDOCKER-USERの内部で使用する場合、これは公開されたポートではなく、コンテナサービスの内部 IPと一致する必要があることに注意してください。これらはしばしば一致しますが、常にではなく、これは他のサービスと簡単に競合する可能性があるため、このDOCKER-USERソリューションは中途半端だと私はまだ主張しています。
コリン

4

更新:2015年に有効ですが、このソリューションはそれを行う正しい方法ではなくなりました。

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

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オプションに触れませんでした。


1
使用する場合iptables -vnL DOCKER、宛先ポートはコンテナ内のすべてのポートです。私がそれを正しければ、それは上記のルール3306がコンテナ内のポートにのみ影響することを意味します-つまり、あなたが-p 12345:3306コンテナにいた場合、あなたのルールはアクセスをロックダウンするのに必要なルールのままです(つまり--dport 12345動作しません) 、DOCKERチェーンのACCEPTルールはpost-NATであるためです。
サンサイド

そうです、ルールはコンテナ内のポートに関連する必要があります。
GGGforce

1
たとえば、内部NGINXを使用してリバースプロキシを実行する複数のコンテナー(たとえば、Zabbix、カスタムロードバランサーなど)を実行する場合は、コンテナーのIPを事前に知る必要があるので、それはちょっといです。私はまだ--iptables=false、必要のない問題の解決策を探していますが、これはそれらのすべての最悪の選択のようです。
サンサイド

ありがとうございました!何時間も検索した結果、あなたは私の問題を解決しました。これで、やっと世界中の人にソフトな腹部をさらすことなく、私の自宅のIPアドレスだけにMySQLを投獄することができます。
マットカバナ

1
DOCKERチェーンは、ユーザーが直接操作することは想定されていません!そのためにDOCKER-USERチェーンを使用します。受け入れられた答えを確認してください。
ポールセバスチャンマノール

3

更新:この回答はまだ有効ですが、@ SystemParadox DOCKER-USERと組み合わせて使用した回答の--ctorigdstport方が優れています。

再起動後も持続し、内部ポートではなく公開ポートに影響を与えることができるソリューションを次に示します。

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/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.