Puoi eseguire Docker in produzione per mesi senza problemi visibili. I contenitori si avviano, le app rispondono, non si rompe nulla. Quindi una porta esposta o un’autorizzazione configurata in modo errato creano un punto d’appoggio che un utente malintenzionato non ha dovuto guadagnarsi. La maggior parte degli errori di sicurezza di Docker non sembrano errori finché qualcosa non va storto.
Questo articolo tratta le configurazioni specifiche che mettono a rischio gli ambienti container, ciò che ciascuno di essi consente a un utente malintenzionato e si chiude con un elenco di controllo che puoi eseguire oggi stesso contro la tua configurazione.
Perché la sicurezza Docker è più difficile di quanto sembri
I contenitori sembrano isolati. Ne avvii uno, esegue il proprio spazio di processo e al suo interno il contenitore successivo non esiste. Ottieni l’isolamento, ma è solo parziale. I contenitori condividono il kernel dell’host, il che significa che un processo all’interno di un contenitore può, in condizioni specifiche, raggiungere interamente il sistema host.
Le navi Docker sono configurate per comodità degli sviluppatori, non per il rafforzamento della produzione. Accesso root attivo. Tutte le porte sono associabili a tutte le interfacce. Nessun monitoraggio del tempo di esecuzione. La maggior parte degli sviluppatori accetta tali impostazioni, spedisce il contenitore e va avanti. Questo è un approccio ragionevole per iniziare; non è una posizione di sicurezza completa.
Secondo Rapporto sulla sicurezza di Red Hat 2024 sullo stato di Kubernetes, il 67% delle organizzazioni ha ritardato o rallentato la distribuzione delle applicazioni a causa di problemi di sicurezza dei container o di Kubernetes. Questo attrito di solito non deriva dagli attacchi. Proviene dai team che scoprono che le configurazioni dei loro container necessitavano di un rafforzamento che non avevano integrato.
Spesso vediamo contenitori in esecuzione in produzione con la stessa configurazione che avevano sul computer locale di uno sviluppatore. È qui che gli errori di sicurezza di Docker tendono a aggravarsi silenziosamente, senza sintomi visibili finché qualcosa non viene controllato o fallisce.
Gli errori che creano queste lacune sono specifici, prevedibili e per lo più evitabili, a partire dal livello di configurazione.
Errori comuni di configurazione Docker
La maggior parte delle violazioni dei container non inizia con un exploit zero-day. Iniziano con una configurazione impostata il primo giorno, senza pensare troppo all'esposizione della rete o all'ambito dei privilegi.
Le impostazioni predefinite di Docker sono progettate per funzionare. Il divario tra funzionalità e sicurezza è il punto in cui si accumulano i rischi per la sicurezza dei contenitori Docker, soprattutto nelle configurazioni self-hosted che vengono distribuite e mai rivisitate.
Vediamo spesso questo modello: contenitori su server con IP pubblico con collegamenti di porta, impostazioni utente e configurazioni di rete esattamente come erano al momento della distribuzione iniziale.
Esecuzione dei contenitori come root
Quando avvii un contenitore Docker senza specificare un utente, viene eseguito come root. Ciò significa che qualsiasi processo all'interno del contenitore, inclusa la tua applicazione, dispone di privilegi a livello di root all'interno dello spazio dei nomi del contenitore.

Il root all'interno di un contenitore non è la stessa cosa del root sull'host, ma la separazione non è assoluta. Gli exploit di escalation dei privilegi mirati al runtime, come il ben documentato runc CVE-2019-5736 e simili difetti di runtime, spesso richiedono un processo di contenitore root per avere successo.
I contenitori non root rimuovono il requisito del processo root da cui dipendono tali exploit, restringendo significativamente la superficie di attacco per quella classe di vulnerabilità, sebbene non eliminino completamente il rischio di fuga dal contenitore.
L'aggiunta di una direttiva USER al tuo Dockerfile risolve questo problema. Alcune immagini ufficiali vengono fornite con un utente non privilegiato che puoi attivare con una direttiva USER, ma molte sono ancora root senza un utente dell'app già pronto. In questi casi, crei l'utente nel Dockerfile prima di passare ad esso. Per la maggior parte delle configurazioni self-hosted, questa singola modifica rimuove un'intera categoria di rischio di escalation.
Esporre troppe porte all'Internet pubblica
Quando pubblichi una porta con Docker, Docker scrive direttamente le proprie regole iptables. Tali regole vengono eseguite prima delle regole del firewall a livello di host. Questo è un comportamento noto segnalato dalla comunità E documentato nella guida al filtraggio dei pacchetti di Docker, non si tratta di un errore di configurazione, e significa che UFW e strumenti simili non bloccano ciò che Docker ha già aperto.

Docker scrive direttamente su iptables, ignorando le impostazioni predefinite di UFW e firewalld su molti host Linux. Ciò significa che una porta associata a 0.0.0.0 può essere raggiungibile pubblicamente anche quando il firewall appare configurato. I gruppi di sicurezza cloud e le regole della catena DOCKER-USER possono comunque bloccare tale traffico, quindi l'esposizione effettiva dipende dalla configurazione di rete specifica.
Associa i servizi a 127.0.0.1 ove possibile, instrada il traffico pubblico attraverso un proxy inverso e pubblica solo ciò che richiede realmente l'accesso esterno. Un proxy inverso è il modo più affidabile per controllare ciò che viene esposto dall'esterno dell'host.
Ignorare l'isolamento della rete tra i contenitori
Qualsiasi contenitore su quella rete può raggiungere qualsiasi altro contenitore su di essa senza restrizioni. Il bridge predefinito non applica alcun filtraggio del traffico tra i contenitori che lo condividono e la maggior parte delle configurazioni non modifica mai tale configurazione.

Se un contenitore viene compromesso, quella comunicazione aperta diventa un percorso di movimento laterale. Un contenitore frontend può raggiungere un database, un'API interna o qualsiasi altra cosa sulla stessa rete bridge predefinita, anche quando tale accesso non è mai stato previsto.
Le reti definite dall'utente ti danno il controllo esplicito su quali contenitori possono comunicare, ma un'unica rete personalizzata condivisa da tutti i tuoi servizi consente comunque il traffico gratuito tra contenitori. Il vero isolamento richiede l’inserimento di servizi che non dovrebbero comunicare tra loro su reti separate. La disattivazione del ponte predefinito è il punto di partenza, non il traguardo.
Affacciato sul socket Docker
Il socket Docker in /var/run/docker.sock è l'interfaccia di controllo per l'intero motore Docker. Il montaggio in un contenitore fornisce a quel contenitore l'accesso API diretto al demone in esecuzione sull'host.

Con tale accesso, un contenitore può avviare nuovi contenitori, montare directory host, ispezionare e modificare contenitori in esecuzione e controllare efficacemente la macchina host. La superficie di attacco equivale al root sull'host, motivo per cui qualsiasi strumento che richiede l'accesso al socket merita un'attenta valutazione.
Per la maggior parte dei casi d'uso, esistono alternative più sicure: API con ambito o Strumenti di gestione Docker che non richiedono l'accesso al socket. Docker-in-Docker comporta compromessi operativi e di sicurezza propri e non è un sostituto semplice.
Gli errori di configurazione creano l'esposizione iniziale. Le scelte di immagine e dipendenza determinano il modo in cui l'esposizione si aggrava nel tempo.
Errori di immagini e segreti che sopravvivono al contenitore
Quando si ferma un contenitore, gli errori di configurazione al suo interno si fermano con esso. Quando si ricostruisce da un'immagine che presenta una vulnerabilità o una credenziale hardcoded, il problema si riavvia con il contenitore. Gli errori a livello di immagine non vengono ripristinati tra le distribuzioni.
Viaggiano con l'immagine in ogni ambiente che la estrae, in ogni registro che la archivia e in ogni membro del team che la esegue. Questa persistenza rende la gestione delle immagini e dei segreti una categoria di rischio distinta, che vale la pena controllare separatamente dalla configurazione.
Vediamo spesso questo schema: un’immagine scelta con cura all’inizio del progetto e mai più ricostruita da allora, che si allontana lentamente dalla linea di base di sicurezza che rappresentava inizialmente.
Utilizzo di immagini non attendibili o obsolete
I registri pubblici sono aperti a chiunque. Immagini dannose sono state distribuite tramite Docker Hub trasportando crypto-miner e backdoor incorporati nella cronologia dei livelli che persistono anche dopo il riavvio del contenitore. Verifica prima di ritirare le questioni, in particolare per le immagini di editori non ufficiali o sconosciuti.

Il problema separato è la stantio. Un'immagine ufficiale scattata sei mesi fa e mai ricostruita da allora ha accumulato vulnerabilità Docker senza patch con ogni CVE divulgato sui suoi pacchetti. L'immagine non è rotta. Semplicemente non è più attuale.
Rapporto Sonatype sullo stato della catena di fornitura del software 2024 ha scoperto che nel 95% dei casi un componente vulnerabile viene utilizzato, è già disponibile una versione corretta e l'80% delle dipendenze delle applicazioni rimane non aggiornato per oltre un anno. Questo modello è rilevante anche per le immagini di base Docker, poiché si basano sugli stessi pacchetti open source.
Utilizza immagini ufficiali di editori verificati e aggiungi tag di versione specifici anziché fare affidamento su "più recente". Crea una cadenza di ricostruzione regolare per mantenere aggiornate le tue immagini.
Segreti hardcoding nei file Dockerfile e nei file Compose
Le credenziali scritte in un'istruzione Dockerfile ENV o ARG, codificate in un blocco dell'ambiente Compose, passate come argomenti di compilazione o archiviate in un file .env impegnato nel controllo della versione non scompaiono quando si arresta il contenitore. Rimangono nella cronologia del livello immagine o nel controllo del codice sorgente, accessibili a chiunque possa raggiungerli.

Questo è uno degli errori di sicurezza Docker più trascurati perché non causa problemi visibili durante lo sviluppo. Una chiave API in un'istruzione ENV funziona correttamente. È anche nel tuo repository, integrato nella tua immagine e distribuito ovunque viaggi l'immagine.
Modern Docker Compose supporta un meccanismo di segreti nativi che monta le credenziali in fase di esecuzione senza inserirle nell'immagine. L'API dei segreti di Docker e i gestori dei segreti esterni seguono lo stesso principio. Queste sono le opzioni che mantengono le credenziali completamente fuori dagli artefatti di build e dai file sottoposti a commit.
Le variabili di ambiente di runtime rappresentano un miglioramento rispetto alle credenziali hardcoded, ma sono comunque esposte tramite l'output, i log e i dump di arresto anomalo di Docker Inspect. Sono un passo avanti rispetto ai segreti nascosti, non una soluzione finita.
Mancato aggiornamento regolare delle immagini del contenitore
Gestire la stessa immagine per mesi è un'abitudine comune. Ogni giorno che passa dopo la scoperta di una nuova vulnerabilità, ma prima della ricostruzione, i contenitori presentano una finestra di esposizione che cresce senza alcun cambiamento visibile.
Crea un programma di ricostruzione coerente. Automatizza questo processo ove possibile ed esegui periodicamente uno scanner di vulnerabilità sulle tue immagini attuali. L’obiettivo non è la perfezione. Sta riducendo il tempo che intercorre tra il rilascio di una patch e la sua implementazione.
Il controllo e il monitoraggio degli accessi possono perdere la priorità nelle distribuzioni veloci. Sono anche le categorie in cui gli incidenti passano inosservati più a lungo.
Controllo degli accessi e lacune di visibilità
Dopo che un contenitore viene eseguito con una configurazione solida e immagini attuali, rimangono due categorie di errori. Entrambi sono invisibili per natura: non noterai un problema di controllo degli accessi debole finché qualcuno non lo utilizza, e non noterai una lacuna nel monitoraggio finché non avrai bisogno di indagare su un'attività che non è mai stata registrata.
Lo stesso Ricerca Red Hat 2024 ha rilevato che il 42% dei team non disponeva di capacità sufficienti per affrontare la sicurezza dei container e le minacce correlate.
Abbiamo scoperto che le lacune nel monitoraggio emergono tipicamente durante le indagini sugli incidenti, non prima. Quando la visibilità diventa una priorità, spesso risponde a qualcosa anziché impedirlo.
Autenticazione debole e dashboard di gestione esposti
Una dashboard di gestione del contenitore su un IP pubblico senza autenticazione non richiede un utente malintenzionato sofisticato. Richiede loro di conoscere l'indirizzo. Si tratta di un livello più basso di quanto la maggior parte delle squadre realizzi.

Gli strumenti di monitoraggio e gestione self-hosted vengono generalmente forniti con un'interfaccia Web accessibile su tutte le interfacce di rete. Lasciare quelli su un IP pubblico senza autenticazione di fronte a loro è l'equivalente contenitore di lasciare un pannello di amministrazione sbloccato.
L'autenticazione, un proxy inverso e il posizionamento nella rete privata rappresentano la base. Il controllo degli accessi è un passaggio di configurazione che aggiungi a qualsiasi interfaccia di gestione, non qualcosa che viene fornito abilitato.
Lo stesso principio vale per Gestione CLI e GUI Docker; l'accesso a livello di amministratore al demone comporta lo stesso rischio indipendentemente dall'interfaccia.
Non monitorare cosa stanno facendo i tuoi contenitori
Se un contenitore viene compromesso, l’attività dell’aggressore crea una traccia: cambiamenti nel comportamento del processo, connessioni di rete insolite e modifiche impreviste dei file. Senza la raccolta dei registri in atto, quella traccia non esiste in una forma su cui puoi agire.
La raccolta centralizzata dei log, la registrazione degli audit dei contenitori e gli strumenti di monitoraggio del runtime forniscono i dati per rilevare attività anomale prima che si aggravino. L’obiettivo non è analizzare ogni riga. Significa avere i dati a disposizione quando è necessario indagare.
Le configurazioni dei contenitori eseguite in modalità silenziosa in produzione, senza pipeline di log e senza avvisi, non richiedono poca manutenzione. Non sono ispezionati. Si tratta di due stati operativi diversi.
Perché è importante anche l’ambiente infrastrutturale
La sicurezza del contenitore inizia con la configurazione, ma la configurazione viene eseguita sull'infrastruttura. Un host con una rete configurata in modo errato, risorse condivise o nessun filtro a livello di rete crea condizioni che incidono su ogni contenitore sopra di esso. Ottenere la corretta configurazione del contenitore e la corretta configurazione del server sono due attività separate.
Molte lacune nella sicurezza di Docker sono amplificate dalle condizioni che i contenitori stessi ereditano:
- Un server con tenant condiviso senza isolamento hardware tra tenant
- Un kernel host in esecuzione senza patch
- Un host senza filtri integrati a livello di rete
Ciò non elimina la necessità di eseguire i passaggi di configurazione precedenti, poiché il corretto rafforzamento dei contenitori è importante indipendentemente dal livello dell'infrastruttura. Iniziare con un’infrastruttura isolata rimuove un livello di preoccupazione dall’equazione.
Noi di Cloudzy offriamo due percorsi a seconda di ciò che richiede la tua configurazione:
- VPS Linux: un ambiente pulito per distribuire Docker autonomamente e applicare i passaggi di rafforzamento descritti in questo articolo
- Portainer VPS: un'opzione con un clic con Portainer preinstallato; il server si avvia e sei già nella dashboard
Entrambe le opzioni funzionano sulla stessa infrastruttura: virtualizzazione KVM, CPU AMD Ryzen 9 con boost clock fino a 5,7 GHz, memoria DDR5, storage SSD NVMe, rete fino a 40 Gbps e protezione DDoS gratuita tramite filtro BuyVM, in 12 sedi globali con uno SLA di uptime del 99,95%.
Per uno sguardo più approfondito sull'esecuzione di Portainer su un VPS, ne parleremo in un articolo dedicato.
Una pratica lista di controllo della sicurezza per le distribuzioni Docker
Gli errori di sicurezza Docker sopra menzionati derivano per lo più da singole decisioni di configurazione prese una volta e mai rivisitate. L'esecuzione di questo elenco di controllo rispetto a una configurazione esistente consente di individuare tali lacune. Funziona come un controllo, non come una guida alla distribuzione.
Queste best practice sulla sicurezza Docker illustrano come proteggere i contenitori Docker dagli errori di configurazione più comuni descritti sopra.
Riferimento rapido: tutti i 9 errori
| Errore | Categoria | Correzione su una riga |
| In esecuzione come root | Configurazione | Aggiungere UTENTE direttiva al tuo Dockerfile |
| Porte legate a 0.0.0.0 | Configurazione | Associarsi a 127.0.0.1 e instradare attraverso un proxy inverso |
| Nessun isolamento della rete | Configurazione | Suddividi i servizi su reti separate definite dall'utente in base alle esigenze di accesso. |
| Presa Docker montata | Configurazione | Rimuovere il supporto; utilizzare API con ambito o alternative |
| Immagini non attendibili o obsolete | Immagine | Utilizza immagini ufficiali con tag di versione appuntati |
| Segreti codificati | Immagine | Sposta le credenziali nelle variabili di ambiente di runtime o in un gestore dei segreti |
| Nessuna pianificazione di ricostruzione dell'immagine | Immagine | Imposta una cadenza di ricostruzione mensile; automatizzare dove possibile |
| Dashboard non autenticati | Accesso | Aggiungi l'autenticazione e sposta le interfacce utente di gestione sulle reti private |
| Nessuna raccolta di log del contenitore | Accesso | Configura la registrazione centralizzata e il monitoraggio del runtime |
Ti consigliamo di eseguirlo prima con le configurazioni esistenti, poiché è lì che è più probabile che siano già presenti le lacune.
Contenitori in esecuzione come non root: Controlla i tuoi Dockerfile per una direttiva USER. Se non esiste, il contenitore viene eseguito come root.
Associazioni di porte limitate a localhost o proxy: Esegui docker ps ed esamina i collegamenti delle porte. Una voce 0.0.0.0:PORT può essere raggiungibile pubblicamente sugli host dove nessun gruppo di sicurezza upstream, firewall esterno o regola della catena DOCKER-USER la blocca.
Reti bridge personalizzate in uso: I contenitori sul bridge predefinito di Docker possono raggiungersi liberamente. I contenitori sullo stesso bridge definito dall'utente possono comunque comunicare tra loro, quindi suddividi i servizi su reti separate in base al limite di attendibilità per un isolamento effettivo.
Presa Docker non montata nei container: Seleziona Componi file ed esegui argomenti. Se /var/run/docker.sock appare come volume, conferma che è necessario e intenzionale.
Immagini di base di editori verificati con versioni fissate: A FROM ubuntu:latest estrae una versione non specificata, potenzialmente obsoleta. Aggiungi a una versione specifica.
Nessun segreto in Dockerfiles, Compose file o build argomenti: La cronologia del livello immagine mantiene le credenziali dopo l'eliminazione del contenitore. Utilizza Componi segreti, Swarm segreti, costruisci cavalcature segrete o un gestore di segreti esterno. Le variabili di ambiente di runtime sono migliori dei valori codificati, ma vengono comunque visualizzati nell'output e nei log di ispezione.
Pianificazione della ricostruzione dell'immagine definita: Le vecchie immagini accumulano vulnerabilità. Una cadenza di ricostruzione mensile mantiene la finestra di esposizione gestibile per la maggior parte delle configurazioni.
Interfacce di gestione dietro l'autenticazione: Qualsiasi dashboard su un IP pubblico senza autenticazione è un punto di ingresso aperto. Ove possibile, è preferibile il posizionamento in una rete privata.
Log del contenitore raccolti: Senza una pipeline di log, il rilevamento degli incidenti dipende dall'impatto visibile del sistema. Questo è un segnale tardivo su cui agire.
Conclusione
La configurazione predefinita di Docker è progettata per comodità, non per sicurezza. La maggior parte degli errori trattati in questo articolo sono riconducibili a impostazioni che non sono mai state modificate dopo la distribuzione iniziale e non ad attacchi sofisticati.
Le correzioni sono per lo più decisioni di configurazione una tantum: una direttiva USER, una modifica del collegamento della porta, una rete personalizzata, una pianificazione della ricostruzione. Nessuno di essi richiede nuovi strumenti per la maggior parte delle configurazioni.
Ottenere la corretta configurazione del contenitore è il primo compito. L'infrastruttura su cui gira è la seconda. Entrambi contano e nessuno dei due sostituisce l’altro.