iptables - 인바운드 트래픽을 내부 IP로 전달합니다(Docker 인터페이스).

iptables - 인바운드 트래픽을 내부 IP로 전달합니다(Docker 인터페이스).

iptables 관련 질문이 있습니다. 내 컴퓨터에는 다음 네트워크 인터페이스가 정의되어 있습니다.

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
   valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether f8:ca:b8:5c:59:b5 brd ff:ff:ff:ff:ff:ff
inet 172.16.214.45/24 brd 172.16.214.255 scope global dynamic eno1
   valid_lft 773635sec preferred_lft 773635sec
3: wlp3s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 80:00:0b:d7:a8:c5 brd ff:ff:ff:ff:ff:ff
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
link/ether 02:42:bf:b2:fa:86 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
   valid_lft forever preferred_lft forever

IP 172.17.0.2(docker0 인터페이스에 연결됨)를 수신하는 활성 도커 컨테이너가 있습니다.

나는 두 가지 일을 하고 싶다:

  1. 내 컴퓨터의 포트 8443에서 들어오는 모든 패킷을 포트 8443의 docker 컨테이너 IP 172.17.0.2로 전달합니다.
  2. lo 인터페이스의 모든 루프백 패킷을 포트 8443의 docker 컨테이너 IP 172.17.0.2로 전달합니다.

이 작업을 수행했지만 루프백 인터페이스에서 테스트할 때 작동하지 않습니다.

iptables -t nat -I PREROUTING -i lo -d 127.0.0.1 -p tcp --dport 8443 -j DNAT --to-destination 172.17.0.2:8443

$ curl https://localhost:8443
curl: (7) Failed to connect to localhost port 8443: Connection refused

$ curl -k https://172.17.0.2:8443
{
  "paths": [
    "/api"
  ]
}

경험 많은 iptables 사람들로부터 내가 뭔가 잘못하고 있다는 징후가 있습니까?

답변1

두 가지 질문(실제로 철저한 경우를 대비해 간단한(최선은 아닐지라도) 솔루션으로 해결하려는 질문되지 않은 세 번째 질문):

로컬에서 시작된 패킷은 전달/라우팅되지 않습니다.

로컬에서 시작된 패킷은 전달(라우팅)되지 않습니다. 따라서 이러한 패킷은 nat/PREROUTING체인을 볼 수 없습니다. 보세요일반 네트워크의 Netfilter 및 패킷 흐름커널에서 패킷의 수명주기 동안 어떤 일이 발생하는지 이해합니다. 로컬 패킷은 "로컬 프로세스"에서 나옵니다.

따라서 "외부"에서 들어오는 패킷에 대한 규칙을 nat/PREROUTING적용하는 것 외에도 DNAT다음과 같아야 합니다.

iptables -t nat -I PREROUTING -i eno1 -p tcp --dport 8443 -j DNAT --to-destination 172.17.0.2:8443

nat/OUTPUT체인 도 사용해야 합니다 . 출력 시 구문은 나가는 인터페이스만 허용하므로 다음과 같이 변경됩니다.

iptables -t nat -I OUTPUT -o lo -p tcp --dport 8443 -j DNAT --to-destination 172.17.0.2:8443

초기 패킷과 후속 흐름은 실제로 다른 인터페이스로 재라우팅됩니다(이전 링크 다이어그램의 "재라우팅 확인"이 올바르게 배치되지 않았을 수 있습니다).

이는 호스트에 속한 모든 IP(예: 172.16.214.45 및 172.17.0.1)에 대해 작동합니다.

loIP 범위 127.0.0.0/8이 인터페이스 외부에 표시되지 않도록 비활성화

Linux 커널에는 127.0.0.0/8 범위의 IP가 인터페이스 이외의 다른 곳으로 라우팅되는 것을 방지하는 특정 설정이 있으며 lo화성 소스와 같은 다른 인터페이스를 사용하려고 "시도"하는 경우 이러한 패킷을 삭제합니다. 예 : 원격 시스템(컨테이너라도)은 소스 주소가 127.0.0.1이고 대상 주소가 172.17.0.2인 수신 패킷을 수락하지 않습니다. 적어도 응답할 위치를 모르기 때문입니다.

따라서 그 외에도 이번에는 통과된 체인에서 패킷에 대한 SNAT(또는 간단한) 작업이 있어야 합니다(이전 회로도 참조).MASQUERADEDNATnat/POSTROUTING

iptables -t nat -I POSTROUTING -s 127.0.0.1 -d 172.17.0.2 -j MASQUERADE

이것만으로는 충분하지 않습니다. 이름에서 알 수 있듯이 nat/POSTROUTING이런 일이 발생합니다 .뒤쪽에라우팅(실제로는 이후에 발생하는 재라우팅 확인 DNAT) 및 패킷이 화성 소스로 삭제되었습니다.

이 예와 같은 특별한 경우에는 인터페이스별 스위치를 사용하여 로컬 네트워크 제한을 무시할 수 있습니다.route_localnet:

echo 1 > /proc/sys/net/ipv4/conf/docker0/route_localnet

이제 라우팅 스택은 소스가 127.0.0.1인 패킷이 통과하도록 허용하며 가상 회선을 통해 컨테이너로 전송되기 전에 해당 소스는 이전 규칙에 따라 172.17.0.1로 수정됩니다. 작동합니다.

두 번째 경우가 필요한 것은 불필요한 복잡성이므로 피해야 합니다. 127.0.0.1 대신 호스트에 속한 IP를 사용하면 모든 테스트에 충분합니다. 또한 docker0인터페이스를 삭제하고 다시 생성 하면 route_localnet설정이 손실되므로 기본값으로 설정하는 것은 현명하지 않습니다.

머리 핀

묻지 않았지만 동일한 LAN에 두 번째 시스템(여기서는 컨테이너)을 추가하면 lan-to-host-to-same-lan 리디렉션에 문제가 발생합니다(Docker가 이미 네트워크 수준에서 이를 처리하지 않는 한).

nat/PREROUTING답변 시작 부분에 작성한 규칙은 인터페이스만 처리합니다 eno1. 이유 때문에 이 제한을 추가했습니다 -i eno1. 이 제한이 없으면 172.17.0.0/16 네트워크의 다른 컨테이너가 예를 들어 172.16.214.45:8443(또는 172.17.0.1:8443)에 연결을 시도하면 패킷이 172.17 .0.2로 리디렉션됩니다. 172.17.0.2가 답글을 달겠습니다곧장소스로: 또 다른 컨테이너이며 호스트와 해당 NAT 규칙을 완전히 우회합니다. 컨테이너는 자신이 모르는 소스에서 오는 응답 패킷을 보고 이를 거부합니다(사용 TCP RST). 그러므로 제대로 처리하지 않는 것보다 전혀 처리하지 않는 것이 좋습니다. Docker는 호스트를 개입시키지 않고 다른 컨테이너의 IP/포트에 직접 서비스를 확인하는 특정 방법을 제공할 수 있습니다.

어쨌든 필요한 경우 이를 극복할 수 있는 여러 가지 방법이 있으며, 종종 간단한 NAT(소스 IP를 잃거나 로깅 목적을 위해 이를 가상 네트워크로 변환해야 함)부터 복잡한 브리지 및/또는 가로채기 가능에 이르기까지 다양한 절충안을 사용하거나 설정합니다. LAN 통신을 위해 라우터를 설정합니다.

소스가 SNAT인 간단한 솔루션은 다음과 같습니다.NETMAP, 가상 네트워크 10.17.0.0/16에 연결됩니다. 간단한 전제 조건: 10.17.0.0/16은 호스트(실제로 사용되지 않더라도), 기본 경로(경우에 따라 다름), 특정 경로 또는 해당 IP가 있는 호스트에서 라우팅되어야 합니다. 가상 네트워크가 이 목적입니다. 이 IP를 가진 패킷은 docker0네트워크 내부에만 존재합니다.

-i eno1위 규칙을 제거한 후 PREROUTING다음과 같은 새 규칙을 추가하세요.

iptables -t nat -I POSTROUTING -s 172.17.0.0/16 -d 172.17.0.0/16 -j NETMAP --to 10.17.0.0/16

이제 LAN에서 동일한 LAN으로의 리디렉션이 작동하고 대상 컨테이너의 로그에 10.17.0.0/16 범위의 소스 IP가 표시됩니다.

물론 머리핀 상황도 피해야 합니다.

관련 정보