web-dev-qa-db-ja.com

Docker VPNは外部から利用可能なコンテナーに内部トラフィックをルーティングします

VPSで複数のDockerコンテナーを実行しています。 nginxプロキシ(Let'sEncryptからの証明書)によるSSL/TLS終了を取得するnextcloudインスタンスがあります。そして、私はopenvpnコンテナを持っています。そのDockerネットワークでは、VPN経由でアクセスできる他のサービス(独自のバインドDNSサーバーとGITサーバー)もホストしています。

次に、VPNを介して次のクラウドインスタンスにもアクセスしたいと思います。もともと私はこれは問題にならないと思っていました。nextcloudインスタンスはインターネット経由でアクセスでき、VPNもインターネットへの接続を提供するためです。しかし、残念ながら到達できません。 VPNを介してサーバー(httpまたはhttps)を丸めると、「ポート80/443:ホストへのルートがありません」というメッセージが表示されます。 VPNに接続しなくても、接続は正しく機能します。

Tracerouteを使用すると、VPSのパブリックIPに正しく到達することがわかります。したがって、ルーティングに問題があると結論付けます。 VPSのパブリックIPのポート80/443をターゲットとするトラフィックは、nginxプロキシコンテナー(上記のポートを公開)に転送/ルーティングされません。

私が理解したように、Dockerはfirewalld/iptablesを使用して、コンテナー間およびコンテナー間のトラフィックをルーティングします。したがって、インターネットからのトラフィック以外のルールがVPNトラフィックに適用されます。 パブリックIPアドレスへのVPNトラフィック(サーバー内部)が対応するコンテナーに正しく転送されるように、どのように構成する必要がありますか? VPNとNoの間の接続を一定/変更せずに維持したい-VPNの状態。これにより、Nextcloudアプリが混乱しないようになっています。

私が試したこと:回避策の可能性を試しました。 VPNのDNSサーバーにネクストクラウドインスタンス用の独自のDNSエントリを追加できます。これは、ネクストクラウドアプリコンテナー(SSL/TLSの終了を失う)またはnginxプロキシのIPをポイントします。最後のケースでは、nginxプロキシは別のホスト名を使用しているため、トラフィックをnextcloudコンテナに転送しません。可能であれば、プロキシ設定を変更しないでください。コンテナの起動時に、またはletsencryptコンパニオンコンテナから自動的に入力されるためです。また、証明書は使用されているFQDNと一致しません。 (外部からと同じFQDNを使用できるように)実際の/パブリックDNS名でマスターゾーンを追加しようとすると、そのTLDからの他のすべてのドメインが転送されなくなります(バインドを構成する可能性はありますか?そのためですか?).

TL; DR: DockerコンテナーからパブリックVPS IPアドレスへのトラフィックは、外部からのトラフィックのように、正しいDockerコンテナーに転送されません。

使用されているコンテナーに関する詳細情報も必要な場合は、リンクとdocker-composeファイルを追加します。

編集:

[root@XXXXXXXX ~]# iptables -S FORWARD
-P FORWARD ACCEPT
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A FORWARD -o br-7e5cecc96f4a -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-7e5cecc96f4a -j DOCKER
-A FORWARD -i br-7e5cecc96f4a ! -o br-7e5cecc96f4a -j ACCEPT
-A FORWARD -i br-7e5cecc96f4a -o br-7e5cecc96f4a -j ACCEPT
-A FORWARD -o br-fd56ce52983e -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-fd56ce52983e -j DOCKER
-A FORWARD -i br-fd56ce52983e ! -o br-fd56ce52983e -j ACCEPT
-A FORWARD -i br-fd56ce52983e -o br-fd56ce52983e -j ACCEPT
-A FORWARD -o br-f1ef60d84b48 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-f1ef60d84b48 -j DOCKER
-A FORWARD -i br-f1ef60d84b48 ! -o br-f1ef60d84b48 -j ACCEPT
-A FORWARD -i br-f1ef60d84b48 -o br-f1ef60d84b48 -j ACCEPT
-A FORWARD -o br-b396aa5a2d35 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-b396aa5a2d35 -j DOCKER
-A FORWARD -i br-b396aa5a2d35 ! -o br-b396aa5a2d35 -j ACCEPT
-A FORWARD -i br-b396aa5a2d35 -o br-b396aa5a2d35 -j ACCEPT
-A FORWARD -o br-83ac9a15401e -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-83ac9a15401e -j DOCKER
-A FORWARD -i br-83ac9a15401e ! -o br-83ac9a15401e -j ACCEPT
-A FORWARD -i br-83ac9a15401e -o br-83ac9a15401e -j ACCEPT
-A FORWARD -d 192.168.122.0/24 -o virbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i lo -j ACCEPT
-A FORWARD -j FORWARD_direct
-A FORWARD -j FORWARD_IN_ZONES_SOURCE
-A FORWARD -j FORWARD_IN_ZONES
-A FORWARD -j FORWARD_OUT_ZONES_SOURCE
-A FORWARD -j FORWARD_OUT_ZONES
-A FORWARD -m conntrack --ctstate INVALID -j DROP
-A FORWARD -j REJECT --reject-with icmp-Host-prohibited
1
chrisl

Dockerはデフォルトで、異なるブリッジに接続されているコンテナの2つの間のトラフィックを許可しません。また、コンテナからdocker自体によって外部にマッピングされているポートへのトラフィックも許可されません。これはすべてiptablesで実装されています。

まず、ポートの外部へのマッピングはiptablesでも行われます。 natテーブルでDNATルールを使用します。これらのルールの場合、Dockerは別のDOCKERチェーンを作成するため、natPREROUTINGまたはOUTPUTから同じルールが適用されますテーブル。 DNATルールの前には、Dockerブリッジからのすべてのトラフィックを除外するRETURNジャンプがあります。それが最初のハードルです。

次のようになります。

-A DOCKER -i br-one -j RETURN
-A DOCKER -i br-two -j RETURN
-A DOCKER ! -i br-one -p tcp -m tcp --dport EXPOSEDPORT -j DNAT --to-destination 172.17.0.2:INTERNALPORT

そのローカルアドレスのみにポートを公開した場合、DNATルールは-d addressを持つこともできます。その前のDNATルールが原因で、どのDockerブリッジからのトラフィックもRETURNルールにヒットできません。また、その上に、DNATルールは、トラフィックが送信されたのと同じブリッジを通過するDNATを許可しません。いずれにしても、同じブリッジから[〜#〜] internalport [〜#〜]にすでに到達できるため、これは必要ありません。

異なるブリッジ上のコンテナ間のトラフィックの制限は、iptablesfilterテーブルに実装されています。 2つのカスタムチェーンがFORWARDチェーンの先頭にあり、そのチェーンのデフォルトポリシーはDROPです。 1つはユーザー定義のブリッジを持つコンテナ用で、もう1つはDockerブリッジを持つコンテナ用です:DOCKER-ISOLATION-STAGE-1。そのチェーンは再びDOCKER-ISOLATION-STAGE-2を使用します。両方の組み合わせは基本的に、トラフィックがDockerブリッジを去る場合、別のDockerブリッジに入るとすると、DROP it(ICMPシグナリングがないため、接続がハングするだけです...)

次のようになります。

-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A DOCKER-ISOLATION-STAGE-1 -i br-one ! -o br-one -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i br-two ! -o br-two -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-2 -o br-one -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o br-two -j DROP

したがって、ブリッジoneからのトラフィックが必要な場合は、ブリッジ上のコンテナによって外部に公開されているポートのDNATをヒットしますtwoそして、トラフィックを完全な接続に戻すには、いくつかのことを行う必要があります。

  • natテーブルのRETURNチェーンのDNATからのトラフィックを停止するDOCKERルールを削除します。ソースブリッジのRETURNを削除する必要があります。そのブリッジのコンテナがRETURN公開ポートにアクセスすることを許可しない場合は、宛先ブリッジにDNATを残すことができます。

    • iptables -t nat -D DOCKER -i br-one -j RETURN
    • iptables -t nat -D DOCKER -i br-two -j RETURN#br-oneの場合はオプション-> br-two
  • filterテーブルのDOCKER-ISOLATION-STAGE-2チェーンから両方のブリッジのDROPルールを削除します。

    • iptables -t filter -D DOCKER-ISOLATION-STAGE-2 -o br-one -j DROP
    • iptables -t filter -D DOCKER-ISOLATION-STAGE-2 -o br-two -j DROP

これでが開いています。

Dockerはそのルールを頻繁に更新しません(少なくとも、テストした19.03バージョンではそうではありません)。コンテナーを停止または開始または作成したときではなく、Dockerデーモンが再起動したときにのみルールセットが再構築されるようです。サービスの再起動に加えられた変更に対処して、永続的なものに保つことができます。

1
Gerrit