Docker
Iptables con Docker
Ricerca…
introduzione
Questo argomento riguarda come limitare l'accesso ai contenitori docker dal mondo esterno usando iptables.
Per le persone impazienti, puoi controllare gli esempi. Per gli altri, leggi la sezione delle note per capire come creare nuove regole.
Sintassi
- iptables -I DOCKER [RULE ...] [ACCEPT | DROP] // Per aggiungere una regola alla parte superiore della tabella DOCKER
- iptables -D DOCKER [RULE ...] [ACCEPT | DROP] // Per rimuovere una regola dalla tabella DOCKER
- ripristino ipset </etc/ipfriends.conf // Per riconfigurare i propri IPs ipset
Parametri
parametri | Dettagli |
---|---|
ext_if | La tua interfaccia esterna sull'host Docker. |
XXX.XXX.XXX.XXX | Un particolare IP su cui deve essere fornito l'accesso ai contenitori Docker. |
yyy.yyy.yyy.yyy | Un altro IP su cui devono essere forniti i contenitori Docker. |
ipfriends | Il nome ipset che definisce gli IP autorizzati ad accedere ai contenitori Docker. |
Osservazioni
Il problema
La configurazione delle regole di iptables per i contenitori Docker è un po 'complicata. All'inizio, penseresti che le regole del firewall "classiche" dovrebbero fare il trucco.
Ad esempio, supponiamo di aver configurato un contenitore proxy nginx + diversi contenitori di servizi per esporre via HTTPS alcuni servizi web personali. Quindi una regola come questa dovrebbe consentire l'accesso ai tuoi servizi Web solo per IP XXX.XXX.XXX.XXX.
$ iptables -A INPUT -i eth0 -p tcp -s XXX.XXX.XXX.XXX -j ACCEPT
$ iptables -P INPUT DROP
Non funzionerà, i tuoi contenitori sono ancora accessibili a tutti.
Infatti, i container Docker non sono servizi host. Si basano su una rete virtuale nel tuo host e l'host funge da gateway per questa rete. E per quanto riguarda i gateway, il traffico indirizzato non viene gestito dalla tabella INPUT, ma dalla tabella FORWARD, che rende la regola postata prima inefficace.
Ma non è tutto. Infatti, il demone Docker crea molte regole di iptables quando inizia a fare la sua magia riguardo alla connettività di rete dei container. In particolare, viene creata una tabella DOCKER per gestire le regole relative ai contenitori inoltrando il traffico dalla tabella FORWARD a questa nuova tabella.
$ iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy DROP)
target prot opt source destination
DOCKER-ISOLATION all -- anywhere anywhere
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain DOCKER (2 references)
target prot opt source destination
ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:https
ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:http
Chain DOCKER-ISOLATION (1 references)
target prot opt source destination
DROP all -- anywhere anywhere
DROP all -- anywhere anywhere
RETURN all -- anywhere anywhere
La soluzione
Se si controlla la documentazione ufficiale ( https://docs.docker.com/v1.5/articles/networking/) , viene fornita una prima soluzione per limitare l'accesso al contenitore Docker a un particolare IP.
$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP
In effetti, aggiungere una regola nella parte superiore della tabella DOCKER è una buona idea. Non interferisce con le regole configurate automaticamente da Docker ed è semplice. Ma due grandi mancanze:
- Innanzitutto, cosa succede se è necessario accedere da due IP anziché uno? Qui può essere accettato solo un IP src, altri verranno eliminati senza alcun modo per impedirlo.
- In secondo luogo, cosa succede se la finestra mobile ha bisogno di accedere a Internet? Praticamente nessuna richiesta avrà successo, in quanto solo il server 8.8.8.8 potrebbe rispondere ad essi.
- Infine, cosa succede se si desidera aggiungere altre logiche? Ad esempio, concedere l'accesso a qualsiasi utente al server web che serve sul protocollo HTTP, ma limitare tutto il resto a particolari IP.
Per la prima osservazione, possiamo usare ipset . Invece di consentire un IP nella regola sopra, consentiamo tutti gli IP dall'ipset predefinito. Come bonus, l'ipset può essere aggiornato senza la necessità di ridefinire la regola iptable.
$ iptables -I DOCKER -i ext_if -m set ! --match-set my-ipset src -j DROP
Per la seconda osservazione, si tratta di un problema canonico per i firewall: se si è autorizzati a contattare un server attraverso un firewall, il firewall dovrebbe autorizzare il server a rispondere alla richiesta. Questo può essere fatto autorizzando pacchetti che sono collegati ad una connessione stabilita. Per la logica docker, fornisce:
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
L'ultima osservazione si concentra su un punto: le regole di iptables sono essenziali. Infatti, la logica aggiuntiva per ACCETTARE alcune connessioni (inclusa quella relativa alle connessioni ESTABLISHED) deve essere posta nella parte superiore della tabella DOCKER, prima della regola DROP che nega tutte le connessioni rimanenti che non corrispondono all'ipset.
Poiché utilizziamo l'opzione -I di iptable, che inserisce le regole nella parte superiore della tabella, le precedenti regole di iptables devono essere inserite in ordine inverso:
// Drop rule for non matching IPs
$ iptables -I DOCKER -i ext_if -m set ! --match-set my-ipset src -j DROP
// Then Accept rules for established connections
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 3rd custom accept rule
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 2nd custom accept rule
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 1st custom accept rule
Tenendo tutto questo a mente, ora puoi controllare gli esempi che illustrano questa configurazione.
Limita l'accesso ai contenitori Docker a un set di IP
Innanzitutto, installa IPSET se necessario. Si prega di fare riferimento alla vostra distribuzione per sapere come farlo. Ad esempio, ecco il comando per le distribuzioni di tipo Debian.
$ apt-get update
$ apt-get install ipset
Quindi creare un file di configurazione per definire un IPS contenente gli IP per i quali si desidera aprire l'accesso ai contenitori Docker.
$ vi /etc/ipfriends.conf
# Recreate the ipset if needed, and flush all entries
create -exist ipfriends hash:ip family inet hashsize 1024 maxelem 65536
flush
# Give access to specific ips
add ipfriends XXX.XXX.XXX.XXX
add ipfriends YYY.YYY.YYY.YYY
Carica questo ipset.
$ ipset restore < /etc/ipfriends.conf
Assicurati che il tuo demone Docker sia in esecuzione: non dovrebbe essere mostrato alcun errore dopo aver inserito il seguente comando.
$ docker ps
Sei pronto per inserire le tue regole di iptables. È necessario rispettare l'ordine.
// All requests of src ips not matching the ones from ipset ipfriends will be dropped.
$ iptables -I DOCKER -i ext_if -m set ! --match-set ipfriends src -j DROP
// Except for requests coming from a connection already established.
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
Se vuoi creare nuove regole, dovrai rimuovere tutte le regole personalizzate che hai aggiunto prima di inserirne di nuove.
$ iptables -D DOCKER -i ext_if -m set ! --match-set ipfriends src -j DROP
$ iptables -D DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
Configurare l'accesso alla restrizione all'avvio del daemon Docker
Lavori in corso
Alcune regole personalizzate di iptables
Lavori in corso