Sysdig
Learn Cloud Native

Sign up to receive our newsletter

Registri di controllo per la protezione di Kubernetes

In generale, Kubernetes non offre funzioni di monitoraggio della sicurezza o di rilevamento delle minacce. Si aspetta che l’utente, cioè l’amministratore dei cluster, monitori e reagisca ai problemi di sicurezza in autonomia.

Tuttavia, Kubernetes offre uno strumento importante che aiuta a rilevare potenziali eventi, ovvero i registri di controllo. Registrando sistematicamente informazioni sulle richieste di accesso emesse dall’API di Kubernetes, i registri di controllo rappresentano una risorsa centralizzata da usare per rilevare le attività sospette in tutto il cluster.

Questo articolo definisce i registri di controllo di Kubernetes, spiega come si usano e fornisce alcuni esempi di impiego per il tracciamento degli eventi di sicurezza.

Cos’è un registro di controllo di Kubernetes?

Per spiegarlo in modo semplice, un registro di controllo di Kubernetes è un registro delle informazioni che provengono dal servizio di controllo di Kubernetes.

Lo scopo dei registri di controllo è aiutare gli amministratori dei cluster a tracciare le richieste inviate, chi le ha generate, quali sono le risorse coinvolte e il risultato di ciascuna richiesta.

Dunque, registrando e analizzando i dati, è possibile ottenere una visibilità tempestiva su eventuali problemi di sicurezza nei cluster, ad esempio richieste di accesso non autorizzato ad alcune risorse o richieste generate da utenti o servizi sconosciuti. I registri di controllo possono inoltre rivelarsi molto utili nella ricerca di una violazione alla sicurezza già in atto (per quanto si speri sempre di individuare i problemi prima che causino una violazione!).

I registri di controllo esistono solo se vengono creati in Kubernetes

Sebbene di frequente si senta parlare di “registri di controllo di Kubernetes” questa dicitura è abbastanza fuorviante, poiché Kubernetes non crea autonomamente un registro di controllo specifico. In altre parole, Kubernetes non registra automaticamente tutti gli eventi di controllo in un file specifico da aprire o monitorare per tenere traccia degli eventi di sicurezza.

In realtà, Kubernetes offre le strutture che gli amministratori possono utilizzare per registrare gli eventi di sicurezza e trasferirli a un backend a propria scelta. Pertanto, è possibile creare diversi tipi di registri di controllo in Kubernetes, ma la loro esatta natura dipenderà dalla configurazione impostata. E non esistono registri di controllo predefiniti a meno che non si configurino da zero.

Eventi di controllo e fasi in Kubernetes

Kubernetes registra i dati di controllo in base a due concetti chiave: le fasi e gli eventi di controllo.

Un evento di controllo è una qualunque richiesta che arriva a un server API, mentre le fasi sono i passaggi che il server esegue per gestire ogni richiesta.

Per ciascun evento esistono quattro “fasi” possibili:

  1. RequestReceived: In questa fase, il server API ha ricevuto la richiesta ma non ha ancora iniziato a elaborarla.
  2. ResponseStarted: Il server ha iniziato a elaborare la richiesta ma non ha ancora inviato una risposta.
  3. ResponseComplete: Il server ha terminato di elaborare la richiesta e ha inviato una risposta.
  4. Panic: Questa fase avviene quando il server API “va in panico” in risposta a una richiesta.

È possibile istruire Kubernetes in maniera tale che registri le informazioni per ciascuna fase di ciascun evento di controllo che avviene nel cluster. In questo modo, è possibile tracciare non solo l’occorrenza delle richieste rilevanti in termini di sicurezza ma anche il modo in cui esse vengono gestite.

Questa granularità è vantaggiosa perché aiuta a valutare la gravità degli incidenti di sicurezza. Per esempio, una richiesta potenzialmente dannosa bloccata in fase ResponseStarted è meno preoccupante di una richiesta a seguito della quale il server API ha inviato una risposta affermativa. Certamente bisognerà raccogliere informazioni su entrambi gli eventi, ma il secondo ha la priorità. Il controllo di Kubernetes aiuta a capire questa differenza.

Formato dei registri di controllo

Per impostazione predefinita, Kubernetes genera i dati relativi a ciascun evento di controllo in formato JSON. Ad esempio, un evento archiviato in un registro di controllo potrebbe avere questa forma:

{ "kind": "Event", "apiVersion": "audit.k8s.io/v1beta1", "metadata": { "creationTimestamp": "2018-10-08T08:26:55Z" }, "level": "Request", "timestamp": "2018-10-08T08:26:55Z", "auditID": "288ace59-97ba-4121-b06e-f648f72c3122", "stage": "ResponseComplete", "requestURI": "/api/v1/pods?limit=500", "verb": "list", "user": { "username": "admin", "groups": ["system:authenticated"] }, "sourceIPs": ["10.0.138.91"], "objectRef": { "resource": "pods", "apiVersion": "v1" }, "responseStatus": { "metadata": {}, "code": 200 }, "requestReceivedTimestamp": "2018-10-08T08:26:55.466934Z", "stageTimestamp": "2018-10-08T08:26:55.471137Z", "annotations": { "authorization.k8s.io/decision": "allow", "authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding "admin-cluster-binding" of ClusterRole "cluster- admin" to User "admin"" } }
Code language: PHP (php)

Abilitazione dei controlli nel server API di Kubernetes

Come già detto, Kubernetes offre le strutture che consentono di registrare gli eventi di controllo, ma non li registra per impostazione predefinita. È necessario abilitare e configurare questa funzione per generare i registri di controllo.

Per farlo, è necessario specificare la posizione di due file nella configurazione del server API:

--audit-policy-file=/etc/kubernetes/audit-policy.yaml \ --audit-log-path=/var/log/audit.log
Code language: JavaScript (javascript)

In questo caso, audit-policy.yaml è il file che definisce quali eventi di controllo devono essere registrati e in che modo devono essere registrati, mentre audit.log è il luogo (nel nodo master) nel quale i dati vengono effettivamente archiviati.

Definizione del file delle policy di controllo

Di solito non si desidera registrare ogni singola richiesta API che avviene all’interno di un cluster. Questo genererebbe una quantità di dati così grande da risultare difficile da filtrare.

Ecco perché è necessario creare un file contenente le policy di controllo. Si tratta di un file in formato YAML che specifica quali eventi devono essere registrati e quanti dati registrare per ciascuno di essi.

Per esempio:

apiVersion: audit.k8s.io/v1 # This is required. kind: Policy # Don't generate audit events for all requests in RequestReceived stage. omitStages: - "RequestReceived" rules: # Log pod changes at RequestResponse level - level: RequestResponse resources: - group: "" # Resource "pods" doesn't match requests to any subresource of pods, # which is consistent with the RBAC policy. resources: ["pods"] # Only check access to resource "pods" - level: Metadata resources: - group: "" resources: ["pods/log", "pods/status"] # Don't log watch requests by the "system:kube-proxy" on endpoints or services - level: None users: ["system:kube-proxy"] verbs: ["watch"] resources: - group: "" # core API group resources: ["endpoints", "services"] # Don't log authenticated requests to certain non-resource URL paths. - level: None userGroups: ["system:authenticated"] nonResourceURLs: - "/api*" # Wildcard matching. - "/version" # Log the request body of configmap changes in kube-system. - level: Request resources: - group: "" # core API group resources: ["configmaps"] # This rule only applies to resources in the "kube-system" namespace. # The empty string "" can be used to select non-namespaced resources. namespaces: ["kube-system"] # Log configmap and secret changes in all other namespaces at the Metadata level. - level: Metadata resources: - group: "" # core API group resources: ["secrets", "configmaps"] # A catch-all rule to log all other requests at the Metadata level. - level: Metadata # Long-running requests like watches that fall under this rule will not # generate an audit event in RequestReceived. omitStages: - "RequestReceived"
Code language: PHP (php)

Come si capisce dai commenti, questo file di policy specifica i tipi di eventi di controllo registrati. Vengono ignorati gli eventi in fase RequestReceived, per esempio, e viene tracciato solo l’accesso ai pod.

Rilevamento di eventi di sicurezza con i registri di controllo

Per avere un esempio del controllo di Kubernetes, possiamo immaginare di aver creato una policy di controllo come la seguente:

apiVersion: audit.k8s.io/v1beta1 kind: Policy omitStages: - "RequestReceived" Rules: - level: Request users: ["admin"] Resources: - group: "" resources: ["*"] - level: Request user: ["system:anonymous"] resources: - group: "" resources: ["*"]
Code language: JavaScript (javascript)

Utilizzando questa configurazione, possiamo rilevare i casi in cui un nuovo utente non associato a un Role o ClusterRole esistente genera una richiesta.

Per esempio, immaginiamo che l’utente provi a elencare i pod con il comando:

kubectl get pods
Code language: JavaScript (javascript)

Dal momento che l’utente non è autorizzato a elencare i pod, il server API rifiuterà la richiesta (kubectl risponderà con “Error from server (Forbidden): pods is forbidden: User”).

Allo stesso tempo, il server API registrerà un evento di controllo simile al seguente:

{ "kind": "Event", "apiVersion": "audit.k8s.io/v1beta1", "metadata": { "creationTimestamp": "2018-10-08T10:00:20Z" }, "level": "Request", "timestamp": "2018-10-08T10:00:20Z", "auditID": "5fc5eab3-82f5-480f-93d2-79bfb47789f1", "stage": "ResponseComplete", "requestURI": "/api/v1/namespaces/default/pods?limit=500", "verb": "list", "user": { "username": "system:anonymous", "groups": ["system:unauthenticated"] }, "sourceIPs": ["10.0.141.137"], "objectRef": { "resource": "pods", "namespace": "default", "apiVersion": "v1" }, "responseStatus": { "metadata": {}, "status": "Failure", "reason": "Forbidden", "code": 403 }, "requestReceivedTimestamp": "2018-10-08T10:00:20.605009Z", "stageTimestamp": "2018-10-08T10:00:20.605191Z", "annotations": { "authorization.k8s.io/decision": "forbid", "authorization.k8s.io/reason": "" } }
Code language: JSON / JSON with Comments (json)

Tracciando il registro di controllo, quindi, gli amministratori possono rilevare la richiesta ed essere avvisati dell’esistenza di un account utente che probabilmente non dovrebbe esistere.

Sfruttare la meglio i registri di controllo di Kubernetes

In un cluster ampio, nel quale i server API gestiscono centinaia o migliaia di richieste all’ora, non è pratico esaminare manualmente un registro di controllo per rilevare potenziali rischi.

Al contrario, è consigliabile inviare i dati registrati a uno strumento di rilevamento che possa monitorare automaticamente gli eventi di controllo e generare avvisi per i casi sospetti.

Esistono due modi per fare ciò:

  • Monitorare direttamente il file del registro di controllo: È possibile configurare uno strumento di rilevamento delle intrusioni al fine di monitorare il file del registro di controllo direttamente sul nodo master. A questo scopo sarà però necessario eseguire lo strumento sul nodo master, il che potrebbe non essere una soluzione ottimale poiché aumenta il carico sul master. (Ovviamente è possibile provare a prendere il file dal nodo master e inviarlo a uno strumento esterno attraverso un agente di registrazione eseguito in locale, ma questo non risolve completamente il problema perché è comunque necessario utilizzare un ulteriore software – l’agente di registrazione – sul master). 
  • Inviare gli eventi attraverso l’HTTP: È possibile utilizzare i webhook per inviare i dati relativi agli eventi a uno strumento di sicurezza esterno attraverso l’HTTP. In questo modo, lo strumento di sicurezza può lavorare separatamente dal cluster.

Per esempio, per inviare i dati relativi a un evento a Falco, lo strumento di sicurezza di runtime open-source, bisognerebbe configurare Falco come webhook di backend nel file kube-apiserver:

apiVersion: v1 kind: Config clusters: - name: falco cluster: server: http://$FALCO_SERVICE_CLUSTERIP:8765/k8s_audit contexts: - context: cluster: falco user: "" name: default-context current-context: default-context preferences: {} users: []
Code language: JavaScript (javascript)

Con questa configurazione, è possibile utilizzare Falco (ospitato su un server a scelta) per avvisare degli eventi di sicurezza quando accadono. Non è necessario occuparsi di monitorare direttamente il file del registro di controllo di Kubernetes né eseguire un software di sicurezza direttamente nel cluster.

Il controllo è una componente essenziale di qualunque strategia di sicurezza in Kubernetes. Sebbene i registri di controllo, come molti elementi di Kubernetes, siano piuttosto complessi da impostare e gestire, sono anche altamente configurabili. Kubernetes permette infatti di stabilire esattamente i tipi di dati da registrare, il luogo in cui devono essere registrati e il modo in cui si desidera elaborarli.

Scegliendo strategicamente i tipi di eventi di controllo da registrare (evitando gli eventi inutili!) e integrando i dati di controllo con strumenti di rilevamento delle intrusioni (come Falco) che possono avvisare di eventuali rischi in tempo reale, è possibile individuare e correggere al meglio le minacce alla sicurezza di Kubernetes prima che si trasformino in grandi problemi.