Etapas para limitar conexões externas ao contêiner docker com iptables?

Meu objetivo é limitar o acesso aos contêineres do docker a apenas alguns endereços IP públicos. Existe um processo simples e repetível para atingir meu objetivo? Entendendo apenas o básico do iptables ao usar as opções padrão do Docker, estou achando muito difícil.

Eu gostaria de executar um contêiner, torná-lo visível para a Internet pública, mas apenas permitir conexões de hosts selecionados. Eu esperaria definir uma política de entrada padrão de REJECT e, em seguida, permitir apenas conexões de meus hosts. Mas as regras e cadeias NAT do Docker atrapalham e minhas regras de entrada são ignoradas.

Alguém pode fornecer um exemplo de como realizar meu objetivo, dadas as seguintes suposições?

  • IP público do Host 80.80.80.80 no eth0
  • IP privado do Host 192.168.1.10 no eth1
  • docker run -d -p 3306:3306 mysql
  • Bloqueie toda a conexão com o host / container 3306, exceto dos hosts 4.4.4.4 e 8.8.8.8

Estou feliz em vincular o contêiner apenas ao endereço ip local, mas precisaria de instruções sobre como configurar as regras de encaminhamento iptables corretamente, que sobrevivem ao processo do docker e ao reinício do host.

Obrigado!

Duas coisas a ter em mente ao trabalhar com as regras de firewall do docker:

  1. Para evitar que suas regras sejam clobbered pelo docker, use o DOCKER-USER cadeia
  2. O Docker faz o mapeamento de porta no PREROUTING cadeia do nat tabela. Isso acontece antes do filter regras, então --dest e --dport verá o IP interno e a porta do contêiner. Para acessar o destino original, você pode usar -m conntrack --ctorigdstport.

Por exemplo:

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

Nota: sem --ctdir ORIGINAL, isso também corresponderia aos pacotes de resposta voltando para uma conexão do contêiner à porta 3306 em algum outro servidor, o que quase certamente não é o que você deseja! Você não precisa estritamente disso se como Eu sua primeira regra é -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT, como isso vai lidar com todos os pacotes de resposta, mas seria mais seguro ainda usar --ctdir ORIGINAL assim.

Com o Docker v. 17. 06, há uma nova cadeia iptables chamada DOCKER-USER. Este é para suas regras personalizadas: https://docs.docker.com/network/iptables/

Ao contrário do DOCKER chain, ele não é redefinido na construção/inicialização de contêineres. Portanto, você pode adicionar essas linhas à configuração/script iptables para provisionar o servidor antes mesmo de instalar o docker e iniciar os contêineres:

-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

Agora, a porta do MySQL está bloqueada do acesso externo (eth0), mesmo que o docker tenha aberto a porta para o mundo. (Essas regras assumem que sua interface externa é eth0.)

Eventualmente, você terá que limpar o iptables reinicie o serviço docker primeiro, se você bagunçou demais tentando bloquear a porta como eu fiz.

ACTUALIZACAO: Embora esta resposta ainda seja válida, a resposta de @ SystemParadox usando DOCKER-USER em combinação com --ctorigdstport é melhor.

Aqui está uma solução que persiste bem entre reinicializações e permite que você afete o exposto Porto em vez do interno porta.

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

Eu construí uma imagem do Docker que usa esse método para gerenciar automaticamente os iptables para você, usando variáveis de ambiente ou dinamicamente com etcd (ou ambos):

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

ACTUALIZACAO: Embora válida em 2015, esta solução não é mais a maneira certa de fazê-lo.

A resposta parece estar na documentação do Docker em https://docs.docker.com/articles/networking/#the-world

As regras de encaminhamento do Docker permitem Todos os IPs de origem externa por padrão. Para permitir que apenas um IP ou rede específica acesse os contêineres, insira uma regra negada na parte superior da cadeia de filtros do DOCKER. Por exemplo, para restringir o acesso externo de modo que apenas o IP de origem 8.8.8.8 possa acessar os contêineres, a seguinte regra pode ser adicionada: iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

O que acabei fazendo foi:

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

Eu não toquei no --iptables ou --icc Opcao.