dockerポートの転送とiptables / nftablesについて学ぶ

dockerポートの転送とiptables / nftablesについて学ぶ

かなり一般的なnftables / iptablesファイアウォール設定を考慮すると(OUTPUT承認、INPUT / FORWARD承認設定+依存、デフォルト削除):

table ip nat {
    chain DOCKER {
        iifname "docker0" return
        iifname != "docker0" meta l4proto tcp ip daddr 172.17.0.1 tcp dport 5000 dnat to 172.17.0.2:5000
        iifname != "docker0" meta l4proto tcp ip daddr 127.0.0.1 tcp dport 5000 dnat to 172.17.0.2:5000
    }

    chain POSTROUTING {
        type nat hook postrouting priority srcnat; policy accept;
        oifname != "docker0" ip saddr 172.17.0.0/16 masquerade
        meta l4proto tcp ip saddr 172.17.0.2 ip daddr 172.17.0.2 tcp dport 5000 masquerade
    }

    chain PREROUTING {
        type nat hook prerouting priority dstnat; policy accept;
        fib daddr type local jump DOCKER
    }

    chain OUTPUT {
        type nat hook output priority -100; policy accept;
        ip daddr != 127.0.0.0/8 fib daddr type local jump DOCKER
    }
}
table ip filter {
    chain INPUT {
        type filter hook input priority filter; policy drop;
        iif "lo" accept comment "Allow loopback"
        ct state invalid drop
        ct state established,related accept
        iifname "bond0-data" tcp dport 22 accept
        udp dport 3052 accept
        iifname "bond0-data" tcp dport 9090 accept
        log drop
    }

    chain FORWARD {
        type filter hook forward priority filter; policy drop;
        jump DOCKER-USER
        jump DOCKER-ISOLATION-STAGE-1
        oifname "docker0" ct state related,established accept
        oifname "docker0" jump DOCKER
        iifname "docker0" oifname != "docker0" accept
        iifname "docker0" oifname "docker0" accept
        log drop
    }

    chain OUTPUT {
        type filter hook output priority filter; policy accept;
    }

    chain FORWARD-OVERRIDE {
        type filter hook forward priority filter + 10; policy accept;
        ct state invalid drop
        ct state established,related accept comment "Accept established, related"
        iifname "bond1-control" drop comment "Drop new connections from bond1-control"
    }

    chain DOCKER {
        iifname != "docker0" oifname "docker0" meta l4proto tcp ip daddr 172.17.0.2 tcp dport 5000 accept
    }

    chain DOCKER-ISOLATION-STAGE-1 {
        iifname "docker0" oifname != "docker0" jump DOCKER-ISOLATION-STAGE-2
        return
    }

    chain DOCKER-ISOLATION-STAGE-2 {
        oifname "docker0" drop
        return
    }

    chain DOCKER-USER {
        return
    }
}

コンテナ 172.17.0.2:5000 は、docker のポート転送を使用してポート 5000 にマッピングされます。

コンテナ172.17.0.3から172.17.0.2:5000に直接接続しようとすると機能します。ホストIP(172.17.0.1:5000)を介してコンテナ172.17.0.3から接続しようとすると、iffname "docker0" acceptINPUTチェーンに追加しないと機能しません。

理由を理解したいです。

kern.log は、接続しようとすると次のようになります。

IN=docker0 OUT= PHYSIN=vethbdc197b MAC=xxxxxxx SRC=172.17.0.3 DST=172.17.0.1 LEN=44 TOS=0x00 PREC=0x00 TTL=58 ID=37344 PROTO=TCP SPT=52535 DPT=5000 WINDOW=1024 RES=0x00 SYN URGP=0

直接接続は許可されていますが、なぜこの接続はブロックされますか?現在のところ、出力が何らかの形で直接接続を可能にし、入力がそれを確立され関連するものとして扱うことが最善の推測です。ただし、Dockerポートマッピングを実行するときに状況がどのように異なるかは不明です。 DNATは別々のINPUT接続を引き起こし、ブロックされる可能性がありますか?

iptables/nftablesの観点から、これがどのように機能するかを教えてくれる人はいますか?

ベストアンサー1

この質問に対する答えは非常に簡単であることがわかりました。私の考えでは、コンテナはホストネットワークスタックによって「追加」IPとしてマークされているようです。これは本当ではありません。コンテナにはホストとは別に独自のネットワークスタックがあります(技術的には、コンテナには独自のiptables / nftablesルールもあります)。

これは、関連するIPがホストネットワークスタックのローカルIPではないため、コンテナ間の直接接続がホストのOUTPUTまたはINPUTチェーンを通過しないことを意味します。方向接続は次のとおりです。

  • コンテナA出力(空になる可能性があります)
  • ホスト転送
  • コンテナB入力(空になる可能性があります)

これがホストでFORWARDを介して機能するという事実は少し驚くべきことです。私がテストした結果、実際にそうです。これは、ブリッジがどのように機能するかによるものです。

この場合、FORWARDチェーンにあるため、ホストは接続を許可しますiifname "docker0" oifname "docker0" accept

一方、コンテナAがホストの転送ポートに接続しようとすると、ホストのINPUTチェーンに入り、上記の規則に従ってブロックされます。

おすすめ記事