docker version
出力:
Client:
Version: 1.10.3
API version: 1.22
Go version: go1.5.3
Git commit: 20f81dd
Built: Thu Mar 10 15:54:52 2016
OS/Arch: linux/amd64
Server:
Version: 1.10.3
API version: 1.22
Go version: go1.5.3
Git commit: 20f81dd
Built: Thu Mar 10 15:54:52 2016
OS/Arch: linux/amd64
docker info
出力:
Containers: 14
Running: 5
Paused: 0
Stopped: 9
Images: 152
Server Version: 1.10.3
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 204
Dirperm1 Supported: false
Execution Driver: native-0.2
Logging Driver: json-file
Plugins:
Volume: local
Network: bridge null host
Kernel Version: 3.13.0-58-generic
Operating System: Ubuntu 14.04.4 LTS
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 7.793 GiB
Name: brm-pheonix-dev
ID: Y6Z4:6D53:RFOL:Z3CM:P7ZK:H6HL:RLV5:JT73:LZMC:DTBD:7ILK:2RS5
Username: benjamenmeyer
Registry: https://index.docker.io/v1/
追加の環境の詳細(AWS、VirtualBox、物理など):
Rackspace Cloud Server、Ubuntu 14.04、しかしそれは実際には問題ではないはずです
問題を再現する手順:
受け取った結果を説明してください。
root @ brm-pheonix-dev :〜/ rse#iptables --list DOCKER
チェーンドッカー(1件の参照)
ターゲットプロトオプトソース宛先
ACCEPTtcp-どこでも172.17.0.2tcp dpt:6379
期待した結果を説明してください。
root @ brm-pheonix-dev :〜/ rse#iptables --list DOCKER
チェーンドッカー(1件の参照)
ターゲットプロトオプトソース宛先
ACCEPT tcp-127.0.0.0 / 24 172.17.0.2 tcp dpt:6379
ACCEPT tcp-172.16.0.0 / 16 172.17.0.2 tcp dpt:6379
重要と思われる追加情報(たとえば、問題が発生するのはたまにしかありません):
デフォルトでは、dockerはセキュリティを破る方法でファイアウォールを変更しています。これにより、すべてのネットワークデバイスからのすべてのトラフィックがコンテナの公開されたポートにアクセスできるようになります。 2つのコンテナがあるサイトを考えてみましょう。コンテナAはNginxを実行している443を公開し、コンテナBはポート8000でAPIを実行します。コンテナAを公開して使用することが望ましいですが、ローカルホストとのみ通信できるようにコンテナBを完全に非表示にします。 (ユーザーによるテスト用)およびdockerネットワーク(コンテナーAとの通信用)。 また、テストの目的で、コンテナCを同じ種類の制限付きでコンテナBが使用するデータベースにすることが望ましい場合もあります。
これは、私が_考えた_サービスのログを監視しているため、一般に公開されていなかったためです。 侵入しようとしているソースからのログエントリを見つけた後、ファイアウォールルールを確認したところ、ソースアドレスまたはインターフェイスに制限がないことがわかりました。 私はUFWを使用しており、この特定のボックスへのSSHのみを許可しており、そのままにしておきたいと考えています。 これは、Dockerコンテナーを使用してサービスをデプロイすることに劇的な影響を与え、注意を怠ると潜在的なセキュリティ問題につながる可能性があります。
最善のセキュリティプラクティスは、デフォルトでネットワークを上記の望ましい効果の例のように機能するように制限し、ユーザーが適切なファイアウォールなどのルールを追加してそのような動作をオーバーライドできるようにするか、現在の動作に戻すオプションを用意することです。 レガシーの理由で、最新の状態で多くのことを壊してしまう可能性が低いことを私は知っています。 したがって、少なくとも今すぐオンにできる上記を有効にするオプションがあることは、良い最初のステップであり、おそらく後で多くの警告の後、それをデフォルトの動作にします。 デフォルトの動作が安全であると仮定すると、docker-compose ymlでこれを管理する機能(ファイアウォール->パブリックポートを有効にする、ip)を持つことは、何が起こっているかを視覚的に知らせるための優れた方法です。
--iptables = falseオプションを見つけましたが、すべてのルールを自分で設定する必要はありません。 私が反対しているのは、ルールのソース設定だけです。
確認はしていませんが、dockerでサポートされているすべてのファイアウォールで同じ問題が発生する可能性があります。
この問題は公開されたポートについて話しているので、それは完全に#14041ではありません。 ポートの公開は、サービスを外部に公開する方法であるため、ポートを公開してアクセスできるようにすることを目的としています。 開発環境で作業している場合は、ホストファイアウォールを使用してコンピューターの外部からポートへのアクセスを無効にするか、ポートを公開せずに直接サービスにアクセスするか、同じネットワーク上の他のコンテナーからアクセスすることができます。
新しいDockerネットワーク機能を使用して、まったく公開したくないサービスのプライベートネットワークを設定することをお勧めします。https://docs.docker.com/engine/userguide/networking/を参照して
それが私が最初に考えたものです。 しかし、ポート( EXPOSE
)を_公開_することは実際には何もしないので、少し混乱しましたが、ポート( -p
/ -P
)を_公開する_は実際にそれを公開しますホスト。
実際に_publishing_について話している場合、これは設計どおりです。
あなたの例では、コンテナBとCはそれらのポートを公開すべきではなく、コンテナAはDockerネットワークを介してそれらと通信できます。
docker network create mynet
docker run -d --net=mynet --name=api api-image
docker run -d --net=mynet --name=db database-image
docker run -d --net=mynet --name=web -p 443:443 nginx
これは「web」コンテナのみをホストに公開します。Webコンテナは名前を介して「API」および「データベース」コンテナにアクセスできます(つまり、 http:// api :80 /およびdb:3306(MySQLを想定))。
@justincormackなので、プライベートネットワークを使用しても問題が解決するとは思いません。 私の場合、コンテナ間でプライベートネットワークを使用していますが、ホストファイアウォールがプライベートネットワークへの公開を制限するように構成されていないため、コンテナは引き続き公開されています。
@thaJeztah問題は依然としてファイアウォールのサポートにあります
今、私はdocker-composeを介してこれを実行しています。 ただし、libnetwork機能にはファイアウォールルールでネットワークを制限する機能が_no_あるため、完全にdocker-composeの問題ではありません。iptablesルールにはソース指定がないため、dockerに依存してネットワークを構成する方法に関係なく、ファイアウォールルール(正しくなる可能性が高いため、これを行う必要があります)の場合、これが問題になります。 docker-compose.ymlファイルで次のことを考慮してください。
nginx:
build: ./docker/nginx/.
ports:
- "127.0.0.1:8080:80"
- "127.0.0.1:443:443"
environment:
DESTINATION_HOST: repose
links:
- repose
repose:
build: ./docker/repose/.
ports:
- "127.0.0.1:80:8080"
environment:
DESTINATION_HOST: phoenix
DESTINATION_PORT: 8888
links:
- phoenix
curryproxy:
build: ./docker/curryproxy/.
ports:
- "127.0.0.1:8081:8081"
external_links:
- rse_rse_1
- rse_rse_2
- rse_rse_3
phoenix:
build: .
ports:
- '127.0.0.1:88:8888'
links:
- curryproxy:curry
external_links:
- rse_rse_1:rse
- rse_rse_2
- rse_rse_3
- rse_cache_1:cache
volumes:
- .:/home/phoenix
上記は私のプロジェクトの1つからの抜粋です。 ホストからローカルでそれらすべてをテストできるようにしたいのですが、他の誰かがnginxインスタンス以外にアクセスできるようにしたくありません。
これがあなたの命名法にどのように変換されるかはわかりません...これは「公開」の側面の一部である可能性があり、私が言っていることを行うには公開機能を拡張する必要があります。
これが設計によるものである場合、見慣れないネットワーク(旅行など)ですべての開発者を極度のリスクにさらすため、セキュリティモデルとしては不十分です。
私が言ったように、私はデフォルトがすぐに変わることを期待していませんが、オプションを持つことは良い最初のステップでしょう。
それでは少し混乱していますが、接続できるものの外部の例をいくつか挙げていただけますか? バックエンドサービスは(デフォルトで) 172.17.0.0/16
ネットワーク上にあり、外部からアクセスすることはできません。外部ホストから定義されたルートへのルートがないため、最初は考えません。
外部IPが内部ネットワークにルーティングされるトラフィックがドロップされないプライベートIPでもある場合(パブリックからプライベートにルーティングされる必要があります)、潜在的な問題があります-それは問題ですか?
@justincormackなので、私は主に適切なプロキシを設定して、一部のサービスがプロキシ経由でのみヒットできるようにし(nginx-sslターミネーション)、認証プロキシを介してフィルタリングし(repose)、最後に別のサービスにオフにします(フェニックス)。 それらすべてが0.0.0.0インターフェースにバインドされていれば、私はあまり気にすることができません。 しかし、私はnginxに外部からアクセスできるようにしたいだけです(または、ここにnginxがない場合は、少なくとも休憩部分)。 たとえば、簡単な解決策は、構成に「127.0.0.1」を設定する必要はありませんが、Dockerネットワークとローカルのみの基本構成でファイアウォールを通過できるように指定するのが簡単なファイアウォールセクションを用意することです。会話が有効になっているホスト(ループバック)インターフェイス-次のようなもの
firewall:
external:
ports:
- 80
- 443
これで、_host_のネットワークマッピングをデフォルトの0.0.0.0マップではなく127.0.0.1に制限することで、状況をある程度緩和できます。 そうしないと、ブリッジングによってホストポートがDockerネットワークに転送されるため、これが実際に軽減されることに注意してください。
そして、はい、私はその制限が機能することを確認しました。 ただし、それでも潜在的な脆弱性は残り、ファイアウォールルールは実際に行われているものと一致しません。
別の例として、少し前にLinuxカーネルの脆弱性がありました(現時点では見つけるのに問題があります)。これは、IPtablesでアプリケーションで使用するために開かれているとマークされているが、実際にはアプリケーションに接続されていないポートに関連していました。 -たとえば、ローカルホストポート上にあるが、パブリックIPポート上にはない。 これにより設定される可能性があり、IPtablesルールをどこからでも接続できるように開いたままにするのではなく、予想されるネットワークに制限することをお勧めします。 私が言ったように、少なくとも指定するオプションがあります。 彼らはおそらくその特定の問題を修正しましたが、なぜ可能性を開いたままにするのですか?
IOW、それはすべてセキュリティに関するものです。
@BenjamenMeyer他のサービスにアクセスしたくない場合、なぜそれらのポートを公開するのですか? つまり、 "127.0.0.1:8081:8081"
は、Dockerネットワーク経由でのみアクセスされる場合は必要ありません(他のサービスはDockerネットワーク経由で直接接続します)
これに関連する問題の1つは、ポートを公開したいが、特定のIPアドレスのみにポートへのアクセスを許可したいということです。
たとえば、いくつかのコンテナでJenkins環境を実行しています。 マスターノードは「公開」されていますが、2つのオフィスだけがアクセスできるように、マスターノードをロックするためにかなり複雑なiptablesルールを作成する必要があります。
現在Dockerに組み込まれているこれを回避する方法はありますか? または、少なくとも推奨される方法はありますか? ドキュメントで、1つのIPアドレスへのアクセスを制限する方法を見てきました。 しかし、いくつかではありません。 これに関するもう1つの問題は、すでにiptables構成が設定されているサーバーがある場合、ルールを適用する前にすべてのルールをリセットする可能性があることです(したがって、複雑なルールを設定する必要がありました)。
@SeerUKが述べたのと同様の問題があります。 既存のファイアウォールルールが公開されたコンテナポートに適用されない場合、予想に反する不快な違反があります。 望ましい動作は次のとおりです(少なくとも私にとっては)
iptablesでこれを達成するための簡潔な方法はありますか、それともそのような構成を簡単に許可しませんか? 私はiptablesの知識が特に限られているので、我慢してください。 Dockerとの相互作用を理解しようとしているときに、最近それについての知識を習得しました。
私が実際に頼ったのは、かなり強力な専用サーバーでこれらのコンテナーを実際に実行しているため、Dockerを実行するKVM VMをセットアップし、さらにいくつかの標準のiptablesルールを使用してホストからのアクセスを制限しました。 。 VMには、サーバーからのみアクセスできる独自のネットワークインターフェイスがあるため、ホスト上のiptablesのポートへのアクセスを明示的に許可するルールを追加する必要があります。 パフォーマンスが少し失われましたが、それほど多くはありません。
@thaJeztahローカルシステムからアクセスして、簡単にテストできるようにしたいと思います。 たとえば、ヘルスエンドポイントを持つRESTful HTTP APIを設定し、ローカルホストを使用してcurl
を確実に実行できるようにします(他の人のためにこれを文書化する必要があり、変更されるIPアドレスは信頼できません)。 ほとんどの場合、開発環境では、コンテナーが相互に通信することだけが必要ですが、ホストからコンテナーにアクセスできるようにすることも必要です。
@SeerUKの場合、IPブロック(5.5.0.0/16-iptablesルールの送信元アドレスの有効なパラメーター)を設定できることは非常に良いことです。 IPtablesにはすでに制限を行う機能がありますが、dockerはそれを利用していません。
@thaJeztah "127.0.0.1:8081:8081"
明示的に設定して、外部ネットワークから遠ざけます。 公開されたポートを介してコンテナに侵入しようとしている人々から、Dockerコンテナにログが見つかりました。
現在の私の回避策は、外部にしたい環境が実際に外部であるか、セキュリティ上の目的で環境が適切に制限されているかを確認できないため、その日の出発前にDockerコンテナをオフにすることです。
@BenjamenMeyerこれを行う1つの方法は、コンテナでこれらのテストを実行することです。
docker run --net -it --rm --net=mynetwork healthchecker
ベンが明らかにしている問題は現実的で驚くべきものです(悪い組み合わせ)。 私のような多くの管理者は、実証済みのufwファイアウォールを使用しています。 Dockerはufwを実行してエンドランし、iptablesルールを変更すると、1)ufwがパケットフィルタリングルールの現在のステータスを誤って報告し、2)一見プライベートなサービスをパブリックネットワークに公開します。 dockerがsysadminコミュニティの良好な状態を維持するには、別のアプローチを考案する必要があります。 現在、ベンや私のように、うっかりしてより広いインターネットへのポートを開いた管理者がたくさんいます。 ベンや私とは異なり、彼らはまだそれを理解していません。
@thaJeztahは、コマンドラインを介して実行しており、IPアドレスを設定するだけでよい別のツールを使用していないことを前提としています。
たとえば、私はAPIに取り組んでいます。 私はそれをサポートするために本番環境でそのAPIを操作するために使用できるツールを持っています。 ツールとAPIの開発のために、ドッキングされたAPIにツールを向けたいだけです。 ツールはdockerについて何も知りませんし、そうすべきでもありません。 また、ツールを使用するためだけにDockerに配置する必要はありません。ローカルホストにのみ公開されているポートにツールを向けるだけで十分です。
@jcheroske同意しますが、その側面に良い解決策があるかどうかはわかりません。 そのためには、 ufw
よりスマートにして、作成に関与しなかったルールを検索してレポートできるようにする必要があります。 ufw
(またはAFAIKfirewalldなど)が知らない方法でiptables
ルールを調整できるソフトウェアはたくさんあります。 それを修正するための簡単な解決策もありません。
そうは言っても、Dockerがそれらと統合して、適切な構成ファイルをダンプして有効/無効にできるようにするか、それらのツールと統合して、フックされて情報を適切にダンプできるようにするとよいでしょう。 _その_側面が実際に解決されるとは思わない、より良い解決策があります。 ここでは、生成されるiptables
ルールの範囲を制限して、ソース(lo、eth0、127.0.0.0 / 24など)の指定を許可することにより、潜在的な影響を少なくとも最小限に抑えることが重要です。
あなたがそうする気があるなら、iptablesを使用することはこれを完全に可能にします。
これは、使用方法の簡略化された例です: https :
一番下で、1.2.3.4がポート8000(Dockerによって公開されている)へのアクセスを明示的に許可されていることがわかります。その後、そのポートへの他のすべてのものがドロップされます。 PRE_DOCKERチェーンはDOCKERチェーンの前に挿入されるため、最初にヒットします。つまり、DROPは、ブロックされたリクエストがDOCKERチェーンに到達するのを防ぎます。
Dockerにこの機能が組み込まれていないのは少し面倒ですが、今は回避できる可能性があります。
もう1つの方法は、外部ファイアウォールを使用することです。 AWSやScalewayのようないくつかの場所は、外部からボックスへのアクセスを管理できるセキュリティグループのようなものを提供し、そこからすべてのポートが同じように動作します。
私は実際にこれをUFWで機能させる方法を理解することができませんでした。 今のところ、解決策としてiptablesを使用することに満足しています。 これまでのところ、非常にうまく機能しているようです。
明らかに、UFWの周りにかなり複雑なファイアウォールルールのセットをすでに構築している場合、これはあまり優れたソリューションではありません。 ただし、iptables-persistentなどの使用は非常に簡単です。 iptablesではより「正常」に見えるこの方法へのアクセスを許可する別の方法を使用することもできます。
@BenjamenMeyerは、サブネットとip-rangeオプションを指定してユーザー定義のdocker network
を使用し、コンテナーに静的IPアドレスを割り当ててローカル開発に使用することを考えたことがあります。これにより、依存する必要がなくなります。 127.0.0.1などの仮想静的IP? これにより、ホストにプライベートなコンテナのポートマッピングをまとめて行う必要がなくなります。
docker network create --subnet=30.1.0.0/16 --ip-range=30.1.0.0/24 mynetwork
docker run --net=mynetwork --ip=30.1.1.1 --name=myservice1 xxxx
docker run --net=mynetwork --ip=30.1.1.2 --name=myservice2 yyyy
この設定では、myservice2はmyservice1
という名前でmyservice1に到達でき、静的IPに依存する必要もありません。 また、ホストはポートマッピングを必要とせずにstatic-ipに自由に到達できます。
また、compose 1.7では、コンテナーの静的IPアドレスを指定し、ネットワークのサブネットと範囲を指定できます。
私は簡単な回避策を見つけました。
1)/ etc / default / dockerを編集します: DOCKER_OPTS="--iptables=false"
2)ufwルールを追加します: ufw allow to <private_ip> port <port>
とても単純なので、なぜ--iptables=false
オプションがデフォルトではないのか不思議に思います。 すべてのDockerが実行する必要があるのに、なぜこのような状況を作り出すのかは、「ファイアウォールを実行している場合は、ファイアウォールに穴を開ける必要があります」と言うだけです。 何が足りないのですか?
https://fralef.me/docker-and-iptables.html
http://blog.viktorpetersson.com/post/101707677489/the-dangers-of-ufw-docker
命を救うためにdockerにiptablesの変更をやめさせることができません。 Ubuntu16.04で/ etc / default / dockerを無効に更新しようとしました
@enzeart /lib/systemd/system/docker.service
お試しください。
@SeerUKあなたの魂を祝福します
@enzeartを使用して、systemdを使用するホストで実行されるデーモンを構成するには、docker.unitファイル自体を編集するのではなく、「ドロップイン」ファイルを使用することをお勧めします。 そうすれば、dockerをアップグレードするときに問題が発生することはありません(新しいdocker.unitファイルがある場合)。 詳細については、 https: //docs.docker.com/engine/admin/systemd/#custom-docker-daemon-optionsを参照して
また、daemon.json構成ファイルを使用することもできます。https: //docs.docker.com/engine/reference/commandline/daemon/#daemon-configuration-fileを参照して
@mavenugoすでに
@jcheroskeは機能しますが、iptables
ルールが正しいことを確認する必要があります。これは最適ではなく、発生する可能性もほとんどありません。 docker
に自動的に実行させるため、この問題が発生します。
こんにちは、お願いします。 私もその問題だと思います。 Iptablesのコンテナチェーンはメインルールに従う必要があり、デフォルトではワールドに公開されません。
Docker(およびdocker-compose)に、そのポートにアクセスできるIPをホワイトリストまたはブラックリストに登録する機能が備わっていることを本当に望んでいます。
たとえば、次のようにします。
nginx:
ports:
- "8000:8000"
whitelist:
- 10.6.20.2
10.6.20.2のソースIPのみがこのホストのポート8000にアクセスできることを意味します。
@StefanPanait私はそのアイデアが本当に好きです。 また、ボリュームやアクセス/拒否リストと同様の構文で、次のように機能する可能性があります。
nginx:
access:
- "10.0.1.6:allow"
- "deny"
もちろん、コンテナ間の通信などを許可する必要があります。
@SeerUKコンテナ間通信をデフォルトにする必要がありますが、1つのコンテナがそのコンテナと通信することを禁止できないのはなぜですか? これはデバッグに非常に役立つ可能性があります...
それを行う適切な方法は、Dockerネットワークを分離することだと思いますが...それでも、次のようなことができると思います。
nginx:
access:
- "10.0.1.6:allow"
- "webapi:allow"
- "database:deny"
- "deny"
役に立つかもしれません...質問は、その程度まで実装を正当化するのに十分有用ですか? わからない。
現在、元の問題が解決されることを望んでいますが、最初から解決策に設計することに意味がない場合は、このような機能を追加できます(そうなる可能性があります)。
1つのコンテナがそのコンテナと通信することを禁止できないのはなぜですか? これはデバッグに非常に役立つ可能性があります
それはdocker network disconnect
ためでしたか? デバッグのためにコンテナをネットワークから切断し、 docker network attach
再接続できます
インターネットに公開されたサーバーで大量のポートが開いていることを発見したばかりの人のために、UFWを利用した後、私は掘り下げて次のことを発見しました。
UFWとDockerを搭載したUbuntu16.04には、新たな課題があります。 私はここに示すように、すべての手順をした: https://svenv.nl/unixandlinux/dockerufwしかし、私は16.04で動作するようにドッキングウィンドウプラスUFWを取得できませんでした。 言い換えれば、私が何をしたかに関係なく、すべてのDockerポートがインターネットにグローバルに公開されるようになりました。 私がこれを見つけるまで: http :
ファイル/etc/docker/daemon.jsonを作成し、次のファイルを入力する必要がありました。
{{
"iptables":false
}
次にsudo service docker stop
発行し、 sudo service docker start
最後にdockerはUFWの適切なルールに従っているだけです。
追加データ: https :
@thaJeztah
1つのコンテナがそのコンテナと通信することを禁止できないのはなぜですか? これはデバッグに非常に役立つ可能性があります
それは、Dockerネットワークの切断が目的だったのですか? デバッグのためにコンテナをネットワークから切断し、docker networkattachで再接続できます
また、ネットワーク接続を維持したい場合はどうなりますか? 例:コンテナーC、D、およびEによって提供されるサービスを維持しながら、コンテナーAのコンテナーBのサーバーからのヘルスチェックの失敗をテストします。ネットワーク全体を閉じるよりも、コンテナーBがコンテナーAに移動することを禁止する方が簡単です-コンテナーCもヘルスチェックに合格するには、コンテナBへのアクセスに依存します。
それでも、それは「元の問題を修正しよう」に耐えられません。
@ gts24興味深い発見。
私見ですが、全体的な問題は、Dockerは、文字通り他のすべてのプログラムと同様に、ファイアウォール(iptablesなど)にまったく触れてはならないということです。 私は、(例えば)にApacheをインストールしてリッスンするようにそれを伝えるときに0.0.0.0:80
それは、ファイアウォールのポート80を開くかどうか、私は私がしたいこと、それのために任意のルールを指定することができますどこに私の決断です。
Docker(および/または作成)構成ファイルのファイアウォールルールを再発明する代わりに、 PUBLISH
機能全体を非推奨にし、他のすべてのプログラムと同じように機能するように新しいLISTEN
機能を作成する必要があります。 せいぜい、dockerは、それを使用するシステム上で、ポート/コンテナーごとにデフォルトで無効にされたfirewalldサービスを作成できます。
@gcscagliaはデーモンに--iptables=false
し、それを取得する必要があります
@thaJeztah Dockerは、デーモンから必要なファイアウォールルール(または関連するパラメーターを使用したより具体的なトリガースクリプトフック)を取得する代替手段を提供しないため、この機能は
@thaJeztahタラダーが言ったこととまったく同じです。
--iptables=false
は、内部のコンテナ間ネットワークでさえ無効になっていると機能しないため、名前を--networking=false
変更する必要があります。 インバウンドファイアウォールルール(つまりLISTEN
)に穴を開けることなく、コンテナにポートとインターフェイスの組み合わせをリッスンさせるオプションは、これらすべてを解決し、下位互換性があり、 --iptables=true
を使用できるようにします。 。
このようなリッスンモードでは、「正しく機能」させたい人はPUBLISH
を使い続けることができ、制御したい人はLISTEN
使うことができます。
@gcscagliaわかりました。したがって、 --iptables
有効にしておくことはできますが、 -p
/ --publish
。 ポートをコンテナに転送するようにIPTablesルールを手動で設定できるはずです。 コンテナはすでに自身のプライベートIPアドレスと、コンテナ内のサービスがリッスンするポートをリッスンしています。
@thaJeztahいいえ、できません。 起動したばかりでファイアウォールルールが必要なコンテナさえあるとは思わないからです。 APIを使用して、リッスンしているホストポートでAPIを起動した人を知る方法もありません。
簡単な例。 Dockerコンテナを使用してJenkinsジョブを実行します。 Dockerが接続できるようにSSHポートを公開します。 それらは仕事が完了するとすぐに破壊されます。 Dockerは、これを--iptables = falseで機能させる方法を提供していません。これは、Jenkinsにホストポートを指示する方法がなく(Docker APIを使用してコンテナーを起動する)、スクリプトをトリガーしてセットアップする方法さえないためです。必要なファイアウォールルール。
あなたのアイデアは、永続的な、決して変更されないコンテナを手動で起動するという途方もなく単純なユースケースでのみ機能します。 コンテナに静的IPがない限り、この設定では、コンテナ内の単純な--restart = alwaysでさえ壊れます。
@taladar私はドッキングウィンドウが_not_は、ポートを開くためにiptablesの管理していて、彼らはiptablesの支配のどこにいる機能を要求し@gcscagliaのユースケースに返信しています。 つまり、手動で行わない限り、コンテナは公開されません。 また、私の返信では、 --iptables=false
使用しないように説明しましたが、有効にしておくために、 -p
/ --publish
機能(dockerに作成するように指示する)は使用しないでくださいIPTablesを介してアクセス可能なポート)。
@thaJeztah私のユースケースは正しいのですが、提案されたソリューションは、タラダーの場合と同じ理由で機能しません。何かを1回再起動すると、突然手動ルールを更新する必要があります。 再起動の通知に使用できるフックやトリガーがないため、このような更新を自動化できます(言うまでもなく、車輪の再発明を行いました)。
現在、私の場合の唯一の解決策は、Dockerホストとすべての外部ネットワークの間に別のファイアウォール(Dockerがアクセスできない)を配置することです。 しかし、Dockerが世界へのポートを開くこと
すべてを手に入れることはできないと思いますが、確かにイライラします。 私のLISTEN
アイデアについて機能リクエストを開く価値があると思いますか、それともDockerチームはそのような機能に興味がないでしょうか?
LISTEN
は何をしますか? EXPOSE
があり、コンテナがリッスンするポートに注釈を付けることができます。 トリガーの場合、Docker events
聞くことができます。
ここに改善の余地がないと言っているのではなく(調査されていることはわかっています)、あなたが何を期待しているのか疑問に思っているだけです
現在、あなたが言ったように、コンテナで実行されているすべてのサービスはコンテナのプライベートIPにバインドします( --net=host
などを使用しない場合)。 ホストとコンテナー間のこのような分離はまさにDockerのセールスポイントであるため、これは適切で望ましいことです。
ただし、現在、コンテナの外部で実行されているアプリケーション(ホスト上またはネットワーク上の他の場所)でコンテナ内で実行されているサービスにアクセスできるようにする場合は、そのサービスをホストのネットワークインターフェイスの1つでリッスンさせる手段が必要です。 ホストのインターフェースをコンテナーに公開せずにこの問題を解決するために、Dockerは-p
/ --publish
機能を作成しました。
私が提案しているのは、他のすべてのサービス/プログラムと同様に、 「1」のみを実行し、ユーザーの裁量で「2」を許可する機能( LISTEN
などの名前)です。
EXPOSE
に関しては、DockerイメージのメタデータのみであるAFAIKにより、ユーザーが-P
(すべてを公開)を指定したときにデーモンが何をすべきかを認識します。 おそらく私はそれについて間違っています、そして「公開された」ポートは再起動に抵抗する方法で転送することができます(ワールドワイドアクセスなしで)?
この問題のOPは、 -p
が「2」を実行する理由とDockerによる実行を停止する方法を正確に尋ねています。 デーモンレベルの設定(ネットワークの無効化以外)で解決できますが、下位互換性を維持するためには、新機能(つまり、 LISTEN
またはその他の名前)が最適です。
このような「箱から出してすぐに使える」効果を好む多くのユーザーが、ファイアウォール管理ソフトウェアが報告しない方法で、iptables / firewalld以外のプログラムがファイアウォールのポートを開くことを期待しているシステム管理者はいません。
3つの大きな問題があると思います。
おそらく、FILTERテーブルでポート公開を実装することは技術的に不可能であるため、1を修正することはできません。 少なくとも、これはどこかで大きな警告を受け取るはずです(修正2)が、理想的には、ファイアウォールルールを追加するallow
やdeny
など、ここの人々が提案したような新しいオプションで3を解決できます。公開/公開されたポートの特定のIPを自動的に許可または拒否します。
たとえば、ポート9200を公開する「elasticsearch」という名前のコンテナのallow: "tcp:{your_trusted_ip}"
は、次のようになります。
iptables -t mangle -N DOCKER-elasticsearch
iptables -t mangle -A DOCKER-elasticsearch -s {your_trusted_ip} -j RETURN
iptables -t mangle -A DOCKER-elasticsearch -j DROP
iptables -t mangle -I PREROUTING -p tcp --dport 9200 -j DOCKER-elasticsearch
これはDockerのドキュメントから非常に便利だと思いました: https ://docs.docker.com/engine/userguide/networking/default_network/container-communication/#communicating -to-the-outside-world
Dockerの転送ルールは、デフォルトですべての外部ソースIPを許可します。 特定のIPまたはネットワークのみがコンテナーにアクセスできるようにするには、DOCKERフィルターチェーンの先頭に否定されたルールを挿入します。 たとえば、ソースIP 8.8.8.8のみがコンテナにアクセスできるように外部アクセスを制限するには、次のルールを追加できます。
$ iptables -I DOCKER -i ext_if! -s 8.8.8.8 -j DROP
@jmimicoはい私は前にそれに出くわしたことがあります。 2つ以上のIPからのアクセスをどのように制限しますか?
Docketが、スクリプトに渡されたすべてのDocker内部情報をパラメーターとして使用してiptablesルールを作成する場所で、シェルスクリプトを実行するオプションを追加するだけで、何がそれほど難しいのでしょうか。 これにより、誰もが必要なルールを正確に作成できるようになります。 iptablesを実行した後に呼び出すことができるアクティブなコンテナーのスクリプトの再実行をトリガーする方法を追加します-他の理由でチェーンを復元またはフラッシュし、完了します。
ここで一部の人々が示唆しているように、Dockerは、フックスクリプトの配布セットによって、そのようなシステム上に構築できる、あらゆる種類の構築済みファイアウォールシナリオを再作成する必要はありません。 せいぜい、ローカルホストでのみ公開し、グローバルに公開する(Dockerが現在行っているように)ようなものが理にかなっているかもしれません。 IPTablesは柔軟性が高すぎるため、Dockerはすべてのシナリオを設定で直接モデル化することを望んでいません。
このチケットは一見永遠に存在し、現在の動作によりDockerの境界線が使用できなくなります(たとえば、適切な組み込みGCの欠如や、カーネルバグのない、パフォーマンスの高いストレージが1つしかないなど、このプロジェクトの機能を実装する標準的な方法のようです。バックエンド、...)そして、人々が自分の環境に合った独自のソリューションを実装できるようにする簡単なソリューションがあります。
@StefanPanait良い質問です。 私の賭けは、オブジェクトグループの使用を活用する必要があるということです。 オブジェクトグループにホワイトリストに登録されたIPを入力し、そのオブジェクトグループをDOCKERチェーンの最初の行で使用します。
例:
iptables -Ndocker-許可
iptables -A docker-allow -s 1.1.1.1 -j ACCEPT
iptables -A docker-allow -s 2.2.2.2 -j ACCEPT
iptables -A docker-allow -s 3.3.3.3 -j ACCEPT
iptables -A docker-allow -j DROP
iptables -I DOCKER -i ext_if -j docker-allow
DOCKERチェーンに追加されたルールが、デーモンの再起動などによって破壊されたことはありませんか? 手動ソリューションの問題は、正しく実行するのが難しいことだと思います。そのため、一般的なケース(個々のIPをブロック/許可)をより直接的にサポートする強力なケースがあります。
おそらくプラグインはこれをサポートするのに適切な場所でしょうか? たとえば、「ufw」プラグインはufw互換の方法でルールを追加して、ユーザーが通常のファイアウォールツールチェーンでファイアウォールを効果的に管理でき、Dockerサービスが通常のホストサービスのように動作するようにすることができます。
DOCKERチェーンに追加されたルールが、デーモンの再起動などによって破壊されたことはありませんか? 手動ソリューションの問題は、正しく実行するのが難しいことだと思います。そのため、一般的なケース(個々のIPをブロック/許可)をより直接的にサポートする強力なケースがあります。
ドロップルールをDOCKER-USERチェーンに追加すると、Dockerの再起動後も永続化できるようになります。
Docker v.17.06には、DOCKER-USERと呼ばれる新しいiptablesチェーンがあります。 これはカスタムルール用です。serverfaultに関する私の回答を参照してください: //serverfault.com/questions/704643/steps-for-limiting-outside-connections-to-docker-container-with-iptables/886257#886257
SFについてコメントしたように、このDOCKER-USERチェーンが他のユーザーが追加したチェーンと異なる理由がわかりません。フィルターが事前に適用されておらず、docker-container宛てのトラフィックだけでなくすべてのトラフィックをフィルターします。それでもインターフェース名を自分で指定する必要があり、iptables以外の専門家が重大な間違いを犯しがちです。
一方で、それでも「Dockerは唯一のiptablesユーザー」という考え方があり、Docker以外にもiptablesを使いたいと思っている人にはうんざりします。 したがって、ホスト全体をDockerだけに捧げる人々を除いて、潜在的なユーザー全体にとっては悪いことです。
OK、DOCKER-USERを使用すると、挿入の順序の問題が解決されます。これは、挿入が常に他のDocker関連のルールの前にチェーンに含まれるようにすることで解決します。 ただし、この時点で--dport
は、公開されたポートではなく、Dockerコンテナー内のサービスのポートであるため、ポート番号によるコンテナーへのトラフィックのホワイトリスト作成はそれほど簡単ではありません。 例:
ポート9900を公開して、9000で内部的にリッスンしているDockerサービスを公開します。
$ sudo iptables -A DOCKER-USER -m limit --limit 20/min -j LOG --log-prefix "IPTables: "
$ docker run --rm -it -p '192.168.56.101:9900:9000' alpine nc -l 9000
ネットワーク上の別のマシンから:
$ telnet 192.168.56.101 9900
ログに記録されるもの:
IPTables: IN=enp0s8 OUT=docker0 MAC=08:00:27:b6:8d:d6:0a:00:27:00:00:04:08:00 SRC=192.168.56.1 DST=172.17.0.2 LEN=52 TOS=0x00 PREC=0x00 TTL=127 ID=14127 DF PROTO=TCP SPT=51208 DPT=9000 WINDOW=64240 RES=0x00 SYN URGP=0
IPTables: IN=docker0 OUT=enp0s8 PHYSIN=veth05ba007 MAC=02:42:0f:f9:76:4c:02:42:ac:11:00:02:08:00 SRC=172.17.0.2 DST=192.168.56.1 LEN=40 TOS=0x00 PREC=0x00 TTL=63 ID=23041 DF PROTO=TCP SPT=9000 DPT=51208 WINDOW=0 RES=0x00 ACK RST URGP=0
ご覧のとおり、現時点ではポート9900へのトラフィックをフィルタリングする機会はありません。確かにトラフィックを9000にフィルタリングすることはできますが、内部ポートが複数のコンテナ間またはホストで実行されているサービス間で意図せず重複する可能性があるため、これは問題です。 これは、1つのホストで複数のサービスを実行でき、ポートの競合を心配しないDockerの優れたセールスポイントの1つです。 そのため、多くのコンテナはポートをリッスンするように設計されており、ユーザーは--publish
オプションを使用して、どのポートがどのインターフェイスで公開されるかを変更できます。
$ docker run -d -p 7777:6379 --name data1 redis
$ docker run -d -p 8888:6379 --name data2 redis
ただし、DOCKER-USERを使用して(間違っている場合は修正してください)、data2へのトラフィックに影響を与えることなく、data1へのトラフィックに影響を与えることはできません。スクリプトや内省を行わずに、公開されたサービスをファイアウォールで保護するためのシンプルで信頼性の高い方法を見つけることをお勧めします。
明確にするために、これは機能しません:
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 192.168.56.0/24 --dport 7777 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 10.0.24.0/24 --dport 8888 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 7777 -j DROP
$ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 8888 -j DROP
これは機能しますが、その結果、両方のサービスが両方のホワイトリストに登録されたCIDRに公開されます。
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 192.168.56.0/24 --dport 6379 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 10.0.24.0/24 --dport 6379 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 6379 -j DROP
したがって、DOCKER-USERは、すべてのポートを特定のIPに公開する場合にのみ役立ちますが、内部ポート番号を参照するiptablesルールを記述してもかまわず、同じものを使用する複数のコンテナーがない場合を除いて、特定のポートを特定のIPに公開することはできません。内部ポート番号。 誰もがこれらの点を見逃していて、解決策としてDOCKER-USERを使用しているようです。これは、新しい、より良い解決策に値すると思います。
@SeerUK
https://gist.github.com/SeerUK/b583cc6f048270e0ddc0105e4b36e480に投稿されたソリューションは私には機能しませんでした。 手伝ってもらえますか?
dockerエラーは、アプリケーションのルーティングを行うためにiptables(システムファイアウォール)を使用することです。 それは永遠の問題と混乱を生み出すでしょう。 iptablesを変更すると非常に危険です。 Dockerに組み込まれたこの関数を追加するのは、それほど費用がかかりません。 さらに、dockerを同時に実行すると、同時に一貫性のないステータスになる可能性があります。
dockerの実行中にiptablesを変更すると、iptablesの動作がおかしくなります。 docker set iptablesを停止し、dockerを再起動すると、すべて予測どおりに機能します。 私の心配は...本番環境でiptablesを変更する必要がある場合はどうなりますか?
dockerの実行中にiptablesを変更すると、iptablesの動作がおかしくなります。
iptablesはiptablesであり、dockerが実行されているかどうかは関係ありません。
前にたくさんのテストを行うと良いです... iptablesがiptablesであると言うのは単なるトートロジーです。 それは私の提案です:)
彼のポイントは、あなたのコメントが示唆しているように、Dockerが実行されているときにiptablesが異なって動作しないということだったと思います。 これは明らかに、同じシステム上で他の誰もそれを必要としないかのようにiptablesを使用する方法に関するDockerの問題です。
DOCKER-USER
がこれを解決しない理由がわかりません。
iptablesを使用して、送信元ポート、ターゲットポート、送信元アドレス、非ローカルトラフィックなどを好きなようにフィルタリングします。
DOCKER-USER
要点は、Dockerルールが実行される前に、ユーザーが実行したいルールを実行することです。これにより、トラフィックがDockerに到達する前に、トラフィックに対して必要なことを実行できます。
@ cpuguy83主要な問題は、 127.0)に関連付けていないため、通知なしにパブリックネットワーク(システムの外部)にポートを開いていることです。 0.1、172.16.1.1); また、Dockerによって導入されたルールがUFWなどのiptables管理ツールに表示されないため、ユーザーは、ローカルホストだけでなく、ネットワーク上の任意のシステムからさまざまなDockerコンテナーにアクセスできることに気付かない可能性があります。
DOCKER-USERは、Dockerネットワークを特定のネットワークインターフェイスまたは特定のIP(fe 127.0.0.1)に関連付けないため、これを解決できません。
私の最初の要求によると:
1.Dockerは、Dockerネットワーク構成に基づいて特定のIPに自分自身を結び付け、ユーザーがルールを追加してコンテナーをシステム外に公開できるようにする必要があります(選択したツールを使用)。 デフォルトでは、コンテナはシステム外に公開されるべきではありません。
私見ですが、全体的な問題は、Dockerは、文字通り他のすべてのプログラムと同様に、ファイアウォール(iptablesなど)にまったく触れてはならないということです。 (例)apacheをインストールし、0.0.0.0:80でリッスンするように指示する場合、ファイアウォールでポート80を開くかどうかを決定します。ここで、必要なルールを指定できます。
Docker(および/または作成)構成ファイルのファイアウォールルールを再発明する代わりに、PUBLISH機能全体を非推奨にし、他のすべてのプログラムと同じように機能するように新しいLISTEN機能を作成する必要があります。 せいぜい、dockerは、それを使用するシステム上で、ポート/コンテナーごとにデフォルトで無効にされたfirewalldサービスを作成できます。
よく言った@gcscaglia ! さらに厄介なことに、 https: //docs.docker.com/engine/reference/run/#expose -incoming-portsには、これらすべてについてほとんどまたはまったく言及されていません。例による学習を補足するためのドキュメントが少しあります。 Dockerが既存のiptablesルールをオーバーライドするリスクを説明する真っ赤なボックスがどこかにあるはずです。
dockerでiptablesを管理したくない場合は、 --iptables-=false
Dockerが特定のインターフェースのポートのみを開くようにしたい場合は、デーモン構成でそれを設定することもできます。
@BenjamenMeyer
DOCKER-USER
内のすべてのトラフィックをブロックし、必要なものだけを通過させることができます。
DOCKER-USERですべてのトラフィックをブロックし、必要なものだけを通過させることができます。
@ cpuguy83ここで私が言うことが間違っているかどうか教えてください:
$ docker run -d -p 7777:6379 --name data1 redis $ docker run -d -p 8888:6379 --name data2 redis
ただし、DOCKER-USERを使用して(間違っている場合は修正してください)、data2へのトラフィックに影響を与えることなく、data1へのトラフィックに影響を与えることはできません。スクリプトや内省を行わずに、公開されたサービスをファイアウォールで保護するためのシンプルで信頼性の高い方法を見つけることをお勧めします。
明確にするために、これは機能しません:
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 192.168.56.0/24 --dport 7777 -j RETURN $ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 10.0.24.0/24 --dport 8888 -j RETURN $ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 7777 -j DROP $ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 8888 -j DROP
これは機能しますが、その結果、両方のサービスが両方のホワイトリストに登録されたCIDRに公開されます。
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 192.168.56.0/24 --dport 6379 -j RETURN $ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 10.0.24.0/24 --dport 6379 -j RETURN $ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 6379 -j DROP
したがって、 DOCKER-USER
を使用して、data2コンテナとは独立してdata1コンテナとの間のトラフィックを制御する方法はありません。 私にとって、これはDOCKER-USER
をあまり解決策にしません。
@colinmollenhour
DOCKER-USER
に一般的なドロップルールがある場合、これは、dockerが追加された場合と追加された場合のメインジャンプルールとどのように異なりますか?
@ cpuguy83私のポイントはオーバーライド自体に反対していません。 私が言っているのは、Dockerに既存のiptablesルールをオーバーライドさせることは、オプトアウト機能ではなく、オプトイン機能であるべきだということです。
また、オプトアウトとしても(そうすべきではありませんが)、デバッグはまったく予期せず、かなり直感に反するため、非常によく文書化する必要があります。 特に、 ufw
使用する人の数を考えると。 私は、非常に明確な警告なしにこのようなことをしている他のソフトウェアを知りません。私は個人的にそのようなソフトウェアに近づかないでしょう。
さらに、これは、ほとんどのDockerユーザー(少なくとも私の経験では)が、追加のネットワークインフラストラクチャが問題を覆い隠している環境で使用し始め、マシンが信じられているとおりに構成されているという仮定を強化するという事実によって悪化します。
@gcscagliaに例示されているように、DockerがLISTENのみのアプローチに移行することを願っています。
DOCKER-USERに一般的なドロップルールがある場合、これは、Dockerが追加された場合と追加された場合のメインジャンプルールとどのように異なりますか?
私はあなたの質問を理解していないと思います... 2017年4月22日のコメントは、DOCKER-USERが実際に解決する永続性に関するものであるため無視してください。 私が指摘している問題は、永続性に関するものではありません。
@taladar正確には、親指を
@jacoscaz
まず、すべてのメンテナは、既存の動作が理想的ではないことに同意していると思います。 残念ながら、この動作は永遠に存在しています。 何百万人もの人々が使用するもののデフォルトを変更することは、ここでできることではありません。 これがDOCKER-USER
を追加した理由の1つであり、少なくとも人々は必要なルールを挿入できます。
ただし、iptables(またはebpf、またはその他のネイティングソリューション)を使用する必要性を回避し、 -p
提供する機能を提供することはできません...逆に、ファイアウォールに穴を開けるのを防ぎたい場合は、 -p
使用を禁止します。
要約すると、次のことができます。
0.0.0.0
、またはすべてのインターフェースです)...ただし、これは誰かが-p
アドレスを手動で指定することを妨げることはありません-p 1.2.3.4:80:80
)DOCKER-USER
に挿入します--iptables=false
iptables管理を無効にする既存のユーザーを壊すことを含まない、他に提案できることはありますか?
@ cpuguy83わかりました。 私は、このような変更がバージョンごとに大幅に行われることを推奨していません。 いくつかのバージョンの過程で計画するのは良い変更だと思います。 また、Dockerがiptablesの使用を完全に停止するべきではないと思います。 転送は許可とは異なり、私が理解できる限り、Dockerはデフォルトでどこからでも誰にもアクセスを許可せずに、デフォルトで転送できるはずです。
今できることに関しては、これに関する追加のドキュメントが何よりもまず重要です。 docker.comのメンテナーとこれを提起するのに最も適切なチャネルはどれですか?
彼らの側に関心がない場合、この会話を生き続けることは、この行動がより広く知られるようになる可能性を最大化するためのおそらく最良の方法です。
この機能のドキュメントを追加するという呼びかけに同意します。 私が知る限り、それはhttps://docs.docker.com/network/iptables/でのみ言及されてい
回避策があることは理解していますが、Dockerの機能を長期的に変更するためにこれを検討する必要があると思います。 ポートでLISTENに設定し、その上にユーザー定義のルールを作成できるようにするというアイデアが好きです。
提案されたように、コンテナが誤って外部にさらされるのを防ぐために、DOCKER-USERにDROPルールを追加しました(これは驚くべきことに起こりました)。
ただし、公開したいサービスが1つあります。 しかし、 @ colinmollenhourが説明しているように、NATはフィルタリングの前に発生するため、
では、どうすればこの1つのサービスを公開できますか?
@SystemParadoxは、DOCKER-USERが問題の実際の修正ではない多くの理由の1つです。
@ cpuguy83
私は提案されたLISTENソリューションが好きで、リリースごとに重大な変更を提唱したことはありません。 しかし、適切な通知を出して一連のバージョンを変更することを提唱しました。多くの人がDockerを使用しており、バージョンごとに重大な変更を加えることはすべての人にとって有害であることを認識しています。
また、 -p
やEXPOSEなどに関するDockerのドキュメントを更新することは、少なくとも問題を認識させるためにすぐに実行する優先事項であることに同意します。 私の経験では、Dockerを使用しているほとんどの人はファイアウォールの専門家ではないため、Dockerが期待することを実行することを信頼していますが、これは現在の設計にはありません。
さらに、 https: //github.com/moby/moby/issues/22054#issuecomment-425580301の要約ソリューションも実際には機能しません。 どうして? Dockerを直接実行するのではなく、YAMLに基づいてDockerComposeを実行します。 IPアドレスは動的(Dockerによって制御)であり、同じDockerネットワーク内に相互作用する必要のある複数のサービスをデプロイすることがよくあります。 したがって、 -p
使用法とアドレスバインディングの使用法(要約のオプション1)はどちらも解決策ではありません。 DOCKER-他の人が指摘しているように(要約のオプション2)、ユーザーは実際には何も解決しません。IPテーブルを完全に無効にする(要約のオプション3)も、すべてが壊れているため、何の助けにもなりません(IPは動的であるため、ソリューションのスクリプトを作成するのは困難です。コンテナ間のネットワークが壊れています。DockerはIPTablesに依存してコンテナ間を移動します。など)。
繰り返しになりますが、このスレッドでは、2つのバージョン間の重大な変更を求める呼び出しはありません。 しかし、人々が適切に移住することを可能にする計画された段階的アプローチの要求が近づきました。
回避策として、 -m conntrack --ctorigdstport
を使用して元の宛先ポートにアクセスできます。
だから私の場合、私は次のものを持っています:
-A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow docker out
-A DOCKER-USER -s 172.17.0.0/16 -j ACCEPT
# Allow access to docker service mapped to host 8702 (the service is actually listening on port 8088 in the container)
-A DOCKER-USER -p tcp -m conntrack --ctorigdstport 8702 -j ACCEPT
# Prevent access to docker from outside
-A DOCKER-USER -j DROP
@SystemParadox
正しいiptablesソリューションをお届けします! 🍻
私は--ctorigdstport
ことを聞いたことがありませんでしたが、それは私が考えられるすべてのiptables拡張機能について読んだり試したりしたことがなく、この文脈で私の知る限り最初に言及したためだと思います。
私はテストしましたが、これは実際に機能します。
$ docker run -d -p 7777:6379 --name data1 redis
$ docker run -d -p 8888:6379 --name data2 redis
$ sudo iptables -N DOCKER-USER-redis1
$ sudo iptables -A DOCKER-USER-redis1 -s 192.168.56.0/24 -p tcp -m tcp -j RETURN
$ sudo iptables -A DOCKER-USER-redis1 -j REJECT --reject-with icmp-port-unreachable
$ sudo iptables -N DOCKER-USER-redis2
$ sudo iptables -A DOCKER-USER-redis2 -s 10.0.24.0/24 -p tcp -m tcp -j RETURN
$ sudo iptables -A DOCKER-USER-redis2 -j REJECT --reject-with icmp-port-unreachable
$ sudo iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 7777 -j DOCKER-USER-redis1
$ sudo iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 8888 -j DOCKER-USER-redis2
このような例は、おそらく99%のユーザーが探しているものをカバーしているため、ドキュメントに含まれていると思います。 -p
を使用してポートを公開する機能ですが、 -s
などの一般的なフィルターを使用してポートへのトラフィックを制御できます。
iptablesに関するDockerドキュメントを更新するリクエストを作成しました。
https://github.com/docker/docker.github.io/issues/8087
https://unrouted.io/2017/08/15/docker-firewall/にリストされているソリューション
FILTERSと呼ばれる追加のiptablesチェーンを作成する、似たようなもののようです
チェーンINPUTとDOCKER-USERがジャンプする場所に移動します。
@SystemParadox @colinmollenhour --ctorigdstport
をテストした後、動作することを確認できますが、少し注意が必要です。
私の場合、ポート80でリッスンしているApache上にドッキングされたPHPアプリケーションがあります。1.2.3.4のみを許可する私のルールは次のとおりです。
-A DOCKER-USER -s 1.2.3.4/32 -i eth0 -p tcp -m conntrack --ctorigdstport 80 -j ACCEPT
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 80 -j DROP
したがって、私のドロップルールはあなたのルールよりも少し具体的で、私のWebサーバーにヒットするパケットのみをドロップします—またはそう思ったのです。 実際、それは私のWebサーバーに向けられたパケットと、PHPアプリケーションからサードパーティサーバーへの要求からの応答で返されるパケットをドロップしていました。
これは、 --ctorigdstport
が、フィルタリングされているパケットの宛先ポートではなく、接続を開始したパケットと一致するためです。 したがって、Dockerから他のサーバーに送信されるリクエストへの応答はSPT=80
なり、 --ctorigdstport 80
とも一致します。
DROPルールをより厳密に制御したい場合は、 --ctdir
も追加する必要があります。
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 80 --ctdir ORIGINAL -j DROP
実際、接続を許可するすべてのルールには、その意味を正確に表現するために--ctdir
追加する必要があります。
-A DOCKER-USER -s 1.2.3.4/32 -i eth0 -p tcp -m conntrack --ctorigdstport 80 --ctdir ORIGINAL -j ACCEPT
@jestうわーそれを知ることは本当に重要です! 私はそれが他の方向のパケットと一致する可能性があることに気づいていませんでした。 接続全体の状態と一致しているので、考えてみると理にかなっていますが、ドキュメントを読むと見逃しがちです。
@SystemParadoxええ、ドキュメントを通じて自分自身に通知する機会がなかったので、応答を待ってハングしているDockerからのリクエストに驚かされました。 :)
--ctdir ORIGINAL
が必要な理由で、私は輪になって回り続けます。 @jestによる説明は完全に理にかなっている一方で、通常は応答パケットを処理する必要がないので、なぜここで異なる必要があるのでしょうか。
違いは、最初のルールとして-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
があるため、残りのルールには応答パケットが表示されないことだと思います。 この場合、 --ctdir ORIGINAL
は厳密には必須ではないと思いますが、とにかく含める方がおそらく安全です。
@jest 、これに同意しますか? おそらく、初期のESTABLISHED,RELATED -j ACCEPT
ルールがないので、これが違いを生むのですか?
@jestあなたの投稿は大いに役立ちました、ありがとう。
あなたのアプローチは、dockerによって管理されるものだけに必要ですか、それともすべてに必要ですか? たとえば、私のsshポート(22)はdockerとは何の関係もありません。 通常どおり-m tcp --dport 22
を使用する必要がありますか、それとも-m conntrack --ctorigdstport 22 --ctdir ORIGINAL
を使用する必要がありますか?
これらのパケットはフィルターテーブルで私に到達する前にマングリング/ナッティングを受けるため、あなたのアプローチはDocker管理のトラフィックにのみ必要であると思います。 しかし、私はiptablesに慣れていないので、私よりも多くのことを知っている誰かから確実に聞きたいです!
@ lonix1ルールは、ポートを公開した場合にのみ、おそらくコンテナーが実行されている場合にのみ、DockerによってDOCKERチェーンに追加されます。 どちらのコンテナでもポート22を公開していない場合は、ファイアウォールルールを変更せずに機能させる必要があります。
@SystemParadoxしばらく経ち、そのサーバーにアクセスして確認することができませんが、正しく覚えていれば、 ESTABLISHED,RELATED
ルールがありました(UFWによって管理され、 ufw-before-input
チェーン内にあります)。 しかし、私の場合には、彼らはポート80でインターネットホストへのドッキングウィンドウから作られた接続の最初のパケット(SYN)には一致しませんとでapproriate規則によって廃棄されますDOCKER-USER
まったくありませんでしたとき--ctdir
。
@ Ionix1 、ホスト上のサービスのパケットはINPUTのみを通過しますが、DockerサービスのパケットはFORWARDとDOCKER-USERのみを通過します。
たとえば、外部IPが10.0.0.1で、 -p 4000:80
と-p 4001:80
2つのコンテナがある場合、次のプロパティを持つパケットが表示されます。
INPUT:
dst 10.0.0.1 dport 80 ctorigdst 10.0.0.1 ctorigdstport 80
FORWARD/DOCKER-USER:
dst 172.17.0.5 dport 80 ctorigdst 10.0.0.1 ctorigdstport 4000
dst 172.17.0.6 dport 80 ctorigdst 10.0.0.1 ctorigdstport 4001
したがって、INPUTルールは完全に別個のチェーンにあるため、 --dport 80
を安全に使用できます。 ご覧のとおり、 --ctorigdstport 80
は引き続き一致しますが、何らかの理由で入力を操作しない限り、おそらくそうしません。
また、実際には--dport 80
と--dst 172.17.0.5
を使用して、特定のDockerコンテナのパケットをフィルタリングできることに気付くかもしれませんが、そのIPは予測できないため、 --ctorigdstport
を使用しています。
最終的には、どのチェーンに属しているか、宛先が何であるか、およびマングリングが行われているかどうかに応じて、特定のルールが一致する可能性のあるパケットを認識する必要があります。
@jestありがとう、それは私の考えを確認するようです。
だから、私は少し方向性が必要です... UFWからiptablesに切り替えるために...
-「ufwdisable」でUFWをオフにするだけですか?
-独自の.shファイルを作成しますか、それとも既存の.shファイルがありますか(私はDigitalOceanのUbuntuです)?
-Dockerに「--iptables = false」と伝える必要がありますか? (Dockerの場合は以上ですか?)
-DOCKER-USERはDockerによってすでに作成され、チェーンされていますか?
@fredjohnston必要に/etc/ufw
保存されます。 ここでの問題は、 /etc/ufw/applications.d
アプリプロファイルがリストされていないため、Dockerが表示されないことです(他のファイアウォールツールとその構成についても同じです)。
DockerでIPTablesを無効にすると、Dockerにネットワークがほとんどなくなり、IPアドレスとコンテナーだけが相互に通信できなくなります。 DOCKER_USER
は、ある程度の制御を可能にするハックですが、実際には問題を解決しません。これは、Dockerコンテナーをデフォルトでネットワーク上で公開せず、コンテナーのIPアドレスにロックすることです。
現時点では、最も使いやすいファイアウォールツール(ufwなど)を引き続き使用することをお勧めしますが、Dockerコンテナはネットワーク上で公開されることに注意してください。
私はとにかくここにいるので、実際に関連する問題に直面しています。これはLinux以外のプラットフォームでも問題になっています。 次のことを考慮してください。
ここで、両方のプロジェクトをローカルで実行するとします。たとえば、両方のプロジェクトが使用する共有ライブラリで作業して、テスト用にコードに簡単に取り込むことができるようにします。
現在のファイアウォールインタラクションデザイン(およびユーザーの知らないうちにコンテナをパブリックネットワークに公開することに関する上記の問題に部分的につながるもの)では、両方のプロジェクトのデータベースドッキングウィンドウを同時に実行することはできません。データベースの公開ポート。 両方のアプリケーションポートを公開する必要があり、両方がアプリケーションサーバーに同じポートを使用した場合も同じです。HTTPベースのAPIとアプリケーションは現在、特にクラウド指向のアプリケーションで非常に一般的であるため、一般的です。
確かに、1つのDBコンテナの下で両方を設定する方法をハックすることができます。 ただし、プロジェクトの設計ごとにそれらを分離しているわけではなく、構成などについてさらに注意する必要があります。
適切な解決策では、ここに2つの要素があります。
0.0.0.0
、 ::
)。繰り返しますが、これは徐々に行うことができます。
DOCKER_USER
は、ある程度の制御を可能にするハックですが、実際には問題を解決しません。これは、Dockerコンテナーをデフォルトでネットワーク上で公開せず、コンテナーのIPアドレスにロックすることです。現時点では、最も使いやすいファイアウォールツール(ufwなど)を引き続き使用することをお勧めしますが、Dockerコンテナはネットワーク上で公開されることに注意してください。
ボルトオンiptables静的構成を作成するためのドキュメント更新リクエストがhttps://github.com/docker/docker.github.io/pull/8357にありますが、そのステータスはわかりません。
編集:あなたがDOCKER-USERの意味を誤解していることに気づきました。 「コンテナをコンテナのIPアドレスにロックする」ためではなく、iptablesルールを使用してコンテナへのアクセスをフィルタリングするために使用されます。
@ aki-k per DOCKER_USER DOCKER_USER
がコンテナをIPアドレスに対してロックしないことを知っており、ロックしたとは主張していません。 DOCKER_USER
は、セキュリティの問題をユーザーに任せて管理するだけです。つまり、ユーザーはファイアウォールを操作して、実際に安全な環境を確保する方法を知っている必要があります。 ほとんどのユーザーはファイアウォールの管理方法を知らないため、ユーザーの問題にすることも同様に受け入れられません。ファイアウォールルールは難しいものであり、ファイアウォールルールの記述について少し知っている人でも、問題が発生することがよくあります。
この問題での私の要求(そして要点)は、Dockerはデフォルトで安全である必要があり、ユーザーの知識や明示的な介入なしにコンテナーを外部に公開しないことです。 そして私の最後のコメント(https://github.com/moby/moby/issues/22054#issuecomment-552951146)によると、そうすることには他の技術的な利点もあります。
この問題での私の要求(そして要点)は、Dockerはデフォルトで安全である必要があり、ユーザーの知識や明示的な介入なしにコンテナーを外部に公開しないことです。
これについて私が見つけた最初の問題レポートは、2014年3月18日のものです。
https://github.com/moby/moby/issues/4737
おそらく、変更したくない設計上の決定であり、DOCKER-USERiptablesチェーンで修正しようとします。 docker runの-pオプションを使用して、ポートをdockerホスト(-p 127.0.0.1:port:port)にのみ公開できますが、それでも問題は解決しません。
はっきりさせておきましょう。Dockerはデフォルトで安全です。 Dockerにポート転送を行うように指示する必要があります。
相互に通信する必要のあるサービスについては、ポート転送ではなく、ネットワーク( docker network
)を使用してアクセスを制限する必要があります。
明確にしましょう。Dockerはデフォルトで安全です。 Dockerにポート転送を行うように指示する必要があります。
確立されたiptables保護を超えて実行されているdockerに関する事実上の問題を却下しないでください。 これについて議論している無数の問題報告を見たことがあると思います。
明確にしましょう。Dockerはデフォルトで安全です。 Dockerにポート転送を行うように指示する必要があります。
相互に通信する必要のあるサービスについては、ポート転送ではなく、ネットワーク(
docker network
)を使用してアクセスを制限する必要があります。
明確にしましょう-Dockerは、Dockerネットワークの外部からアクセスするまで安全です。 ローカルホスト(127.0.0.1)からでもアクセスしたい場合、Dockerは0.0.0.0にバインドし、システムからコンテナーを公開するため、デフォルトでは安全ではありiptables
直接使用以外のツールで。 DOCKER_USERは、基盤となるファイアウォールシステム(Linuxのiptables、Macが使用するもの、およびWindowsのWindowsファイアウォール)についてユーザーが十分に理解している必要があるため、適切なソリューションではありません。 それでもデフォルトで安全である必要があります。 以前にhttps://github.com/moby/moby/issues/22054#issuecomment-552951146で概説し、この問題全体で何度も呼びかけたように、これを行う非常に簡単な方法があります(おそらく、それほど明確ではありませんが)コメント)。
ポートを公開するためのドキュメントにもこのセキュリティの問題は記載されておらず、ポートを公開するときにDockerがシステムファイアウォールとどのように相互作用するかについては言及されていないため、Dockerが使用されるまで安全であるように設計されていたシステムのセキュリティが低下することにも注意してください。
明確にしましょう。Dockerはデフォルトで安全です。 Dockerにポート転送を行うように指示する必要があります。
相互に通信する必要のあるサービスについては、ポート転送ではなく、ネットワーク(docker network
)を使用してアクセスを制限する必要があります。明確にしましょう-Dockerは、Dockerネットワークの外部からアクセスするまで安全です。 ローカルホスト(127.0.0.1)からでもアクセスしたい場合、Dockerは0.0.0.0に対してバインドするため、デフォルトでは安全ではありません[...]
正確には、Dockerは0.0.0.0にバインドしません。 これは、ユーザーの(合理的な)期待です。CLIで--publish
を指定すると、ユーザースペースで動作し、指定されたポートでリッスンし、着信接続を受け入れて前後にプッシュする、ある種のプロキシデーモンを起動します。 Dockerと外界との間のすべてのパケット。
ただし、代わりに、Dockerは魔法のDNAT /マスカレードルールをファイアウォールに挿入してパケットのアドレスを書き換えるため、プリインストールされているルールシステムをランダムに破壊します。
私の意見では、ここで抽象化のレベルを台無しにすることは最大の悩みの種であり、ユーザーを混乱させます。 ここに表示されている--publish
機構を設計するときに、Dockerチームがどのシナリオを検討したかはわかりませんが、決定を正当化するものはありません(パフォーマンス上の理由以外に)。
はっきりさせておきましょう。Dockerはデフォルトで安全です。 Dockerにポート転送を行うように指示する必要があります。
...これはDockerで最も使用されている機能の1つです。 事実上、Dockerの最も使用されている機能の1つ内で既存のファイアウォールルールを文書化されていないオーバーライドにより、Dockerがデフォルトで_安全になる_と述べたばかりです。
まあ、私が推測するあなたのために働くものは何でも。 私にはうまくいかないので、別のコンテナプラットフォームを検討し始めます。 セキュリティの問題は修正できますが、合理的なセキュリティの期待をあからさまに無視することは別の獣です。
今日の状況を評価してみましょう。
デフォルトでは、ポートは公開されていません。 Dockerにポートを公開するように指示する必要があります。
以前は、Dockerはブリッジネットワークへのルーティング方法を知っているものはすべてコンテナIPにアクセスできるようにiptablesをセットアップしていましたが(転送ポリシーを「accept」に設定することにより)、これはもはや真実ではありません。
-p
を使用してサービスを相互に公開していると言う人がいますが、これは必須ではありません。
デフォルトのネットワークでは、 --link
を使用してサービスを相互に接続でき、コンテナはDNS経由で利用できます。
デフォルト以外のネットワーク(ユーザー定義ネットワーク)では、コンテナーはDNSによって相互にアクセスできます。これには、 --link
を介したエイリアスの設定や、指定されたエイリアスを持つネットワークへの設定も含まれます。
多くの場合、実際にはクライアントからサービスに接続したいだけのようです。その場合、ポートを公開するのではなく、接続したいサービスにアクセスできる別のコンテナーを使用することをお勧めします。
-p
は、外部のものがこのサービスにアクセスできるようにするために、特に入力用に設計されています。
-p
のデフォルトは、実際、どこからでもトラフィックを許可することです。 -p
ごとに、またはデーモン全体の設定として許可するアドレスを手動で指定することにより、これを変更できます。
-p
はiptablesを使用するため、 DOCKER-USER
チェーンが作成され、ユーザーはコンテナーに到達する前に独自のフィルタールールを追加できます。
-p
は入力用に設計されているため、トラフィックを公開するのと同じように公開するのが妥当だと思います。 Dockerルールがフィルターテーブルの一番上に挿入されているのは残念なことですが、これを変更すると、この動作を希望する大規模なユーザーグループにとっては重大な変更になります。
-p
は、他にもいくつかの選択肢があります。
-p
使用せず、コンテナIPに直接接続します。 IPを検索する必要があるため、これには少し余分な作業が必要ですが、このデータはAPIから入手できます。 また、ファイアウォールの転送ポリシーでこれが許可されていることを確認する必要があります(別のホストから接続していると仮定すると、同じホストで問題ありません)--net=host
使用します。これにより、ホストネットワーク名前空間でサービスが実行され、ホストにすでに存在するネットワークインフラストラクチャへのサービスアクセスが可能になります。「デフォルトでこれを安全にする」と言いますが、ポートを公開することは、定義上、潜在的に安全でないアクションです。 ローカルホストのみに公開することは安全であるという考えもあるようですが、ホスト上で実行されているものがローカルホストにアクセスできるわけではありません(デスクトップの場合はブラウザーのJavaScriptを含む)。
-p
使用してどのようなユースケースを解決しようとしていますか?
あなたが見たい実際の変化について何か考えがありますか?
これをワークフローに合わせて改善するために何かを変更するのは問題ありませんが、ここにはさまざまなユースケースがあり、1つのサイズですべてに対応できるわけではありません( -p
に関する苦情を参照)。
@ cpuguy83これはすべて問題なくダンディですが、このリクエストでは何も変更されません。
人々はdockerを使用していて、ローカルシステムからdockerで実行されているアプリケーションに接続したいと考えています-これは、特に何かを診断しようとしたり、dockerの下にないが、dockerでホストされているサービスに接続する必要があるサービスを作成したりする場合の開発者にとって非常に一般的なユースケースです(開発環境に入力するため)。 Dockerでの開発は、次のように言っても、必ずしも良い、楽しい、または便利なエクスペリエンスとは限りません。
ポートを公開するのではなく、接続するサービスにアクセスできる別のコンテナーを使用することをお勧めします。
単にノーゴーです。 すべてのツールがDockerに対応しているわけではなく、そうである必要もありません。 Dockerで実行されているサービスを利用するために、ユーザーが完全にDockerの下にいる必要はありません。 それでも、Dockerを使用してサーバーを操作する場合、管理者はファイアウォール構成とポートの公開機能を介してサーバーを簡単に制御できませんが、調整されています(コマンドライン、Dockerfile、Docker Compose Config)は完全に壊れています。
さらに、人々はDocker Composeを使用して環境の大部分を管理し、 docker-compose.yml
またはDockerfile
を介して、ローカルにアクセスできるようにポートを公開する必要があることを指定します。 したがって、 use the -p
パラメーターは、dockerコマンドと直接インターフェースすることはないため、正しくありません。
ポートを公開しても、セキュリティが破られなければならないという意味ではありません。 セキュリティを損なうことなくローカルシステムにポートを公開する方法(https://github.com/moby/moby/issues/22054#issuecomment-552951146)の概要を説明しました。これにより、外部公開の管理がオフになります。システム)既存のツールで簡単に制御できる方法でユーザーの手に。
解決:
つまり、 127.0.0.1:<port>
を介してDockerコンテナー内のサービスにアクセスする代わりに、ローカルホストからでも<docker container ip>:<service port>
必要です。 システムからサービスを公開したい場合は、ツール(ufwなど)を介してファイアウォールルールを追加し、特定のポートから<docker container ip>:<service port>
にポートフォワードすることができます。
または、プロキシ設計でKubernetesのアプローチに従い、 https: //github.com/moby/moby/issues/22054#issuecomment-554665865で提案されている@jestのように効果的に実行します。 繰り返しになりますが、これは、ユーザーが意図的に外部ネットワークに公開するまでは、ローカルシステムである必要があります。
ここでの最大の問題は、Dockerがサービスを提供するためにファイアウォールの整合性を危険にさらしていることです。これは、ユーザーにまったく通知せず、ユーザーのツールに統合せずに、ユーザーがファイアウォールについて知らず、制御できないようにします。
市場にはたくさんのファイアウォールインターフェースがあることに気づきました。iptablesでも、firewalld、ufw、その他多数あります。 Dockerがそれらと統合されることは本当に期待していませんが(それは素晴らしいことですが)、Dockerがそれらをバイパスしたり、ユーザーが設定したセキュリティを壊したりしない方法で機能することを期待しています。
基本的なテストケースとして:
ufw allow OpenSSH
実行しますufw enable
実行しますこの時点で、かなり安全なサーバーができました。 許可されるトラフィックは、(a)発信トラフィックまたは(b)SSHサーバートラフィックのいずれかのみです。
次に、ポートが公開されたDockerコンテナを起動します。
許容できるソリューションは、次の条件を満たすでしょう。
firewalld
を使用するCentOS / Fedora / RHELベースのシステムでも同じことを試してください。
@ cpuguy83 IMOの人々は、 -p
がアプリケーションレベルで機能することを期待しています。 つまり、 -p 80:80
場合、コンテナのポート80にバインドされたアプリケーションがホスト上で実行されているかのように動作することを期待しています。
VirtualBoxまたはSSHモデルのポートフォワーディングはこのような方法で行われるため、Dockerの場合も同じであると見なされます。
より広い期待値を並行して使用するには、ユーザーの観点からは、ホストにバインドされたボリュームとして機能する必要があります。 ホストディレクトリをポイントするだけで、「魔法のように」コンテナ内に表示されます。 パーミッション、クォータなど、反対側からファイルシステムに加えられた変更はすべて同じように機能します。
-p
問題をファイアウォールの場合に絞り込みます。通常の世界では、ユーザーは0.0.0.0:80にバインドされたアプリケーションが外部から見えることを期待しています。 ユーザーがアクセスを制限したい場合は、ファイアウォールを使用してINPUT
チェーンにルールを設定するように多数のガイドで指示されています。
-P INPUT DROP
-A INPUT -s 1.2.3.4/32 -p tcp --dst-port 80 -j ACCEPT
またはUFWのようなツールを使用します:
ufw enable
ufw allow http
しかし、dockerを使用する場合、ユーザーはそのようなルールを簡単に作成できる必要があります。
-A DOCKER-USER -s 1.2.3.4/32 -i eth0 -p tcp -m conntrack --ctorigdstport 80 --ctdir ORIGINAL -j ACCEPT
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 80 --ctdir ORIGINAL -j DROP
Dockerを使用してこのような一般的なシナリオを解決する方法について、平均的なユーザー向けの包括的なガイドを1つ見せてください。
そして、たとえば、「アプリケーションコンテナ化」の概念全体を販売している平均的な開発者にとって、ポートを公開した場合の結果は単純に予測できません。
最近は知識不足のためポートを公開せず、代わりにTraefikのようなサービスを利用しています。 たぶん--expose
もCLIドキュメントで汎用として提案されるべきではありません。IMOは平均的なユーザーには何の役にも立たないからです。
または、これらのツールに関する深い知識がない人に、DellやLenovoなどのLinuxラップトップを提供し、誰かがローカルデータベースにアクセスしているときに、ファイアウォールを適切に設定するための誠実な努力がまったく違いをもたらさないことを確認します。スターバックスでコーヒーを飲みます。
この正確な問題により、週末に発見したシステムの脆弱性が発生しました。 @jacoscazによると、公開されたポートがあるため、別の開発者のローカルデータベースを利用することができました。 他の人が同じことをしないように、すべての人がこれをイントロドキュメントに含めることができれば素晴らしいと思います。 ネットワーク上の他の全員がアクセスすることなくコンテナに接続するには、コンテナ化されていないサービスが必要なので、Dockerネットワークは問題外です。 誰かがより良いアイデアを持っていない限り、今のところ最良のオプションはローカルコンテナIPに接続することのように思えます。
@dentonmwoodそれはあなたがすべきこととまったく同じように聞こえます。 上で述べたように、macvlanまたはipvlanを使用して実行するようにサービスを設定することもできます。これにより、通常のネットワーク上で直接IPが提供されます。
@BenjamenMeyer @jest @jacoscaz
追加のフィードバックをありがとう。
この点でユーザーにポーズをとるように求めている知識は素晴らしいものではないことに同意します。 現在、ユーザー(システム管理者または開発者)に責任を負わせて、 -p
機能を理解し、適切な予防措置を講じて、サービスが公開されていると思われるユーザーのみに公開されるようにしています。 iptablesを知る理由がないことが多い開発者が、自分の環境に合わせて( DOCKER-USER
介して)ステップインして修正することを期待することによっても、さらに一歩進んでいます。
互換性を損なう恐れがあるため、基本的にこの状況にあります。
まだ十分に検討する時間がなかったアイデアがいくつかありますが、基本的には、クライアントのAPIバージョンに基づいて-p
の動作を変更し、入力を個別に処理します。 それでも私を心配する重大な変更ですが、少なくとも古い動作は古いAPIバージョンで保持されます。
ローカルアクセスのユースケースに対してローカルプロキシ(ala kubectl proxy
)を実行できるとは思っていましたが、これも開発者に、実際に必要な以上のことを知って理解する責任を負わせます。 。
考え?
プロキシの導入は良い方向への一歩だと思います。
「ポートフォワーディング」は、スウォームモードと同様に、コンテナとオーケストレーターの間で共有される責任であることを認めます。 ただし、最小限のホスト統合が常に必要であり、(専門家ではない)ユーザーに-p
ようなオプションを与える場合、提案されたソリューションはそのようなユーザーにとって理解しやすいものでなければなりません。
環境への-p
影響は指定されていないため(少なくともCLIレベルでは)、動作方法のユーザーフレンドリーな構成を導入する可能性があります。
例えば、現時点で存在するiptables
で/etc/docker/daemon.json
操作するか否かを決定するDOCKER
またはず。 iptables==true
&& expose_with_network_proxy==true
ような組み合わせでプロキシのような動作がオンになるように、構成を別のエントリで拡張できます。
しばらく前にaufs
もoverlay2
を優先していたので、これは一般的に新規インストールに対して安全であるはずです(私が正しく覚えていれば)。 また、アップグレードは既存の構成ファイルに影響を与えないため、そのように簡単に展開できますが、新規インストールは自由に実行できます。
互換性を損なう恐れがあるため、基本的にこの状況にあります。
この問題の重大さは、少なくとも私の目には、現在の-p
技術的基盤よりも、ドキュメントの欠如に関係しているという事実を強調したいと思います。 はい、現在のメカニズムが「安全」であるとは言えないと思いますが、セキュリティ上の欠陥は修正でき、現在のシナリオにつながった理由を批判する立場にはありません。 結局のところ、後知恵は常に20/20であり、下位互換性への取り組みと、そのような取り組みがもたらす技術的課題に直面する意欲を高く評価しています。
私が得られないのは、Dockerのドキュメント全体に-p
使用による副作用を明示的に警告する明るい大きな赤いボックスがまだない理由です。 もし私がそのような警告に出くわしたならば、私はそもそもここにいることすらできないと思います。
考え?
プロキシオプションは合理的に聞こえます。 さらに、 docker run
起動中に強制されるのではなく、必要なときにいつでもポートを公開および公開解除できるというアイデアが好きです。
@BenjamenMeyer @jest @jacoscaz
追加のフィードバックをありがとう。
最後にこれをもっと詳しく見てくれてありがとう。
この点でユーザーにポーズをとるように求めている知識は素晴らしいものではないことに同意します。 現在、ユーザー(システム管理者または開発者)に責任を負わせて、
-p
機能を理解し、適切な予防措置を講じて、サービスが公開されていると思われるユーザーのみに公開されるようにしています。 iptablesを知る理由がないことが多い開発者が、自分の環境に合わせて(DOCKER-USER
介して)ステップインして修正することを期待することによっても、さらに一歩進んでいます。
互換性を損なう恐れがあるため、基本的にこの状況にあります。まだ十分に検討する時間がなかったアイデアがいくつかありますが、基本的には、クライアントのAPIバージョンに基づいて
-p
の動作を変更し、入力を個別に処理します。 それでも私を心配する重大な変更ですが、少なくとも古い動作は古いAPIバージョンで保持されます。考え?
状況の重大さは確かにそれを修正するための破壊的な変化を可能にすると思います。 人々に知らせずにそれをしないでください。 変更が頻繁に議論される場所のタイムライン(6か月?12か月?)を設定し、コミュニティを準備します。 次に、「メジャー」バージョンで変更を加えます。 バージョンスキーマに基づくと、最初のセットは年(19)のように見えます。 2019年の終わりになっていることを考えると、2019年の残りを使用し、次に2020年を使用してソリューションを考案し、宣伝します。 2020年のいつかオプション機能として導入し、2021年に1位/デフォルトの使用法に昇格させます。
DockerfileバージョンとDockerCompose Schema Versionは、デフォルトの動作を設定するという点では優れたツールかもしれませんが、古いバージョンがそれを利用できるようにブロックすることはなく、更新の必要性について強い警告を出します。そのような場合にも。
どのように展開されても、なぜ、何が起こっているのかを理解し、それによって盲目的にされていると感じないのであれば、コミュニティ全体がそのような変化をはるかに支持していることがわかると思います。
ローカルアクセスのユースケースに対してローカルプロキシ(ala
kubectl proxy
)を実行できるとは思っていましたが、これも開発者に、実際に必要な以上のことを知って理解する責任を負わせます。 。
私はプロキシのアイデアが好きで、それを有効にする方法についての@jestの提案は、移行を行うための優れた方法かもしれません。
正直なところ、それをシステムから公開しようとしているほとんどの人は、UFWまたはfirewalldをそのように構成する方法であっても、ある程度ファイアウォールに精通している、または精通しているはずです。 したがって、ソリューションがローカルホストのみで利用できるようにする場合は、ファイアウォールツールを使用してファイアウォールを介してポートフォワードを実行する方法を学ぶことは許容できると思います。
このような機能は、すべてが見えるようになるため、ユーザーが使用することを決定したファイアウォールツールを介して実行することが重要だと思います。 このような機能は、ツールをバイパスするべきではありません。 また、ファイアウォールツールが非常に多いため、Dockerがそれらすべてと統合するのは無理だと思います。 ですから、ドキュメンテーションルートを取り、人気のあるものを使ってそれを行う方法を強調し、コミュニティにさらに追加して更新させることをお勧めします。
私はプロキシのアイデアが好きで、それを有効にする方法についての@jestの提案は、移行を行うための優れた方法かもしれません。
正直なところ、それをシステムから公開しようとしているほとんどの人は、UFWまたはfirewalldをそのように構成する方法であっても、ある程度ファイアウォールに精通している、または精通しているはずです。 したがって、ソリューションがローカルホストのみで利用できるようにする場合は、ファイアウォールツールを使用してファイアウォールを介してポートフォワードを実行する方法を学ぶことは許容できると思います。
私はこれをエコーします。 プロキシソリューションを使用すると、ユーザーが必要なインターフェイスとポートの任意の組み合わせにプロキシをバインドできるようにするものを考え出すことが可能だと思います。 ただし、下位互換性(私がサポートします!)またはその他の理由で妥協を余儀なくされた場合は、システム外の露出をユーザーに委任することを犠牲にしても、合理的なセキュリティの期待に一致するように優先する必要があります。
私のコメントに加えて、プロキシは実際には、利用可能なファイアウォールツールに応じてさまざまな方法で動作する可能性があります。 サポートされているファイアウォール構成ツールが検出された場合、プロキシはそれを使用して適切な転送ルールを設定できます。 このようなツールの存在は、実稼働環境の要件として追加できます。 このようなツールが利用できない場合、プロキシはデフォルトでアプリケーションレベルのプロキシサーバーを生成します。
Dockerは、Linuxの場合と同じようにmacOSファイアウォールをバイパスします。
開発マシン(Mac用のDockerデスクトップ)で、Dockerデーモン構成に"ip": "127.0.0.1"
を追加しました。 このようにして、開発データベースなどはデフォルトでローカルホストからのみアクセスできます。 アプリを他の人に見えるようにする必要があるまれなケースでは、 -p 0.0.0.0:8080:8080
を使用して明示的に公開できます。
編集:Dockerデーモンの構成に関係なく、DockerComposeはデフォルトで0.0.0.0にバインドされているようです。 したがって、このトリックは、コマンドラインからDockerを実行している場合にのみ機能します。 とにかく、Composeファイルはシステム構成が異なる可能性のあるチームメイトと共有されることが多いため、Composeファイルに明示的に127.0.0.1を追加することをお勧めします。
@luontolaなんてエレガントな解決策でしょう。
編集:私も考えていたのは、たとえばDockercomposeで定義できるアドレスの許可/ブロックリストを作成して、DOCKER-USERiptablesチェーンに自動的に追加する方法でした。
この問題の重要性を強調する小さなoopsieデイジー: https :
あなたのような@danhallinのコメントは、状況によっては本当にその日を救うことができます。 共有していただきありがとうございます。
うーん面白い読書!
私はMacOS Xで実行していて、LittleSnitchと呼ばれるローカルファイアウォールも持っています。 185.156.177.252がcom.docker.backendプロセスに接続しても問題ないかどうかを尋ねるダイアログが表示されました。 私は否定をなめました。
ルーターのポートフォワードをどのように開くことができるのか疑問に思っていましたが、これはもちろんUPnPを介して行われることに気づきました。 すべてのルーターがこれをサポートしています。
私が今疑問に思っているのはその理由です。 185.156.177.252の何かが外部から接続しようとしているのはなぜですか? ローカルのDockerプロセスに何かが必要な場合は、外部のポートを開くのではなく、内部からホームと呼ぶ必要があります。
@ cpuguy83これはすべて問題なくダンディですが、このリクエストでは何も変更されません。
人々はdockerを使用していて、ローカルシステムからdockerで実行されているアプリケーションに接続したいと考えています-これは、特に何かを診断しようとしたり、dockerの下にないが、dockerでホストされているサービスに接続する必要があるサービスを作成したりする場合の開発者にとって非常に一般的なユースケースです(開発環境に入力するため)。 Dockerでの開発は、次のように言っても、必ずしも良い、楽しい、または便利なエクスペリエンスとは限りません。
ポートを公開するのではなく、接続するサービスにアクセスできる別のコンテナーを使用することをお勧めします。
単にノーゴーです。 すべてのツールがDockerに対応しているわけではなく、そうである必要もありません。 Dockerで実行されているサービスを利用するために、ユーザーが完全にDockerの下にいる必要はありません。 それでも、Dockerを使用してサーバーを操作する場合、管理者はファイアウォール構成とポートの公開機能を介してサーバーを簡単に制御できませんが、調整されています(コマンドライン、Dockerfile、Docker Compose Config)は完全に壊れています。
さらに、人々はDocker Composeを使用して環境の大部分を管理し、
docker-compose.yml
またはDockerfile
を介して、ローカルにアクセスできるようにポートを公開する必要があることを指定します。 したがって、use the -p
パラメーターは、dockerコマンドと直接インターフェースすることはないため、正しくありません。ポートを公開しても、セキュリティが破られなければならないという意味ではありません。 セキュリティを損なうことなくローカルシステムにポートを公開する方法( #22054(コメント) )の概要を説明しました。これにより、外部公開(システム外)の管理がユーザーの手に渡り、簡単にできるようになります。既存のツールで制御します。
解決:
* Use Docker Network * Expose the Ports on the Docker Network alone and local host * Stop binding the port on 0.0.0.0 - or effectively doing so * Require users to use their own firewall tooling to expose the port off system (ufw, firewalld, etc) * Provide integrations for common firewalls to make this easy
つまり、
127.0.0.1:<port>
を介してDockerコンテナー内のサービスにアクセスする代わりに、ローカルホストからでも<docker container ip>:<service port>
必要です。 システムからサービスを公開したい場合は、ツール(ufwなど)を介してファイアウォールルールを追加し、特定のポートから<docker container ip>:<service port>
にポートフォワードすることができます。または、プロキシ設計でKubernetesのアプローチに従い、 #22054(コメント)で提案されている@jestのように効果的に実行します。 繰り返しになりますが、これは、ユーザーが意図的に外部ネットワークに公開するまでは、ローカルシステムである必要があります。
ここでの最大の問題は、Dockerがサービスを提供するためにファイアウォールの整合性を危険にさらしていることです。これは、ユーザーにまったく通知せず、ユーザーのツールに統合せずに、ユーザーがファイアウォールについて知らず、制御できないようにします。
市場にはたくさんのファイアウォールインターフェースがあることに気づきました。iptablesでも、firewalld、ufw、その他多数あります。 Dockerがそれらと統合されることは本当に期待していませんが(それは素晴らしいことですが)、Dockerがそれらをバイパスしたり、ユーザーが設定したセキュリティを壊したりしない方法で機能することを期待しています。
基本的なテストケースとして:
* Setup a Debian-based server (Debian, Ubuntu) * Install ufw, OpenSSH Server * run `ufw allow OpenSSH` * run `ufw enable`
この時点で、かなり安全なサーバーができました。 許可されるトラフィックは、(a)発信トラフィックまたは(b)SSHサーバートラフィックのいずれかのみです。
次に、ポートが公開されたDockerコンテナを起動します。
許容できるソリューションは、次の条件を満たすでしょう。
* The port should not be accessible from another computer; the firewall should continue to block it from outside systems. * The port should be accessible from the local computer (localhost). * Multiple docker containers should be able to expose the same port and have everything work; all containers with an exposed port should be accessible from the local system only. * The user should not have to know about their firewall configuration details to make this happen.
firewalld
を使用するCentOS / Fedora / RHELベースのシステムでも同じことを試してください。
ポートが公開されるたびにファイアウォール入力ルールをバイパスしないようにDockerを構成する方法があるかどうかを調べようとしていたときに、この問題に遭遇しました。 上記のコメントは、全体を説明する上で優れた効果を発揮し、より好ましいIMOアプローチも提供します。
昨日、私は偶然この問題に出くわしました。 VPS用にiptablesファイアウォールルールを細心の注意を払ってカスタマイズするのに何週間も費やしました。 私は用心深く制限しようとしました。 フィルタの入力と出力は、デフォルトでドロップするように設定されています。 特定のトラフィックを明示的に許可し、それ以外はすべてブロックします。 トラフィックはログに記録され、私はテストと監視を行ってきました。
DockerがフォワードチェーンとNATテーブルに独自の変更を加えたことを知っていました。そのため、プロセス全体でこれらの変更を尊重するように_細心の注意を払っています。 また、すべてのコンテナはユーザー定義のネットワークに接続されています。 デフォルトのホストネットワークは使用されません。 公式文書には、そうしないようにと
私の最初の驚きは、コンテナ化されたNginxプロキシがインターネット全体にアクセスできることでした。 ファイアウォールルールに、世界中からのインバウンドWebトラフィックを許可するオプションがあり
私のWebアプリケーションのいくつかは、MySQLのようなデータベースに依存しています。 最初は、DockerComposeで-pオプションを使用しませんでした。 私のWebアプリケーションとデータベースサーバーは同じユーザー定義のDockerネットワークを共有していたので、それは必要ないことを私は知っていました。 しかし、元DBAとして、私は常にバックアップについて考えています。 そこで、 -pオプションをアクティブにして、ホストのcronジョブとバックアップツールがタイムリーにバックアップできるようにしました。 外部SQLアクセスを許可するために、さらに別のファイアウォール_option_を作成しました。 しかし、繰り返しになりますが、まだそれを有効にしていませんでした。
Nginxに驚いた後、MySQLも公開されていないことを再確認することにしました。 (ラップトップから)リモートVPSのMySQLデータベースに接続しようとしました。 そして、すぐに接続に成功したとき、再びショックを受けました。
私が言っていることは、以前の投稿で詳細に議論されていません。 有益な調査と提案をしてくれた@ BenjamenMeyer @ jest @ jacoscazに感謝します。 しかし、現代のユースケースと経験を求めている人にとっては? ここにあります。 このスレッドが始まってから4年以上経った今でも、私のような人々はこの行動に直面しています。 そして、それでもショックを受けて去っていきます。
はい、回避策はたくさんあります。 私はすぐにいくつかを追求します。 しかし、それらを実装するには、そもそもこの問題が存在することを実際に知っている必要があります。 それが私を最も失望させたものです。 Docker開発者が、良いか悪いかにかかわらず、特定の設計上の決定を下したわけではありません。
しかし、この「ファイアウォールバイパス動作」は明確に指摘されておらず、大声で警告されており、より広く文書化されています。 ネットワークセキュリティに関して言えば、驚きは決して良いことではありません。
他の人が役立つと思った場合に備えて、この問題の回避策を共有したいと思いました。 iptablesとipsetを使用します。 Ubuntu、CentOS 7、RHEL 7でテスト済み。「信頼できる」IPは常に同じIP範囲にあるとは限らないため、ipsetが使用されます(iptablesの制限を修正)。
通常のDocker、およびDocker Swarm(別名SwarmKit)で動作します。
これにより、デフォルトで安全が確保され、指定したIPのみが、指定したOSポートとDockerポート(iptablesとipsetを使用)に接続できるようになります。 OSポートまたはDockerポートを「パブリック」(すべてのIPに公開)にするオプションもあります
Ansibleは必須ではありませんが、簡単になります。Ansibleの役割: https :
CentOS / RHELの手動手順:
https://github.com/ryandaniels/ansible-role-iptables-docker#manual -commands-centosrhel
そしてUbuntu18.04 / 20.04:
https://github.com/ryandaniels/ansible-role-iptables-docker#manual -commands-ubuntu-2004
iptablesに加えてipsetをインストール/構成する必要があります(問題がある場合は上記のリンクを参照してください)。
iptables configの例(sshポート22をすべての人に公開):
*filter
:DOCKER-USER - [0:0]
:FILTERS - [0:0]
#Can't flush INPUT. wipes out docker swarm encrypted overlay rules
#-F INPUT
#Use ansible or run manually once instead to add -I INPUT -j FILTERS
#-I INPUT -j FILTERS
-A DOCKER-USER -m state --state RELATED,ESTABLISHED -j RETURN
-A DOCKER-USER -i docker_gwbridge -j RETURN
-A DOCKER-USER -s 172.18.0.0/16 -j RETURN
-A DOCKER-USER -i docker0 -j RETURN
-A DOCKER-USER -s 172.17.0.0/16 -j RETURN
#Below Docker ports open to everyone if uncommented
#-A DOCKER-USER -p tcp -m tcp -m multiport --dports 8000,8001 -j RETURN
#-A DOCKER-USER -p udp -m udp -m multiport --dports 9000,9001 -j RETURN
-A DOCKER-USER -m set ! --match-set ip_allow src -j DROP
-A DOCKER-USER -j RETURN
-F FILTERS
#Because Docker Swarm encrypted overlay network just appends rules to INPUT
-A FILTERS -p udp -m policy --dir in --pol ipsec -m udp --dport 4789 -m set --match-set ip_allow src -j RETURN
-A FILTERS -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FILTERS -p icmp -j ACCEPT
-A FILTERS -i lo -j ACCEPT
#Below OS ports open to everyone if uncommented
-A FILTERS -p tcp -m state --state NEW -m tcp -m multiport --dports 22 -j ACCEPT
#-A FILTERS -p udp -m udp -m multiport --dports 53,123 -j ACCEPT
-A FILTERS -m set ! --match-set ip_allow src -j DROP
-A FILTERS -j RETURN
COMMIT
最も参考になるコメント
ベンが明らかにしている問題は現実的で驚くべきものです(悪い組み合わせ)。 私のような多くの管理者は、実証済みのufwファイアウォールを使用しています。 Dockerはufwを実行してエンドランし、iptablesルールを変更すると、1)ufwがパケットフィルタリングルールの現在のステータスを誤って報告し、2)一見プライベートなサービスをパブリックネットワークに公開します。 dockerがsysadminコミュニティの良好な状態を維持するには、別のアプローチを考案する必要があります。 現在、ベンや私のように、うっかりしてより広いインターネットへのポートを開いた管理者がたくさんいます。 ベンや私とは異なり、彼らはまだそれを理解していません。