Meu objetivo é limitar o acesso aos contêineres 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 enquanto uso 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 permitir apenas conexões de hosts selecionados. Eu esperaria definir uma política INPUT padrão de REJECT e permitir apenas conexões de meus hosts. Mas as regras e cadeias NAT do Docker atrapalham e minhas regras INPUT são ignoradas.
Alguém pode fornecer um exemplo de como atingir meu objetivo, considerando as seguintes suposições?
- Hospede o IP público 80.80.80.80 na eth0
- Hospede IP privado 192.168.1.10 em eth1
docker run -d -p 3306:3306 mysql
- Bloquear todas as conexões com o host/container 3306, exceto dos hosts 4.4.4.4 e 8.8.8.8
Fico feliz em vincular o contêiner apenas ao endereço IP local, mas precisaria de instruções sobre como configurar as regras de encaminhamento do iptables adequadamente, que sobrevivem ao processo do docker e às reinicializações do host.
Obrigado!
Duas coisas a ter em mente ao trabalhar com as regras de firewall do docker:
DOCKER-USER
cadeiaPREROUTING
cadeia danat
tabela. Isso acontece antes dasfilter
regras, então--dest
e--dport
vai ver o IP interno e a porta do container. Para acessar o destino original, você pode usar-m conntrack --ctorigdstport
.Por exemplo:
NOTA: Sem
--ctdir ORIGINAL
, isso também corresponderia aos pacotes de resposta voltando para uma conexão do contêiner para a 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 for-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
, pois isso lidará com todos os pacotes de resposta, mas seria mais seguro usar de--ctdir ORIGINAL
qualquer maneira.Com o Docker v.17.06, há uma nova cadeia de iptables chamada DOCKER-USER. Este é para suas regras personalizadas: https://docs.docker.com/network/iptables/
Ao contrário da cadeia DOCKER, ele não é redefinido na construção/início de contêineres. Portanto, você pode adicionar essas linhas ao seu iptables config/script para provisionar o servidor antes mesmo de instalar o docker e iniciar os contêineres:
Agora a porta do MySQL está bloqueada para acesso externo (eth0), mesmo que o docker abra a porta para o mundo. (Essas regras assumem que sua interface externa é eth0.)
Eventualmente, você terá que limpar o iptables, reiniciar o serviço docker primeiro, se você estragou muito tentando bloquear a porta como eu fiz.
ATUALIZAÇÃO : Embora válida em 2015, esta solução não é mais a maneira correta de fazê-lo.
A resposta parece estar na documentação do Docker em https://docs.docker.com/articles/networking/#the-world
O que acabei fazendo foi:
Não toquei nas opções
--iptables
ou--icc
.ATUALIZAÇÃO: 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 as reinicializações e permite que você afete a porta exposta em vez da porta interna .
Criei uma imagem do Docker que usa esse método para gerenciar automaticamente o iptables para você, usando variáveis de ambiente ou dinamicamente com etcd (ou ambos):
https://hub.docker.com/r/colinmollenhour/confd-firewall/
Com base na excelente resposta aceita por @SystemParadox, eu queria impedir todo o tráfego (TCP e UDP) de todos os hosts externos para as portas publicadas de todos os contêineres em execução, pois farei proxy reverso para as portas do contêiner que realmente desejo acesso por fora.
A regra que funcionou para mim para conseguir isso:
Isso insere a regra no topo da
DOCKER-USER
cadeia. Ajuste de acordo com o(s) nome(s) real(is) de sua(s) interface(s) de rede externa(s) ou as posições desejadas na cadeia (com-I DOCKER-USER <number>
).O
conntrack
módulo withctdir
parece ser importante aqui, pois tive alguns problemas comdocker-compose
d containers perdendo acesso ao mundo externo com variantes que tentei sem eles. Por exemplo:iptables -I DOCKER-USER -i eth0 ! -s 127.0.0.1 -j DROP
, sugerido por Jeff Geerling em uma postagem de blog de 2020, ele próprio proveniente dos documentos oficiais , impediu que meus contêineres se comunicassem com IPs externos.