Docker 컨테이너가 호스트 IP의 서비스에 액세스 할 수 있도록 IPtables 규칙 세트


18

도커 컨테이너에서 호스트 개인 인터페이스 (ip)에 액세스하는 데 문제가 있습니다. 나는 그것이 Iptables 규칙 (또는 라우팅)과 관련이 있다고 확신합니다. 에 --net=host플래그를 추가하면 docker run모든 것이 예상대로 작동합니다. 마찬가지로 INPUT 정책이 자유주의를 따르도록 지정 -P INPUT ACCEPT하면 예상대로 작동합니다. 그러나 이것은 바람직하지 않고 안전하지 않은 옵션입니다.

내 서비스 (DNS)에만 국한되지 않기 때문에 문제에서 제외했습니다. 도커와 함께 검색하면 다른 (인기있는) 문제 영역에서 결과가 나오기 때문에 검색 결과에 노이즈가 추가됩니다.

또한 Docker 컨테이너의 링크는 실행 가능한 옵션이 아닙니다. 왜냐하면 특정 컨테이너는 --net = host 옵션으로 실행해야 연결이 불가능하고 가능한 한 일관된 상황을 만들고 싶습니다.

다음 Iptables 규칙이 있습니다. CoreOS, Digital Ocean 및 Docker의 조합으로 가정합니다.

-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N DOCKER
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT

내 (관련) 호스트 인터페이스 :

3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet 10.129.112.210/16 brd 10.129.255.255 scope global eth1
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever

그리고 도커 컨테이너를 실행합니다.

$ docker run --rm -it --dns=10.129.112.210 debian:jessie # Specifying the DNS is so that the public DNS servers aren't used.

이 시점에서 10.129.112.210:53에 바인딩 된 로컬 서비스를 사용할 수 있기를 원합니다. 따라서 다음과 같은 답변이 제공됩니다.

$ ping google.com
^C
$ ping user.skydns.local
^C

호스트에서 동일한 명령을 실행할 때 :

$ ping photo.skydns.localPING photo.skydns.local (10.129.112.206) 56(84) bytes of data.
64 bytes from 10.129.112.206: icmp_seq=1 ttl=64 time=0.790 ms
^C

내 resolv.conf

$ cat /etc/resolv.conf
nameserver 10.129.112.210
nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 8.8.4.4

여기서 중요한 점은 호스트에서 사용 가능한 로컬 DNS 서비스 (다른 도커 인스턴스를 통해)를 사용하여 퍼블릭 호스트가 아니라 내부 호스트에 액세스하는 것입니다.

더 자세히 설명하기 위해 (아스키 아트 디자인 기술이 내 iptables fu를 능가 하므로이 시점에서 충분히 말해야합니다) :

 ______________________________________________
|  __________________________           Host   |
| |   Docker DNS container   |                 |
|  ``````````````````````|```                  |
|                        |                     |
|     ,----------,---( private n. interface )  |
|     |          |                             |
|     |          |   ( public  n. interface )---
|     |          |                             |
|     |          |   ( loopbck n. interface )  |
|     |          |                             |
|     |          |                             |
|     |        __|_______________________      |
|     |       | Docker service container |     |
|     |        ``````````````````````````      |
|     |                                        |
|     |                                        |
| [ Local host service using DNS. ]            |
|                                              |
|______________________________________________|

  private (host) network interface: eth1 (10.129.0.0/16)
  Docker network interface: docker0 (172.17.0.0/16)

나는 다른 예제 Iptables 구성을 검색하고 읽고 적용했지만, 진행중인 상황을 이해하고 원하는 결과를 얻기 위해 더 "고급"Iptables 규칙을 너무 적게 알고 있습니다.

출력 iptables -t nat -nL:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

Chain DOCKER (2 references)
target     prot opt source               destination

출력 cat /proc/sys/net/ipv4/ip_forward:

1

의 출력을 게시 할 수 있습니까 iptables -t nat -nL? 소스 컨테이너에서 핑을 수행하고 tcpdump를 사용하여 호스트의 패킷을 캡처하는 등 패킷 분석을 수행 했습니까?
다니엘 t.

확실히, 지금까지 도와 주셔서 감사합니다. pastebin.com/TAaT73nk (주석에 맞지 않았습니다 ..)- 편집 -> 만료되지 않은 페이스트 빈에 대한 링크가 업데이트되었습니다.
Dynom

어쩌면 나는 당신의 문제를 올바르게 이해하지 못했지만 호스트에서 DNS 쿼리를 허용하는 규칙을 보지 못했습니다. 또한 ip_forward가 활성화되어 있습니까?
Laurentiu Roescu

안녕하세요 @LaurentiuRoescu. $ cat /proc/sys/net/ipv4/ip_forward -> 1그리고 -A INPUT -i eth1 -j ACCEPT온 모든 연결을 받아 개인 인터페이스를. 어떤 규칙이 누락 되었습니까?
Dynom

2
컨테이너의 패킷은 eth1이 아닌 docker0 인터페이스에서 나온 것 같습니다. 시도-A INPUT -i docker0 -j ACCEPT
Laurentiu Roescu

답변:


14

컨테이너는 docker0인터페이스를 사용하여 호스트와 통신 합니다. 컨테이너에서 트래픽을 허용하려면 다음을 추가하십시오.

-A INPUT -i docker0 -j ACCEPT

2
Dynom, 당신이 이것을 없애고 싶을 수있는 교훈은 모든 거부를 기록하는 것이 유용하다는 것 iptables -A INPUT -j LOG입니다. 이 스탬프 IN=docker0는 룰 조정이 필요한 작업을 수행하는 데 매우 유용했을 것입니다. Laurentiu의 작품을 빼앗아 가지 마십시오.
MadHatter는 Monica

5
UFW를 사용하는 사람들을 위해 Docker 컨테이너에서 호스트로의 모든 통신을 허용하기 위해 수행 한 작업은 다음과 같습니다. ufw allow on on docker0
Ali Ok

0

매우 비슷한 상황이 발생했지만 추가 -A INPUT -i docker0 -j ACCEPT하면 docker 호스트의 eth0 인터페이스를 통해 컨테이너에 대한 모든 액세스 권한이 열리게됩니다.

그리고 컨테이너가 호스트 네트워크에서 완전히 종료되는 대신 호스트 인터페이스에 대한 액세스 (포트 22 만)에 대한 액세스가 제한되어 있음을 알았으므로 iptables 규칙을 검토하고 체인 IN_public_allow에서 규칙을 찾았습니다. 규칙은 -A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT입니다. 따라서 컨테이너가 원하는 다른 호스트 포트에 액세스 할 수 있도록 비슷한 규칙을 추가했습니다. 이는 컨테이너에 대한 호스트 네트워크 액세스를 여는보다 정확한 방법 일 수 있습니다.


-i docker0이는 docker0 네트워크를 통해 도착하지 않는 트래픽에 영향을 미치지 않아야합니다. 그래도 문법은 확실하지 않습니다. 아마도 eth0을 통해 도커 호스트에서 나가는 액세스가 활성화되었다고 말할 수 있습니다. 나는 당신이 필요로하는 것보다 더 많은 목표 규칙을 여는 것이 가능하다는 데 동의합니다.
mc0e
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.