Sul successo del modello-container e di Docker c’è poco da dire: piace perché è una forma di virtualizzazione “leggera” e perché si adatta bene al concetto dei microservizi, altro trend inarrestabile.
Non sorprende quindi che moltissime aziende siano rapidamente salite sul treno di Docker, tranne poi a chiedersi quanto la piattaforma sia davvero sicura, per la sua impostazione. In realtà non è una domanda che ha una risposta semplice, perché Docker più che una piattaforma è un insieme di elementi (almeno due) la cui sicurezza a valutata in modo differente.
Un ambiente Docker è in ultima analisi composto dall’engine che si occupa di gestire i container (quello che di solito implicitamente si indica quando si cita Docker) e dai container stessi. La sicurezza va quindi considerata in maniera distinta per il primo e per i secondi.
Come si tutela l’engine
Il Docker Engine “è” la tecnologia di containerizzazione in sé. Esegue i container a partire dai loro file immagine, assegna loro le risorse necessarie di elaborazione, si occupa degli aspetti legati alla rete e allo storage condiviso. La sua sicurezza è strettamente legata a due elementi che derivano dalla genesi Linux della tecnologia: i namespace e i cgroup.
In estrema sintesi, i namespace (più precisamente e completamente, gli user namespace) fanno in modo che un container veda solo una parte delle risorse del sistema host ma si comporti come se fosse in realtà l’unico elemento in esecuzione. In questo modo si raggiunge un elevato grado di isolamento tra i container: nessuno ha visibilità su cosa fanno gli altri, con conseguenze positive sulla sicurezza del sistema e sulla privacy delle informazioni. I namespace sono supportati dalla versione 1.10 di Docker ma non sono attivi di default.
I cgroup, o control group, sono – sempre in sintesi – un meccanismo di Linux che permette di assegnare una quantità limitata di risorse del sistema (CPU, memoria, rete, I/O) a un gruppo di processi. In questo modo siamo sicuri che anche un comportamento anomalo di un container nell’usare le risorse di sistema non impatterà negativamente sulle prestazioni degli altri container.
Insieme, namespace e cgroup fanno in modo che i container non possano apportare danni al sistema consumando le sue risorse e nemmeno intervenire negativamente sul funzionamento delle altre applicazioni. Si può anche andare oltre le funzioni offerte dai due approcci, implementandone altri che garantiscono un controllo ancora più granulare su cosa possa o non possa fare un container. Alcuni esempi in questo senso sono AppArmor e Seccomp.
Container sotto controllo
Il Docker Engine gestisce i container e può isolarli, ma non si occupa di controllare se un container è “sicuro”, ossia se ha una vulnerabilità che potenzialmente rischia di mettere in crisi tutto il sistema host o parti di esso. Non è un elemento secondario perché il bello della virtualizzazione a container è la sua estrema portabilità: chiunque può sviluppare un container e distribuire la sua immagine in modo che altri possano scaricarla ed eseguirla con pochi clic del mouse. Ma se quel container ha qualche problema, ecco che di colpo lo abbiamo anche noi.
Il modo per evitare questo rischio è ricavare immagini solo da fonti – i registry – ufficiali e controllate. Nella gran parte dei casi questo significa scaricare dal Docker Hub, la piattaforma cloud che fa capo al progetto Docker e che viene comunemente usata dagli sviluppatori per condividere codice e container.
Il Docker Hub ha una funzione (a pagamento) per la scansione delle immagini dei container: va alla ricerca delle principali vulnerabilità conosciute e presenta un “indice” di pericolosità dell’immagine nel suo complesso. La funzione di scansione elenca i problemi rilevati e queste indicazioni servono agli sviluppatori per capire come eliminarli. E a noi per non scaricare l’immagine prima che sia stata corretta.
Non c’è peraltro solo il Docker Hub. Ci sono anche diversi altri registry ufficiali dai quali “fornirsi” in sicurezza. Ciò che va evitato è scaricare immagini di container da sviluppatori sconosciuti.