동일한 호스트의 LXC, Docker 및 iptables, 컨테이너에서 컨테이너로의 포트 전달 시간 초과

동일한 호스트의 LXC, Docker 및 iptables, 컨테이너에서 컨테이너로의 포트 전달 시간 초과

읽어 주셔서 감사합니다! 호스트로 사용하는 공용 서버(debian 10)가 있고 LXC(LXD 아님) Docker이 두 컨테이너 서비스는 대부분 원래 구성으로 실행됩니다(LXC는 lxc-net 및 해당 lxcbr0브리지를 사용하고 Docker는 해당 docker0브리지를 사용함). 컨테이너는 NAT를 통과합니다.

거의 모든 것이 정상입니다(컨테이너 내 인터넷 액세스, 포트 포워딩 등).제외하고호스트 공용 IP(따라서 포트 전달)를 사용하여 내부에서 직접 컨테이너에 액세스할 수 없습니다.도커가 시작될 때(그리고 iptables: true).

LXC container web예: IP가 물리적 호스트를 가리키는 에서 호스팅되는 웹사이트에 액세스하고 싶습니다 .
외부에서(예: 내 컴퓨터):효과가있다
호스트 자체에서:효과가있다
다른 LXC 컨테이너에서:효과가있다
Docker 컨테이너에서:효과가있다
에서 web container itself:정지시키다

LXC 컨테이너는 네트워킹을 위해 간단한 집에서 만든 .NET을 사용합니다 iptables rules.

iptables -t nat -A PREROUTING -d ${MY_PUBLIC_IP}/32 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.0.0.10:443
iptables -t nat -A OUTPUT -o lo -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.0.0.10:443
iptables -t nat -A POSTROUTING -s 10.0.0.0/8 ! -d 10.0.0.0/8 -j MASQUERADE # added by LXC

몇 주 동안 나는 이 문제를 해결하려고 필사적으로 노력했지만 성공하지 못했습니다. 규칙을 수정하고, 변장 규칙을 추가하고, 규칙을 문서화해 보았으나 나 자신이 보지 못하는 오해가 있을 수도 있습니다.
docker를 사용하여 docker를 실행하거나 중지하면 iptables: false이 문제를 해결할 수 있습니다.
한 가지 해결 방법은 컨테이너의 루프백 인터페이스를 사용하도록 /etc/hosts를 조정하는 것일 수 있지만 도메인이 너무 많기 때문에 이를 피하는 것이 좋습니다.

내 생각엔 DOCKER-USER 규칙이 내 요청을 차단하고 있는 것 같지만 해결 방법을 찾을 수 없습니다.

나보다 경험이 많은 사람이 내가 뭘 잘못하고 있는지 말해 줄 수 있습니까?

답변1

너는 하나 가지고 있어야 해머리 핀제대로 작동하도록 구성하십시오.

또한 아래에 설명된 것은 동일한 LAN의 다른 LXC 컨테이너에서 작동하는 이상한 세계 이며 아마도 작동하지 않아야 할 것 입니다.브리지 네트워크 필터.


두 가지 다른 효과를 얻을 수 있습니다. 하나는 매우 미묘하고 모든 것을 이해하는 방식을 변경합니다.

  • Docker는 커널 모듈을 br_netfilter로드합니다. 내 답변에서 설명했듯이iptable은 Linux 브리지와 어떻게 작동합니까?, 이는iptables규칙 영향브리지된액자.

    이 규칙은 일반적으로 라우팅 경로에서 호출되어야 합니다.

    iptables -t nat -A PREROUTING -d ${MY_PUBLIC_IP}/32 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.0.0.10:443
    

    대상을 10.0.0.10으로 변경합니다. 이는 또한 다음을 의미합니다.

    iptables -t nat -A POSTROUTING -s 10.0.0.0/8 ! -d 10.0.0.0/8 -j MASQUERADE # added by LXC
    

    지금은 발동되지 않습니다.

    따라서 클라이언트 컨테이너가 10.0.0.11이면 결과는 다음과 같습니다.회로망컨테이너 응답곧장브리지 경로를 통해 10.0.0.11에 도달하세요. 10.0.0.11은 알 수 없는 IP 주소 10.0.0.10(MY_PUBLIC_IP 아님)으로부터 연결을 수신하므로 TCP RST가 다시 전송됩니다. 이는 Docker가 실행되지 않으면(연결이 전혀 관련되지 않은 경우에도) LXC -> LXC 사례가 작동하지 않음을 의미합니다.

    그리고 br_netfilter로드됨브리지된프레임은반품~에 의해연결하다및 네트워크 주소 변환. 따라서 10.0.0.11에 응답할 때 10.0.0.10이 브리지 경로에서 가로채어 소스 MY_PUBLIC_IP로 다시 디DNA됩니다. 10.0.0.11 MY_PUBLIC_IP에서 여전히 응답을 보았습니다: 투명 헤어핀이 발생했습니다.

    그래도 괜찮긴 하지만이상한 행동그것을 염두에 두어야 하며 당연하게 여기지 말아야 합니다. 일반적인 동작은 브리지 패킷을 변경하지 않는 것입니다. 다시 말하지만, 정상적인 행동은iptables' FORWARD 체인은 브리지 컨테이너를 필터링하지 않지만 이제 필터링됩니다.

    이에 대한 자세한 내용은 여기를 확인하세요.개략도. 하단 파란색(브리지 수준) 배경의 녹색(네트워크 수준) 상자는 에 의해 활성화됩니다 br_netfilter. 그림 3c를 확인할 수도 있습니다.Linux 기반 브리지의 ebtables/iptables 상호 작용.

  • 연결의 경우회로망br_netfilter때로는 (모듈을 로드하지 않고도) 10.0.0.10에서 10.0.0.10까지 유선을 통해 컨테이너와 자체 사이에 연결이 있을 수 있지만 작동하지 않습니다. 기본적으로 네트워크 스택은 자체 소스 주소 Bag으로 수신된 원격 데이터를 삭제합니다. 하지만 버그처럼 보이는 또 다른 문제가 있습니다. 아래를 참조하세요.


따라서 현재 구성에 반창고를 적용하려면 소스 IP 주소를 라우팅된 IP 주소로 변경해야 합니다. 8.8.8.8 등 무엇이든 될 수 있지만 직접 제어하는 ​​것이 더 좋습니다. MY_PUBLIC_IP 또는 실용적이지 않은 경우 할당된 주소lxcbr0(10.0.0.1이라고 가정합니다.) 이는 웹 서비스가 로그에서 자체 IP 주소를 볼 수 없음을 의미합니다. 이것은 완전히 피할 수 없는 일입니다.

그러나 설명할 수 없는 이유로 시행착오(넷필터에서 패킷 추적) 후에반품무차별 모드는 브리지 자체 인터페이스에서 활성화되어야 합니다.lxcbr0그렇지 않으면 ip nat/PREROUTING과 브리지 필터/INPUT 사이에서 패킷이 사라집니다(이 순서대로 다시 확인하세요).그림 3c), 따라서 ip nat/POSTROUTING에 도달하지 않습니다. 것 같다8장에 설명된 동작예상대로 일어나지 않았습니다.

ip link set lxcbr0 promisc on

그런 다음 다음을 추가합니다.

iptables -t nat -A POSTROUTING -s 10.0.0.10 -p tcp --dport 443 -j SNAT --to-source $MY_PUBLIC_IP

또는:

iptables -t nat -A POSTROUTING -s 10.0.0.10 -p tcp --dport 443 -j MASQUERADE

또는 DNATed 스트림과 일치시키십시오(SNAT 대상에서도 작동함).

iptables -t nat -A POSTROUTING -s 10.0.0.10 -m conntrack --ctstate DNAT -j MASQUERADE

최신 커널(5.3 이상이라고 생각함) 에서는 네트워크 네임스페이스 또는 브리지(예: )별로 ip link set lxcbr0 type bridge nf_call_iptables 1활성화를 선택적으로 활성화 또는 비활성화할 수 있습니다 net.bridge.bridge-nf-call-iptables. 하지만 Docker가 이를 어떻게 트리거하는지 모릅니다(보통 다음과 같은 이유 때문입니다).-m physdev iptables일치하지만 유일한 경우는 아닐 수 있음) Docker가 평소대로 작동하도록 유지하면서 이 기능을 비활성화할 위치를 아는 것은 어렵습니다.

관련 정보