iptables가있는 docker container에 대한 외부 연결을 제한하는 단계는 무엇입니까?


20

내 목표는 도커 컨테이너에 대한 액세스를 몇 개의 공개 IP 주소로 제한하는 것입니다. 목표를 달성하기위한 간단하고 반복 가능한 프로세스가 있습니까? Docker의 기본 옵션을 사용하는 동안 iptables의 기본 사항 만 이해하면 매우 어렵습니다.

컨테이너를 실행하고 공용 인터넷에 표시하도록하고 싶지만 일부 호스트의 연결 만 허용하고 싶습니다. 기본 입력 정책을 REJECT로 설정 한 다음 호스트의 연결 만 허용합니다. 그러나 Docker의 NAT 규칙과 체인이 방해를 받고 내 입력 규칙이 무시됩니다.

다음 가정을 통해 내 목표를 달성하는 방법의 예를 누군가가 제시 할 수 있습니까?

  • eth0에서 공개 IP 80.80.80.80 호스트
  • eth1에서 호스트 개인 IP 192.168.1.10
  • docker run -d -p 3306:3306 mysql
  • 호스트 4.4.4.4 및 8.8.8.8을 제외하고 호스트 / 컨테이너 3306에 대한 모든 연결을 차단하십시오.

컨테이너를 로컬 IP 주소에만 바인딩하는 것이 행복하지만 도커 프로세스 및 호스트 다시 시작에서 살아남은 iptables 전달 규칙을 올바르게 설정하는 방법에 대한 지침이 필요합니다.

감사!

답변:


15

도커의 방화벽 규칙으로 작업 할 때 명심해야 할 두 가지 :

  1. 도 커가 규칙을 어지럽히 지 않게하려면 DOCKER-USER체인을 사용하십시오.
  2. Docker는 테이블 PREROUTING체인 에서 포트 매핑 을 수행 nat합니다. 이것은 전에 일어나는 filter규칙, 그래서 --dest--dport용기의 내부 IP와 포트를 볼 수 있습니다. 원래 목적지에 액세스하려면을 사용할 수 있습니다 -m conntrack --ctorigdstport.

예를 들면 다음과 같습니다.

iptables -A DOCKER-USER -i eth0 -s 8.8.8.8 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP

참고 :이 없으면 --ctdir ORIGINAL컨테이너에서 다른 서버의 포트 3306으로 다시 연결되는 응답 패킷과 일치합니다.이 패킷은 거의 확실하지 않습니다! 나와 같은 첫 번째 규칙은 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT모든 응답 패킷을 처리하므로 엄격하게 필요하지는 않지만 여전히 사용하는 것이 더 안전 --ctdir ORIGINAL합니다.


? 를 포함 하도록 편집해야합니까 --ctdir? 나는 사용한다-m conntrack --ctstate NEW --ctorigdstport 3306 --ctdir ORIGINAL
lonix

@Ionix, 그래야하지만 왜 혼란 스럽습니까? 약간의 설명을 추가했습니다.
SystemParadox

1
기본 DOCKER-USER테이블에는 항목이 포함되어 있습니다.이 항목은를 -A DOCKER-USER -j RETURN사용하는 경우 위 의 항목 보다 먼저 실행됩니다 -A. 해결책은 머리에 규칙을와 반대 순서로 삽입하는 것입니다 -I.
BMitch

@BMitch 또는 더 나은 아직 , 새로운 FILTERS체인 에 모든 규칙을 추가하고 -I말한대로 새 규칙을 삽입하여 다음 -I INPUT -j FILTERS과 같이 하십시오.-I DOCKER-USER -i eth0 -j FILTERS
lonix

@BMitch 그러나 방금 서버를 확인했는데 반환 규칙이 없으며 최신 도커 버전이 더 이상 삽입하지 않습니까? -I안전을 위해 사용하는 것이 좋습니다 .
lonix

8

Docker v.17.06에는 DOCKER-USER라는 새로운 iptables 체인이 있습니다. https://docs.docker.com/network/iptables/ 사용자 지정 규칙에 대한 것입니다.

체인 DOCKER와 달리 컨테이너 빌드 / 시작시 재설정되지 않습니다. 따라서 docker를 설치하고 컨테이너를 시작하기 전에 서버를 프로비저닝하기 위해 iptables 구성 / 스크립트에 다음 행을 추가 할 수 있습니다.

-N DOCKER
-N DOCKER-ISOLATION
-N DOCKER-USER
-A DOCKER-ISOLATION -j RETURN
-A DOCKER-USER -i eth0 -p tcp -m tcp --dport 3306 -j DROP
-A DOCKER-USER -j RETURN

이제 MySQL의 포트는 외부 액세스 (eth0)에서 차단되어도 커가 세계의 포트를 엽니 다. (이 규칙은 외부 인터페이스가 eth0이라고 가정합니다.)

결국, iptables를 정리해야 Docker 서비스를 다시 시작해야합니다.


이 DOCKER-USER 테이블이 다른 사용자 추가 테이블과 다른 이유를 그리워합니다. 필터가 사전에 적용되지 않았으므로 여전히 인터페이스 이름을 직접 지정해야합니다. "MY-CHAIN"을 작성하고 FORWARD 체인에 삽입하면 동일한 결과가 나타납니다.
ColinM

Docker가 DOCKER-USER 체인을 FORWARD 체인에 삽입하기 때문에 차이가 있습니다. 그렇기 때문에 -A FORWARD -j DOCKER-USER -A FORWARD -j DOCKER-ISOLATION DOCKER 체인 전에 사용자 지정 명령이 실행됩니다.
ck1

--dportDOCKER-USER 내부에서 사용하는 경우 노출 된 포트가 아니라 컨테이너 서비스 의 내부 IP 와 일치해야합니다 . 이것들은 종종 일치하지만 항상 그런 것은 아니며 다른 서비스와 쉽게 충돌 할 수 있으므로 여전히이 DOCKER-USER 솔루션이 반 구운 것이라고 주장합니다.
ColinM

4

업데이트 : 2015 년에 유효했지만이 솔루션은 더 이상 올바른 방법이 아닙니다.

대답은 https://docs.docker.com/articles/networking/#the-world 의 Docker 설명서에있는 것 같습니다.

Docker의 전달 규칙은 기본적으로 모든 외부 소스 IP를 허용합니다. 특정 IP 또는 네트워크 만 컨테이너에 액세스 할 수있게하려면 DOCKER 필터 체인 상단에 부정 규칙을 삽입하십시오. 예를 들어 소스 IP 8.8.8.8 만 컨테이너에 액세스 할 수 있도록 외부 액세스를 제한하려면 다음 규칙을 추가 할 수 있습니다.iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

내가 한 일은 다음과 같습니다.

iptables -I DOCKER -i eth0 -s 8.8.8.8 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER -i eth0 -s 4.4.4.4 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER 3 -i eth0 -p tcp --dport 3306 -j DROP

--iptables또는 --icc옵션을 터치하지 않았습니다 .


1
그렇게 iptables -vnL DOCKER하면 대상 포트는 컨테이너 내의 모든 포트입니다. 내가 그 권리를 얻는다면, 위의 규칙 3306은 컨테이너 내의 포트에만 영향을 미칩니다. 즉 , 컨테이너에있는 경우 -p 12345:3306규칙은 여전히 액세스를 잠그는 데 필요한 규칙입니다 (즉 --dport 12345작동하지 않음) DOCKER 체인의 ACCEPT 규칙이 NAT 이후이기 때문입니다.
sunside

맞습니다. 규칙은 컨테이너 내의 포트와 관련이 있어야합니다.
GGGforce

1
내부 프록시 NGINX를 사용하여 리버스 프록 싱 (예 : Zabbix, 커스텀로드 밸런서 등)을 사용하는 컨테이너를 여러 개 실행하면 컨테이너의 IP를 미리 알아야하기 때문에 우스운 일입니다. 나는 여전히 필요하지 않은 문제에 대한 해결책을 찾고 있습니다 --iptables=false. 왜냐하면 이것이 모두 최악의 선택 인 것 같습니다.
sunside

감사합니다! 여러 시간 동안 검색 한 후 내 문제를 해결했습니다. 이제 마침내 전 세계에 소프트를 노출시키지 않고 MySQL을 내 집의 IP 주소로 감금 할 수있게되었습니다.
Matt Cavanagh

1
DOCKER 체인은 사용자가 직접 조작하지 않아야합니다! 이를 위해 DOCKER-USER 체인을 사용하십시오. 허용 된 답변을 확인하십시오.
Paul-Sebastian Manole

3

업데이트 : 이 답변은 여전히 ​​유효하지만 @SystemParadox의 답변 DOCKER-USER과 함께 사용 하는 --ctorigdstport것이 좋습니다.

다음은 재시작 사이에 잘 ​​유지 되고 내부 포트가 아닌 노출 된 포트 에 영향을 줄 수있는 솔루션입니다 .

iptables -t mangle -N DOCKER-mysql iptables -t mangle -A DOCKER-mysql -s 22.33.44.144/32 -j RETURN iptables -t mangle -A DOCKER-mysql -s 22.33.44.233/32 -j RETURN iptables -t mangle -A DOCKER-mysql -j DROP iptables -t mangle -A PREROUTING -i eth0 -p tcp -m tcp --dport 3306 -j DOCKER-mysql

이 방법을 사용하여 환경 변수를 사용하거나 etcd를 사용하여 동적으로 iptables를 자동으로 관리하는 Docker 이미지를 만들었습니다.

https://hub.docker.com/r/colinmollenhour/confd-firewall/

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.