この問題は私を夢中にさせています。 Ubuntu 18.04のフレッシュインストールを実行します。
私は標準のdocker.ioパッケージを試してみましたが、パッケージはdocker自身のdebリポジトリから作成されました。
ポートをバインドするIP(例:-p 10.58.26.6:98800:98800)を選択し、UFWでポートを開くDockerコンテナーを展開できるようにしたい。
しかし、Dockerはbr0ブリッジを混乱させるiptablesルールを作成するようです(たとえば、ホストはlibvirtゲストにpingできない)。
私は周りを見回しましたが、セキュリティに配慮した優れたソリューションを見つけることができません。
iptables -I FORWARD -i br0 -o br0 -j ACCEPT
seemsを手動で実行すると、すべてが機能するようになります。
また、Dockerデーモンに"iptables": false
を設定すると、ブリッジは正常に動作しますが、Dockerのコンテナーの下りネットワークが壊れます。
単一のUFWのファイルを編集することで、このソリューションは単純に見えました https://stackoverflow.com/a/51741599/1091772 が、まったく機能しません。
これを永続的に解決し、再起動まで生き残るためのベストプラクティスと安全な方法は何ですか?
EDIT:COMMITの前の-A ufw-before-forward -i br0 -o br0 -j ACCEPT
の最後に/etc/ufw/before.rules
を追加してしまいました。これを修正と見なすことはできますか、それともいくつかの問題を引き起こしませんか?
説明から、論理的な説明は bridge netfilter code が有効になっていることだけだと思います:ステートフルブリッジファイアウォールやiptablesの活用など、さまざまな用途に使用できます'すべてをebtablesに複製する必要がない(または複製できない)ブリッジパスの一致およびターゲット。ネットワークレイヤー2のイーサネットブリッジコードであるネットワークレイヤーをまったく無視すると、IPレベル、つまりネットワークレイヤー3で動作するiptablesがupcallされるようになります。ホストとすべてのコンテナ、またはなし。何が起こっているかを理解し、何を探すべきかを知ったら、適応した選択を行うことができます。
Netfilterプロジェクトは、br_netfilterが有効な場合のさまざまな ebtables
/iptables
相互作用 について説明します。特に興味深いのは セクション7 のように、ブリッジパスからの意図しない影響を回避するために、明らかな影響のないいくつかのルールが必要になる場合がある理由を説明します。
iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -d 172.16.1.0/24 -j ACCEPT iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE
同じLAN上の2つのシステムがブリッジでNAT処理されるのを回避するため(ブリッジの例を参照)。
問題を回避するための選択肢はいくつかありますが、詳細をすべて知りたくない場合や、一部のiptablesルール(他の名前空間に隠されている場合もある)が中断されるかどうかを確認したくない場合は、おそらく最善の選択です。
br_netfilterモジュールがロードされるのを永久に防ぎます。通常、blacklist
では不十分です。install
を使用する必要があります。これは、br_netfilterに依存するアプリケーションで問題が発生しやすい選択肢です。明らかにDocker、Kubernetes、...
echo install br_netfilter /bin/true > /etc/modprobe.d/disable-br-netfilter.conf
モジュールをロードしますが、その効果を無効にします。 iptables 'の効果の場合:
sysctl -w net.bridge.bridge-nf-call-iptables=0
起動時にこれを配置する場合、モジュールを最初にロードする必要があります。そうしないと、このトグルはまだ存在しません。
これら2つの以前の選択は、確実にiptables一致を混乱させます -m physdev
:xt_physdevモジュールそれ自体がロードされると、br_netfilterモジュールが自動ロードされます(これは、コンテナーから追加されたルールがロードをトリガーした場合でも発生します)。これでbr_netfilterは読み込まれなくなり、-m physdev
はおそらく一致しません。
OPのように、必要に応じてbr_netfilterの影響を回避します。 セクション7 で説明されているように、さまざまなチェーン(PREROUTING、FORWARD、POSTROUTING)にこれらの明らかなノーオペレーションルールを追加します。例えば:
iptables -t nat -A POSTROUTING -s 172.18.0.0/16 -d 172.18.0.0/16 -j ACCEPT
iptables -A FORWARD -i br0 -o br0 -j ACCEPT
いくつかのまれなDNAT設定を除いて、同じIP LAN内のトラフィックはルーティングされないため、これらのルールが一致することはありません。ただし、br_netfilterのおかげで一致します。これは、switchedフレーム(IPパケットに「アップグレード」)を最初に呼び出すためです。 bridge。次に、それらはroutedパケットに対して再度呼び出され、routerを無関係のインターフェースに転送します(ただし、一致しません)。
ブリッジにIPを置かないでください。そのIPをveth
インターフェイスの一方の端に、ブリッジのもう一方の端に配置します。これにより、ブリッジがルーティングと相互作用しないことが保証されますが、そうではありません。ほとんどのコンテナー/ VM共通製品を実行しています。
独自の分離されたネットワーク名前空間でブリッジを非表示にすることもできます(今回は、他のebtablesルールから分離したい場合にのみ役立ちます)。
すべてを nftables に切り替えます。これにより、指定された目標の中でこれらの ブリッジの相互作用の問題 が回避されます。現時点では、ブリッジファイアウォールは利用可能なステートフルサポートを備えていません。それは [〜#〜] wip [〜#〜] ですが、「アップコール」がないため、利用可能な場合はよりクリーンであることが約束されています。 。
br_netfilter(例:-m physdev
)のロードをトリガーするものを検索し、それを回避できるかどうかを確認して、続行方法を選択する必要があります。
ネットワーク名前空間を使用していくつかの効果を再現しましょう。 ebtablesルールはどこでも使用されないことに注意してください。また、この例は、Debianバスターでデフォルトで有効になっている nftables over iptables ではなく、通常のレガシー iptables
に依存していることにも注意してください。
多くのコンテナー使用法と同様の単純なケースを再現してみましょう:ルーター192.168.0.1/192.0.2.100がNAT背後に2つのホスト:192.168.0.101と192.168.0.102を持ち、ブリッジ上のブリッジにリンクされています) 2つのホストは、ブリッジを介して、同じLANで直接通信できます。
#!/bin/sh
for ns in Host1 Host2 router; do
ip netns del $ns 2>/dev/null || :
ip netns add $ns
ip -n $ns link set lo up
done
ip netns exec router sysctl -q -w net.ipv4.conf.default.forwarding=1
ip -n router link add bridge0 type bridge
ip -n router link set bridge0 up
ip -n router address add 192.168.0.1/24 dev bridge0
for i in 1 2; do
ip -n Host$i link add eth0 type veth peer netns router port$i
ip -n Host$i link set eth0 up
ip -n Host$i address add 192.168.0.10$i/24 dev eth0
ip -n Host$i route add default via 192.168.0.1
ip -n router link set port$i up master bridge0
done
#to mimic a standard NAT router, iptables rule voluntarily made as it is to show the last "effect"
ip -n router link add name eth0 type dummy
ip -n router link set eth0 up
ip -n router address add 192.0.2.100/24 dev eth0
ip -n router route add default via 192.0.2.1
ip netns exec router iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j MASQUERADE
カーネルモジュールbr_netfilterをロードして(後でないことを確認)、(not-per-namespace)トグルを使用してその効果を無効にしますbridge-nf-call-iptables、初期ネームスペースでのみ使用可能:
modprobe br_netfilter
sysctl -w net.bridge.bridge-nf-call-iptables=0
警告:繰り返しますが、これは -m physdev
のようなiptablesルールをホスト上の任意の場所または依存するコンテナbr_netfilterがロードされ、有効になっています。
Icmp pingトラフィックカウンターをいくつか追加してみましょう。
ip netns exec router iptables -A FORWARD -p icmp --icmp-type echo-request
ip netns exec router iptables -A FORWARD -p icmp --icmp-type echo-reply
Pingしましょう:
# ip netns exec Host1 ping -n -c2 192.168.0.102
PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.058 ms
--- 192.168.0.102 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1017ms
rtt min/avg/max/mdev = 0.047/0.052/0.058/0.009 ms
カウンターは一致しません:
# ip netns exec router iptables -v -S FORWARD
-P FORWARD ACCEPT -c 0 0
-A FORWARD -p icmp -m icmp --icmp-type 8 -c 0 0
-A FORWARD -p icmp -m icmp --icmp-type 0 -c 0 0
bridge-nf-call-iptablesを有効にして、もう一度pingします。
# sysctl -w net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-iptables = 1
# ip netns exec Host1 ping -n -c2 192.168.0.102
PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.163 ms
--- 192.168.0.102 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1006ms
rtt min/avg/max/mdev = 0.094/0.128/0.163/0.036 ms
今回切り替えられたパケットは、iptablesのfilter/FORWARDチェーンで一致しました。
# ip netns exec router iptables -v -S FORWARD
-P FORWARD ACCEPT -c 4 336
-A FORWARD -p icmp -m icmp --icmp-type 8 -c 2 168
-A FORWARD -p icmp -m icmp --icmp-type 0 -c 2 168
DROPポリシー(デフォルトのカウンターをゼロにする)を入力して、もう一度試してみましょう。
# ip netns exec Host1 ping -n -c2 192.168.0.102
PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
--- 192.168.0.102 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1008ms
# ip netns exec router iptables -v -S FORWARD
-P FORWARD DROP -c 2 168
-A FORWARD -p icmp -m icmp --icmp-type 8 -c 4 336
-A FORWARD -p icmp -m icmp --icmp-type 0 -c 2 168
ブリッジコードは、iptablesを介してスイッチフレーム/パケットをフィルタリングしました。 OPのようにバイパスルール(デフォルトのカウンターを再びゼロにする)を追加して、もう一度試してみましょう。
# ip netns exec router iptables -A FORWARD -i bridge0 -o bridge0 -j ACCEPT
# ip netns exec Host1 ping -n -c2 192.168.0.102
PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.132 ms
64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.123 ms
--- 192.168.0.102 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1024ms
rtt min/avg/max/mdev = 0.123/0.127/0.132/0.012 ms
# ip netns exec router iptables -v -S FORWARD
-P FORWARD DROP -c 0 0
-A FORWARD -p icmp -m icmp --icmp-type 8 -c 6 504
-A FORWARD -p icmp -m icmp --icmp-type 0 -c 4 336
-A FORWARD -i bridge0 -o bridge0 -c 4 336 -j ACCEPT
Host1からのping中にHost2で実際に受信されたものを見てみましょう。
# ip netns exec Host2 tcpdump -l -n -s0 -i eth0 -p icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
02:16:11.068795 IP 192.168.0.1 > 192.168.0.102: ICMP echo request, id 9496, seq 1, length 64
02:16:11.068817 IP 192.168.0.102 > 192.168.0.1: ICMP echo reply, id 9496, seq 1, length 64
02:16:12.088002 IP 192.168.0.1 > 192.168.0.102: ICMP echo request, id 9496, seq 2, length 64
02:16:12.088063 IP 192.168.0.102 > 192.168.0.1: ICMP echo reply, id 9496, seq 2, length 64
...ソース192.168.0.101の代わりに。 MASQUERADEルールもブリッジパスから呼び出されました。これを回避するには、前に例外ルールを追加するか( (セクション7 の例で説明))、または可能な場合はブリッジ以外の発信インターフェースを記述します(これが利用可能になった場合、-m physdev
ブリッジにする必要がある場合...).
ランダムに関連:
LKML/netfilter-dev: br_netfilter:非初期netnsで有効にする :グローバルではなくネームスペースごとにこの機能を有効にすると、ホストとコンテナー間の相互作用が制限されます。
netfilter-dev: netfilter:physdev:br_netfilter依存関係を緩和 :存在しないphysdevルールを削除しようとすると、問題が発生する可能性があります。
netfilter-dev: ブリッジの接続追跡サポート :nftablesを使用してステートフルブリッジファイアウォールを準備するWIPブリッジネットフィルターコード。今回はよりエレガントに。 iptables(カーネルサイドAPI)を取り除くための最後のステップの1つだと思います。
上記の脅威で問題が解決しない場合は、Debian Stretchで問題を解決した方法を次に示します。
まず、現在のiptablesを保存します
iptables-save > your-current-iptables.rules
2番目、削除[〜#〜] all [〜#〜] Dockerが作成したルール
iptables -D <DOCKER-CHAIN-RULES> <target-line-number>
3番目に、入力、転送、出力へのトラフィックを受け入れるitpablesルールを追加します
iptables -I INPUT -j ACCEPT
iptables -I FORWARD -j ACCEPT
iptables -I OUTPUT -j ACCEPT
4番目に、Dockerを再起動します
service docker restart
手順3が完了すると、ブロックされたlibvert KVMホストに別のPCからpingを実行できます。ICMP応答が表示されます。
Dockerを再起動すると、必要なiptablesルールもマシンに追加されますが、ブリッジされたKVMホストをブロックしなくなります。
上記の解決策が機能しない場合は、次のコマンドを使用してiptablesを復元できます。
Iptablesを復元する
iptables-restore < your-current-iptables.rules