Sicurezza dei cluster Kubernetes, componente per componente
Chi conosce Kubernetes sa che non si tratta di un unico strumento, ma di una moltitudine di servizi e risorse diversi quali server API, agenti di nodi, runtime di container e molto altro.
Ciascun componente all’interno di un cluster Kubernetes è soggetto a diverse minacce per la sicurezza e richiede configurazioni diverse. In alcuni casi, è possibile applicare la stessa tecnica di protezione a più componenti. Per esempio, è possibile utilizzare il Role-Based Access Control per gestire le autorizzazioni di diversi tipi di risorse in Kubernetes.
Tuttavia, alcuni componenti hanno requisiti di sicurezza unici che richiedono soluzioni uniche. Proteggere il server API, ad esempio, è diverso da proteggere i nodi. Per proteggere i cluster Kubernetes è necessario capire e affrontare le possibili minacce alla sicurezza relative a ciascun componente.
Tenendo questa realtà ben chiara in mente, ecco come proteggere un cluster Kubernetes proteggendo ciascuno dei suoi molti componenti.
Come proteggere un cluster Kubernetes
Proteggere il server API di Kubernetes
Il server API, kube-apiserver, è il cuore del cluster Kubernetes. È responsabile di accogliere le richieste di accesso, di eseguire i workload, eccetera.
Il principale strumento per proteggerlo è il Role-Based Access Control, o RBAC. Tramite le policy RBAC, è possibile definire utenti e account di servizio e assegnare autorizzazioni che consentano loro di svolgere alcune azioni utilizzando l’API di Kubernetes.
Per esempio, è possibile creare un Role RBAC che consenta a una risorsa di ottenere, visualizzare ed elencare i pod all’interno del namespace Kubernetes predefinito. Il Role avrebbe più o meno questa forma:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
Code language: PHP (php)
A questo punto, il Role dovrebbe essere associato a un gruppo di utenti o servizi in Kubernetes creando un RoleBinding o un ClusterRoleBinding con un comando del tipo:
kubectl create rolebinding podreader-binding --user=john
Questo RoleBinding autorizza l’utente “john” a ottenere, visualizzare ed elencare i pod definiti nel Role indicato sopra.
Controller di ammissione e sicurezza dell’API di Kubernetes
È inoltre possibile creare un secondo livello di difesa per l’API di Kubernetes (e, per estensione, per l’interno cluster) utilizzando i controller di ammissione. In pratica, i controller di ammissione sono codici che intercettano le richieste indirizzate all’API di Kubernetes dopo che l’API le ha già autenticate e autorizzate ma prima che vengano applicate.
È possibile utilizzare i controller di ammissione, ad esempio, per limitare il volume delle risorse che un oggetto può richiedere dall’API, oppure per impedire l’esecuzione di alcuni comandi anche quando le policy RBAC e i contesti di protezione le consentono.
Utilizzare i registri di controllo per migliorare la sicurezza
Una terza risorsa che aiuta a prevenire i problemi di sicurezza legati all’API di Kubernetes è rappresentata dai registri di controllo. I registri di controllo sono una funzione opzionale di Kubernetes che consente di registrare e tenere traccia delle richieste mentre il server API le elabora.
Creando registri di controllo e analizzandoli continuamente con uno strumento come Falco, si ricevono avvisi automatici quando un utente o un servizio effettuano richieste sospette, ad esempio quando cercano ripetutamente di accedere a risorse a cui non sono autorizzati ad accedere.
Protezione e backup di etcd
Per impostazione predefinita, Kubernetes utilizza etcd, un archivio di valori chiave, per archiviare tutti i dati relativi alle configurazioni del cluster.
Kubernetes non offre alcuno strumento nativo per proteggere etcd, ma è necessario abilitare la sicurezza del trasporto. Consultare la documentazione etcd per maggiori dettagli.
Come migliore prassi per la sicurezza del cluster, bisogna inoltre effettuare il backup di etcd utilizzando il comando etcdctl snapshot save. Anche se Kubernetes viene eseguito in ambienti nei quali la sicurezza di etcd è praticamente garantita, i backup proteggono dal ransomware o da altri attacchi che cercano di impedire l’accesso ai dati di configurazione critici archiviati in etcd.
Infine, quando si lavora con etcd, è consigliabile evitare di archiviare in esso dati segreti o sensibili come password e chiavi d’accesso. Molte distribuzioni di Kubernetes archiviano informazioni segrete su etcd per impostazione predefinita, ma bisognerebbe piuttosto utilizzare un sistema di gestione esterno.
Proteggere il nodo master
In Kubernetes, un nodo master è il nodo che ospita il server API, il pianificatore, il controller ed etcd, ovvero tutti i servizi fondamentali che tengono insieme e gestiscono un cluster di Kubernetes. Alcuni cluster di Kubernetes possono eseguire più nodi master per aumentare la loro disponibilità, nel qual caso ciascuno dei nodi eseguirà istanze ridondanti dei principali servizi di Kubernetes.
Dato il ruolo centrale dei nodi master nel cluster, la loro protezione è vitale per la sicurezza generale del cluster. Diverse sono le migliori prassi da seguire per proteggere i nodi master:
- Dotare i nodi di distribuzioni minimaliste di Linux, ad esempio Alpine Linux. Evitare di installare applicazioni o librerie extra sul nodo a meno che non siano strettamente necessarie.
- Utilizzare policy RBAC per limitare le azioni che possono essere svolte sui nodi. Minore è l’accesso ai nodi e minori sono le informazioni che li riguardano, più i nodi stessi saranno protetti dagli hacker.
- Utilizzare strumenti di applicazione quali SELinux, AppArmor e seccomp per limitare il controllo degli accessi a livello di kernel sul master. Questi strumenti consentiranno di evitare l’escalation degli eventi di sicurezza rendendo più difficile per un processo dannoso accedere alle risorse del kernel o interferire con altri processi.
- Monitorare costantemente i file di registro dei nodi per rilevare segnali di attività sospette.
Protezione dei nodi worker e limitazione delle autorizzazioni Kubelet e Kube-Proxy
Lo scopo principale dei nodi worker è ospitare container o pod in esecuzione. Ciascun nodo worker comunica con il resto del cluster attraverso kubelet, un agente eseguito localmente su ciascun nodo worker. I nodi worker utilizzano inoltre un servizio chiamato kube-proxy per gestire le comunicazioni di rete per i pod ospitati su di essi.
Da design, i nodi worker di Kubernetes sono sostituibili. Se un nodo smette di funzionare, cioè, Kubernetes riassegnerà automaticamente i suoi pod ad altri nodi. In questo senso, proteggere i nodi worker è meno critico che proteggere i nodi master, perché un problema ad alcuni nodi worker causato da questioni di sicurezza non pone una minaccia tanto grave al cluster.
Ciononostante, l’autore di un attacco che riesce a compromettere un nodo worker può potenzialmente accedere a qualunque pod ospitato su di esso. Per questa ragione, è importante adottare delle misure per proteggere i nodi worker nel contesto del processo di sicurezza generale del cluster.
Tutte le migliori prassi per la protezione dei nodi master indicate sopra valgono anche per i nodi worker. Inoltre, bisogna considerare di limitare le autorizzazioni assegnate a kubelet e kube-proxy per ridurre il potenziale danno causato da un attacco che riesce a evadere da un container e a introdursi nel nodo worker che lo ospita.
Scansione continua delle immagini dei container
Le immagini dei container, che definiscono le risorse richieste per eseguire un container, non fanno parte di Kubernetes, tuttavia sono un elemento fondamentale di molti cluster Kubernetes e non dovrebbero essere trascurate nella loro protezione.
La chiave per proteggere le immagini dei container è scansionarle continuamente. Inoltre, è possibile minimizzare i problemi di sicurezza legati ai container:
- Utilizzando solo immagini derivanti da fonti affidabili. Resistendo alla tentazione di ottenere immagini da un registro casuale solo per comodità.
- Evitando di utilizzare il tag “latest” (più recente) quando si cercano le immagini. Al contrario, è bene specificare una versione per conoscere esattamente qual è la versione del container in esecuzione e quali vulnerabilità potrebbero interessarla.
- Adottando un approccio minimalista alla progettazione delle immagini dei container. Piuttosto che ammassare molte risorse in un’unica immagine, creando diverse immagini per ciascuna funzionalità che si desideri implementare.
Sicurezza del runtime dei container
Il runtime di un container è un servizio che esegue i container. Kubernetes supporta molti runtime diversi. Le differenze tra i runtime di solito non sono rilevanti per i casi d’uso, perché molti di essi sono in grado di eseguire la maggior parte dei container.
Una falla nella sicurezza del software di runtime di un container potrebbe consentire agli autori di un attacco di svolgere una molteplicità di azioni. Per esempio, nel 2019 gli sviluppatori hanno scoperto una grave vulnerabilità nel runtime di Docker che consentiva ai container di ottenere accesso a livello di root all’intero host.
Kubernetes non prevede funzioni per monitorare le vulnerabilità dei runtime dei container o per avvisare di eventuali violazioni che potrebbero derivare da tali vulnerabilità. È pertanto necessario affidarsi a strumenti esterni per proteggere i runtime, tra cui:
- Strumenti di applicazione quali SELinux e AppArmor, che possono essere utilizzati per limitare le azioni svolte da un container dannoso. Se adeguatamente configurati, questi strumenti rappresentano un secondo livello di difesa in caso di attacco che sfrutta una vulnerabilità del runtime di un container e gli consente di svolgere azioni che non dovrebbe poter svolgere.
- Strumenti di controllo quali Falco monitorano continuamente i registri di controllo e altri stream di dati dall’ambiente di runtime del container e generano un avviso quando rilevano comportamenti che potrebbero indicare una violazione. Sebbene gli strumenti di controllo siano in grado di rilevare diverse minacce per la sicurezza oltre a quelle associate con i runtime dei container, sono uno dei principali strumenti per l’individuazione di violazioni derivanti da una vulnerabilità a livello di runtime.
- A meno che non sia strettamente necessario, i contesti di protezione di Kubernetes impediscono ai container di eseguire la modalità privilegiata e limitano le risorse a cui hanno accesso. Anche se i contesti di protezione non impediscono direttamente le vulnerabilità del runtime dei container, forniscono un ulteriore livello di difesa in grado di mitigare l’impatto di una eventuale violazione.
Un approccio olistico alla sicurezza dei cluster di Kubernetes
Sarebbe molto più semplice se esistesse un trucco magico da utilizzare per proteggere in una sola volta tutti i componenti di Kubernetes. Ma non esiste. La sicurezza di Kubernetes è tanto complessa quanto l’architettura che lo caratterizza. Mentre alcune prassi a livello di cluster, come il controllo e il monitoraggio, possano fornire ampia protezione da alcuni tipi di minacce, è anche necessario ricorrere a risorse di sicurezza in grado di proteggere i singoli componenti che formano un cluster Kubernetes, dal server API ai nodi worker e master, a etcd, e così via.