Dockerを試しました。それは素晴らしいですが、ufwでうまく動作しないようです。デフォルトでは、dockerはiptablesを少し操作します。結果はバグではなく、私が期待したものではありません。詳細については、 FW + Dockerの危険性 をご覧ください。
私の目標は、次のようなシステムをセットアップすることです
Host (running ufw) -> docker container 1 - nginx (as a reverse proxy)
-> docker container 2 - node web 1
-> docker container 3 - node web 2
-> .......
Ufwを介して着信トラフィックを管理(アクセスの制限など)したいので、ドッカーがiptablesに触れないようにします。これが私のテストです
環境:
--iptables=false
がDockerデーモンに追加されました。最初の試み
docker run --name ghost -v /home/xxxx/ghost_content:/var/lib/ghost -d ghost
docker run --name nginx -p 80:80 -v /home/xxxx/nginx_site_enable:/etc/nginx/conf.d:ro --link ghost:ghost -d nginx
運がありません。最初のコマンドは問題ありませんが、2番目のコマンドはエラーをスローします
Error response from daemon: Cannot start container
2回目の試行
それから私はこれを見つけました: コンテナを--iptables = false#12701でリンクできません
次のコマンドを実行すると、すべてが正常に見えます。
Sudo iptables -N DOCKER
しかし、コンテナ内でアウトバウンド接続を確立できないことに気付きました。例えば:
xxxxg@ubuntu:~$ Sudo docker exec -t -i nginx /bin/bash
root@b0d33f22d3f4:/# ping 74.125.21.147
PING 74.125.21.147 (74.125.21.147): 56 data bytes
^C--- 74.125.21.147 ping statistics ---
35 packets transmitted, 0 packets received, 100% packet loss
root@b0d33f22d3f4:/#
--iptables=false
をDockerデーモンから削除すると、コンテナーのインターネット接続は通常に戻りますが、ufwは「正しく」機能しません(定義により...)。
では、docker + ufwのベストプラクティスは何ですか?誰でも助けを提供できますか?
ありがとう。
バート。
私は数ヶ月前のようにこのような問題を抱えていましたが、最近、私のブログで解決策とともに問題を説明することにしました。これがショートカットです。
--iptables=false
を使用しても、説明したケースではあまり役に立ちません。ここでは単に十分ではありません。デフォルトでは、どのコンテナも発信接続を行うことはできません。
ここでUFWの背後にコンテナを置くために途中で省略している小さなステップがあります。次のように、--iptables=false
を使用するか、コンテンツを含む/etc/docker/daemon.json
ファイルを作成できます
{
"iptables": false
}
結果は同じになりますが、後者のオプションでは、service docker restart
を使用してdockerサービス全体を再起動するか、この機能を無効にする前にdockerがiptablesルールを追加する機会がある場合は再起動する必要があります。
完了したら、さらに2つのことを行います。
$ sed -i -e 's/DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/g' /etc/default/ufw
$ ufw reload
そのため、UFWでデフォルトの転送ポリシーを受け入れ用に設定し、次を使用します。
$ iptables -t nat -A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE
そのようにして、iptablesルールでdockerの乱雑な動作を無効にし、同時にdockerに必要なルーティングを提供することで、コンテナーが発信接続を正常に行えるようにします。ただし、この時点からUFWルールは引き続き制限されます。
これがあなたと、答えを求めてここに来た人のために問題を解決することを願っています。
https://www.mkubaczyk.com/2017/09/05/force-docker-not-bypass-ufw-rules-ubuntu-16-04/ で問題と解決策をより包括的に説明しました
この問題は長い間存在していました。
Dockerでiptablesを無効にすると、他の問題が発生します。
インターネットで見つかった現在のソリューションに従ってサーバーを変更した場合は、まず次の変更をロールバックしてください。
--iptables=false
を含む/etc/docker/daemon.json
などのすべての変更を削除します。DROP
ではなくデフォルトのACCEPT
に戻ります。/etc/ufw/after.rules
でDockerネットワークに関連するルールを削除します。このソリューションは1つのUFW構成ファイルのみを変更する必要があり、すべてのDocker構成とオプションはデフォルトのままです。 docker iptables機能を無効にする必要はありません。
UFW構成ファイル/etc/ufw/after.rules
を変更し、ファイルの最後に次のルールを追加します。
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER
ファイルを変更した後、コマンドSudo systemctl restart ufw
を使用してUFWを再起動します。これで、パブリックネットワークは公開されたドッカーポートにアクセスできなくなり、コンテナとプライベートネットワークは相互に定期的にアクセスでき、コンテナは内部から外部ネットワークにもアクセスできます。
たとえば、パブリックネットワークがDockerコンテナによって提供されるサービスにアクセスできるようにする場合、コンテナのサービスポートは80
です。次のコマンドを実行して、パブリックネットワークがこのサービスにアクセスできるようにします。
ufw route allow proto tcp from any to any port 80
このコマンドにより、パブリックネットワークは、コンテナポートが80であるすべての公開ポートにアクセスできます。
注:オプション-p 8080:80
を使用してポートを公開する場合、ホストポート80
ではなく、コンテナポート8080
を使用する必要があります。
サービスポートが80のコンテナが複数あるが、外部ネットワークから特定のコンテナにのみアクセスしたい場合。たとえば、コンテナのプライベートアドレスが172.17.0.2である場合、次のコマンドを使用します。
ufw route allow proto tcp from any to 172.17.0.2 port 80
サービスのネットワークプロトコルがUDP(DNSサービスなど)の場合、次のコマンドを使用して、外部ネットワークが公開されているすべてのDNSサービスにアクセスできるようにすることができます。
ufw route allow proto udp from any to any port 53
同様に、IPアドレス172.17.0.2などの特定のコンテナーのみの場合:
ufw route allow proto udp from any to 172.17.0.2 port 53
次のルールにより、プライベートネットワークが相互にアクセスできるようになります。通常、プライベートネットワークはパブリックネットワークよりも信頼されています。
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
次のルールにより、UFWはパブリックネットワークがDockerコンテナによって提供されるサービスへのアクセスを許可されるかどうかを管理できます。そのため、すべてのファイアウォールルールを1か所で管理できます。
-A DOCKER-USER -j ufw-user-forward
次のルールは、すべてのパブリックネットワークによって開始された接続要求をブロックしますが、内部ネットワークから外部ネットワークへのアクセスを許可します。 TCPプロトコルの場合、パブリックネットワークからのTCP接続をアクティブに確立できません。UDPプロトコルの場合、32767未満のポートへのアクセスはすべてブロックされます。このポートはなぜですか?UDPプロトコルはステートレスなので、TCPのように。GNU/ Linuxの場合はローカルポート範囲を見つけることができます。ファイル内の/proc/sys/net/ipv4/ip_local_port_range
。デフォルトの範囲は32768 60999
です。実行中のコンテナからUDPプロトコルサービスにアクセスする場合、ローカルポートはポート範囲からランダムに選択され、サーバーはデータを返します。したがって、すべてのコンテナ内のUDPプロトコルのリッスンポートは32768未満であると想定できます。これが、パブリックネットワークが32768未満のUDPポートにアクセスしないようにする理由です。
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
https://github.com/chaifeng/ufw-docker
Sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
chmod +x /usr/local/bin/ufw-docker
ufw-docker help
ufw-docker install
ufw-docker status
ufw-docker allow webapp
ufw-docker allow webapp 80
ufw-docker allow webapp 53/udp
ufw-docker list webapp
ufw-docker delete allow webapp 80/tcp
ufw-docker delete allow webapp
ufw-user-forward
ではなくufw-user-input
を選択した理由ufw-user-input
を使用プロ:
使いやすく、理解しやすく、古いバージョンのUbuntuをサポートしています。
たとえば、コンテナポートが8080
である公開されたポートに公衆がアクセスできるようにするには、次のコマンドを使用します
ufw allow 8080
短所:
コンテナのポートを公開するだけでなく、ホストのポートも公開します。
たとえば、ホストでサービスが実行されており、ポートが8080
である場合。コマンドufw allow 8080
を使用すると、パブリックネットワークはサービスと、コンテナのポートが8080
であるすべての公開されたポートにアクセスできます。ただし、ホスト上で実行されているサービス、またはコンテナ内で実行されているサービスのみを公開し、両方ではありません。
この問題を回避するには、すべてのコンテナに対して次のようなコマンドを使用する必要があります。
ufw allow proto tcp from any to 172.16.0.3 port 8080
ufw-user-forward
を使用プロ:
同じコマンドでホストとコンテナで同時に実行されているサービスを公開することはできません。
たとえば、コンテナのポート8080
を公開する場合は、次のコマンドを使用します。
ufw route allow 8080
パブリックネットワークは、コンテナポートが8080
であるすべての公開されたポートにアクセスできます。
ただし、ホストのポート8080
にはまだパブリックネットワークからアクセスできません。そうする場合は、次のコマンドを実行して、ホストのポートへのパブリックアクセスを個別に許可します。
ufw allow 8080
短所:
Ubuntuの古いバージョンはサポートしていません。コマンドはもう少し複雑です。しかし、私のスクリプト https://github.com/chaifeng/ufw-docker を使用できます。
Ubuntuの古いバージョンを使用している場合、ufw-user-input
チェーンを使用できます。ただし、公開すべきでないサービスを公開しないように注意してください。
ufw route
サブコマンドをサポートするUbuntuの新しいバージョンを使用している場合は、ufw-user-forward
チェーンを使用し、ufw route
コマンドを使用してコンテナーのファイアウォールルールを管理することをお勧めします。
スクリプト fw-docker はDocker Swarmをサポートするようになりました。詳細については、最新のコードを参照してください https://github.com/chaifeng/ufw-docker
Swarmモードで使用する場合、このスクリプトはマネージャーノードでのみ使用してファイアウォールルールを管理できます。
after.rules
ファイルの変更Docker Swarmモードで実行すると、このスクリプトはグローバルサービスufw-docker-agent
を追加します。イメージ chaifeng/ufw-docker-agent もこのプロジェクトから自動的にビルドされます。
価値があるのは、セットアップ全体にさらに多くのブリッジネットワークが関係している場合の @ mkubaczyk's answer の補足です。これらはDocker-Composeプロジェクトによって提供される場合があり、これらのプロジェクトがsystemd
によって制御される場合、適切なルールを生成する方法は次のとおりです。
/etc/systemd/system/[email protected]
[Unit]
Description=Docker-Compose project: %I
After=docker.service
BindsTo=docker.service
AssertPathIsDirectory=/<projects_path>/%I
AssertFileNotEmpty=/<projects_path>/%I/docker-compose.yml
[Service]
Type=simple
Restart=always
WorkingDirectory=/<projects_path>/%I
ExecStartPre=/usr/bin/docker-compose up --no-start --remove-orphans
ExecStartPre=+/usr/local/bin/update-iptables-for-docker-bridges
ExecStart=/usr/bin/docker-compose up
ExecStop=/usr/bin/docker-compose stop --timeout 30
TimeoutStopSec=30
User=<…>
StandardOutput=null
[Install]
WantedBy=multi-user.target
/usr/local/bin/update-iptables-for-docker-bridges
#!/bin/sh
for network in $(docker network ls --filter 'driver=bridge' --quiet); do
iface=$(docker network inspect --format '{{index .Options "com.docker.network.bridge.name"}}' ${network})
[ -z $iface ] && iface="br-${network}"
subnet=$(docker network inspect --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' ${network})
rule="! --out-interface ${iface} --source ${subnet} --jump MASQUERADE"
iptables --table nat --check POSTROUTING ${rule} || iptables --table nat --append POSTROUTING ${rule}
done
明らかに、これはそれほどうまくスケーリングしません。
また、基本的な概念全体が、コンテナで実行されているアプリケーションの接続のソースを偽装することも注目に値します。
あなたの質問はよくわかりませんが、私が収集できるものから、Docker内で実行しているアプリにアクセスできるユーザーをより適切に制御したいと思いますか?ここでは、IPテーブルではなくフロントエンドプロキシを介してトラフィックを制御する同様の質問に回答しました Dockerコンテナへの外部アクセスをブロックする
お役に立てれば
ディラン
上記のアプローチを使用すると、UFWを使用して、ポート80(つまり、プロキシ)への着信接続のみを許可できます。これにより、プロキシ設定とDNSを介してトラフィックを制御できるというボーナスが追加され、ポートの露出が最小限に抑えられます。