Set di regole iptabili in modo che un contenitore docker possa accedere a un servizio su un IP host


18

Ho problemi ad accedere a un'interfaccia privata host (ip) da un contenitore docker. Sono abbastanza certo che sia legato alle mie regole di Iptables (o forse al routing). Quando aggiungo la --net=hostbandiera a docker run, tutto funziona come previsto. Allo stesso modo, quando specifico che la politica INPUT segue un modello liberale -P INPUT ACCEPT, anche le cose funzionano come mi aspetterei. Tuttavia, queste sono opzioni indesiderabili e non sicure che vorrei evitare.

Dal momento che non è specifico per i miei servizi (DNS) l'ho escluso dal problema, dal momento che la ricerca in combinazione con la finestra mobile produce in una diversa area (popolare) del problema, aggiungendo rumore ai risultati della ricerca.

Anche il collegamento dei contenitori Docker non è un'opzione praticabile, poiché alcuni contenitori devono essere eseguiti con l'opzione --net = host, impedendo il collegamento e voglio creare una situazione coerente, ove possibile.

Ho le seguenti regole di Iptables. Presumo una combinazione di CoreOS, Digital Ocean e 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

Le mie interfacce host (pertinenti):

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

E corro un container docker:

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

A questo punto voglio essere in grado di utilizzare un servizio locale, associato a 10.129.112.210:53. In modo che quanto segue possa dare una risposta:

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

Quando eseguo lo stesso comando dal mio host:

$ 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

Il mio 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

Il punto qui non è quello di accedere agli host pubblici, ma piuttosto a quelli interni, utilizzando il servizio DNS locale disponibile sull'host (tramite un'altra istanza docker).

Per illustrarlo ulteriormente (Le mie capacità di progettazione artistica ascii superano il mio fu di iptables, quindi a questo punto dovrei dire abbastanza):

 ______________________________________________
|  __________________________           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)

Ho cercato, letto e applicato diverse configurazioni di Iptables di esempio, ma conosco troppo poco delle regole Iptables più "avanzate" per capire cosa sta succedendo e quindi ottenere il risultato desiderato.

Uscita di 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

Uscita di cat /proc/sys/net/ipv4/ip_forward:

1

Puoi pubblicare l'output di iptables -t nat -nL? Hai fatto qualche analisi di pacchetto, diciamo di fare un ping dal contenitore di origine e hai usato tcpdump per catturare i pacchetti sull'host.
Daniel t.

Certamente, grazie per l'aiuto finora: pastebin.com/TAaT73nk (Non si adattava al commento ..) - modifica -> Aggiornato il link a un pastebin che non scade.
Dynom,

Forse non ho capito correttamente il tuo problema, ma non vedo alcuna regola per consentire le query DNS sull'host. Inoltre, ip_forward è abilitato?
Laurentiu Roescu,

Ciao @LaurentiuRoescu. $ cat /proc/sys/net/ipv4/ip_forward -> 1e -A INPUT -i eth1 -j ACCEPTaccetta tutte le connessioni sull'interfaccia privata . Quali regole manchi?
Dynom,

2
Penso che i pacchetti dal contenitore provengano dall'interfaccia docker0, non da eth1. provare-A INPUT -i docker0 -j ACCEPT
Laurentiu Roescu il

Risposte:


14

Il contenitore comunica con l'host utilizzando l' docker0interfaccia. Per consentire il traffico dal contenitore aggiungere:

-A INPUT -i docker0 -j ACCEPT

2
Dynom, una lezione che potresti voler trarre da questo è che è utile registrare tutti i tuoi rifiuti, ad es iptables -A INPUT -j LOG. Il francobollo IN=docker0sarebbe stato molto utile per capire quale modifica della regola fosse necessaria. Non togliermi dal lavoro di Laurentiu, che è stato eccellente - +1 da me!
MadHatter supporta Monica il

5
Per le persone che usano UFW, ecco cosa ho fatto per consentire a tutte le comunicazioni dai container Docker di ospitare: ufw consentire l'accesso su docker0
Ali Ok

0

Ho riscontrato una situazione molto simile, ma l'aggiunta -A INPUT -i docker0 -j ACCEPTaprirà tutti gli accessi attraverso la mia interfaccia eth0 dell'host docker a contenitori che non è assolutamente quello che intendevo.

E poiché ho notato che il mio contenitore aveva un accesso limitato (diciamo solo la porta 22) all'interfaccia host invece di chiudere completamente dalla rete host, ho rivisto le mie regole iptables e ho trovato una regola nella catena IN_public_allow che dovrebbe essere responsabile di questo. La regola è -A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT. Quindi ho aggiunto regole simili per consentire al mio container di accedere ad altre porte host desiderate, che penso potrebbe essere un modo un po 'più preciso per aprire l'accesso alla rete host ai container.


-i docker0dovrebbe garantire che ciò non influisca sul traffico che non arriva attraverso la rete docker0. Tuttavia, la tua grammatica non è chiara. Forse stavi dicendo che l'accesso in uscita dagli host docker tramite eth0 era abilitato, il che potrebbe essere vero. Concordo sul fatto che è possibile aprire regole più mirate solo quanto necessario.
mc0e
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.