saverioriotto.it

Utilizzo sicuro delle API di Docker

Le API Docker, per impostazione predefinita, non è completamente protetta ad eccezione dei permessi del filesystem sul suo socket Unix. Per aumentare la sicurezza potresti configurare il TLS sulle connessioni TCP al Docker Engine altrimenti chiunque abbia accesso alla porta TCP potrebbe sfogliare i tuoi container Docker, avviarne di nuovi ed eseguire azioni come root sul tuo sistema.

Utilizzo sicuro delle API di Docker

Configurare il TLS richiederà ai client di presentare un certificato valido firmato dall'autorità di certificazione del server. Per farlo funzionare, devi creare i certificati SSL, quindi configurare Docker Engine per richiedere connessioni TLS. Anche i client Docker CLI devono essere configurati per prevedere un server TLS.

Esporre il socket TCP

È possibile esporre il socket TCP di Docker utilizzando il flag -H per definire un endpoint all'avvio del processo Docker. Questo flag può essere ripetuto più volte; in questo esempio saranno disponibili sia il socket Unix che il socket TCP:

/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375

La porta 2375 viene convenzionalmente utilizzata per le connessioni Docker non crittografate. La porta 2376 dovrebbe essere utilizzata invece una volta impostato il TLS.

È possibile configurare Docker per l'utilizzo automatico di questi flag modificando la definizione del servizio Docker. Aggiungi un override in /etc/systemd/system/docker.service.d/override.conf che cambia la riga ExecStart:

[Service]
ExecStart=/usr/bin/dockerd -H ...

Ricarica systemd per applicare la modifica:

sudo systemctl daemon-reload

Creazione della tua autorità di certificazione

Inizia creando un'autorità di certificazione (CA) per la tua configurazione TLS. Utilizzerai questa CA per firmare i tuoi certificati; il server rifiuterà di comunicare con i client che presentano un certificato da una CA diversa.

Usa OpenSSL per generare chiavi CA private e pubbliche sulla macchina che ospita il tuo server Docker:

# Generazione della chiave privata
openssl genrsa -aes256 -out ca-private.pem 4096

# Generazione della chiave pubblica tramite la chiave privata
openssl req -new -x509 -days 365 -key ca-private.pem -sha256 -out ca-public.pem

Ti verrà chiesto di fornire una passphrase, un indirizzo e-mail, il prefisso internazionale, i nomi di stato e città e il nome dell'organizzazione da includere con la tua chiave pubblica. Inserisci le informazioni nel terminale, premendo invio dopo ogni riga per andare avanti e creare la chiave.

Generazione di una chiave server e di una richiesta di firma del certificato

Quindi crea una chiave del server e una richiesta di firma del certificato:

# Generazione della server key
openssl genrsa -out server-key.pem 4096

# Generazion di una richiesta di firma del certificato
openssl req -subj "/CN=example.com" -sha256 -new -key server-key.pm -out request.csr

La richiesta di firma del certificato (CSR) contiene tutte le informazioni necessarie per produrre un certificato firmato. È importante verificare che il nome comune nella CSR sia corretto per il tuo server. Questo è specificato nel campo CN come esempio.com sopra; dovresti impostarlo sul nome di dominio completo (FQDN) per il tuo server.

Configurazione delle estensioni dei certificati

L'utilizzo di questo CSR consentirebbe le connessioni al server tramite il suo FQDN. È necessario specificare le estensioni del certificato se si desidera aggiungere un altro dominio o utilizzare un indirizzo IP. Crea un file di estensioni con i campi subjectAltName e extendedKeyUsage per impostarlo:

Questo esempio consentirebbe inoltre connessioni tramite sub.example.com e 192.168.0.1 .

Ora sei pronto per combinare tutti i componenti e generare un certificato firmato:

openssl x509 -req -days 365 -sha256 \
    -in request.csr \
    -CA ca-public.pem \
    -CAkey ca-private.pem \
    -CAcreateserial \
    -extfile extfile.cnf \
    -out certificate.pem

Questo prende la richiesta di firma del certificato, aggiunge il tuo file di estensione e usa le chiavi della tua CA per produrre un certificato OpenSSL firmato. Dovrai fornire la passphrase della CA per completare il processo.

Questo certificato scadrà dopo un anno. Puoi settare il flag -days per ottenere una validità utile per le tue esigenze. Ricorda sempre che dovresti pianificare la generazione di un certificato sostitutivo prima della scadenza di quest'ultimo.

Generazione di un certificato client

Successivamente dovresti generare un altro certificato da utilizzare per i tuoi client Docker. Questo deve essere firmato dalla stessa CA del certificato del server. Utilizzare un file di estensioni con extendedKeyUsage = clientAuth per preparare questo certificato per l'uso in uno scenario client.

# Generazione della chiave clinet
openssl genrsa -out client-key.pem 4096

# Generazione di una richiesta di firma del certificato
openssl req -subj '/CN=client' -new -key client-key.pem -out client-request.csr

# Completamento della firma
echo extendedKeyUsage = clientAuth >> extfile-client.cnf
openssl x509 -req -days 365 -sha256 \
     -in client-request.csr \ 
     -CA ca-public.pem \
     -CAkey ca-private.pem \
     -CAcreateserial \
     -extfile extfile-client.cnf \
     -out client-certificate.pem

Preparazione alla configurazione di Docker

Copia i file ca-public.pem, certificate.pem e server-key.pem in una nuova directory pronta per fare riferimento nella tua configurazione Docker. Successivamente, copia i file ca-public.pem, client-certificate.pem e client-key.pem sulla macchina da cui ti connetterai.

È possibile eliminare la richiesta di firma del certificato e i file di estensione nella directory di lavoro. Fai attenzione a non perdere le tue chiavi private perché non sono recuperabili. Senza di essi non sarai in grado di convalidare certificati o generare rinnovi.

Configurazione del demone Docker

Ora puoi avviare il demone Docker con i flag TLS che fanno riferimento al certificato e alle chiavi generate. I parametri --tlscacert, --tlscert e --tlskey specificano i percorsi delle rispettive risorse OpenSSL generate sopra.

/usr/bin/dockerd \
    -H unix:///var/run/docker.sock \
    -H tcp://0.0.0.0:2376 \
    --tlsverify \
    --tlscacert=ca-public.pem \
    --tlscert=certificate.pem \
    --tlskey=server-key.pem

L'aggiunta del flag --tlsverify consente l'imposizione delle connessioni TLS. Ai client senza un certificato corrispondente verrà impedito di accedere al socket TCP di Docker.

Configurazione del client Docker

Attiva TLS sul client fornendo i flag TLS quando usi il comando docker. È inoltre necessario aggiungere il flag -H per specificare l'indirizzo del socket Docker remoto a cui connettersi. Dal punto di vista del client, --tlsverify significa che il comando si connetterà solo ai server con un certificato TLS firmato dalla stessa autorità di certificazione.

docker \
    -H tcp://0.0.0.0:2376 \
    --tlsverify \
    --tlscacert=ca-public.pem \
    --tlscert=client-certificate.pem \
    --tlskey=client-key.pem \
    ps

Fornire questi flag ogni volta che si utilizza la CLI diventa ripetitivo molto rapidamente. Se lavorerai principalmente con lo stesso host protetto da TLS, imposta le variabili di ambiente DOCKER_HOST e DOCKER_TLS_VERIFY nel tuo profilo shell. Copia i file dei certificati in ca, cert e key all'interno della tua directory ~/.docker. Questi corrispondono ai flag --tls di Docker e definiscono un certificato predefinito per il client.

export DOCKER_HOST=tcp://0.0.0.0:2376
export DOCKER_TLS_VERIFY=1

Puoi semplificare il lavoro con più host utilizzando una combinazione di connessioni locali, remote, non protette e TLS configurando contesti Docker. Questa funzione ti consente di passare da un target all'altro utilizzando i comandi Docker CLI.

Il client Docker supporta anche modalità di verifica alternative. L'utilizzo di una combinazione di flag tls, tlscacert, tlscert, tlskey e tlsverify attiva diversi livelli di imposizione TLS.

Con solo tls impostato, Docker autenticherà il server utilizzando il pool CA predefinito. L'aggiunta dei flag tlscacert e tlsverify senza una chiave client imporrà al server di utilizzare la CA specificata senza altri controlli. L'omissione di tlscacert e tlsverify ma l'inclusione delle altre tre chiavi verificherà il certificato del client senza autenticare la CA del server.

Conclusione

La protezione del socket TCP di Docker con i certificati TLS ti consente di esporre l'API in modo più sicuro impedendo connessioni da client non autorizzati. Agli attori che effettuano la scansione delle porte della tua rete verrà impedito di connettersi a Docker, offrendoti un livello di protezione che impedisce che la tua macchina venga compromessa con privilegi a livello di root.

Dopo aver generato i certificati, puoi utilizzarli per autenticarti con Docker CLI o con i tuoi client HTTP. Curl, ad esempio, li accetterà come flag --cert, --key e --cacert.

TLS è solo un componente di un'istanza dell'API Docker protetta. Fornisce la crittografia e garantisce che i client siano affidabili, ma non è un meccanismo di controllo dell'accesso granulare.

Se desideri limitare ciò che i singoli client possono fare, devi configurare un plug-in di autorizzazione Docker Engine. I plugin possono contattare un servizio esterno per determinare se una particolare richiesta API può procedere. In alternativa, puoi utilizzare un reverse proxy davanti al tuo socket TCP per imporre il controllo dell'accesso prima che le richieste raggiungano Docker.




Commenti
* Obbligatorio