Parte 1: Concetti
Il GDPR ha introdotto il “diritto all’oblio”, che consente alle persone di presentare richieste verbali o scritte di cancellazione dei dati personali. Una delle sfide comuni quando si cerca di conformarsi a questo requisito in un’infrastruttura applicativa basata su Apache Kafka è la possibilità di cancellare selettivamente tutti i record Kafka relativi a uno degli utenti dell’applicazione.
Il modello di dati di Kafka non avrebbe mai potuto supportare una tale funzione di cancellazione selettiva, quindi le aziende hanno dovuto trovare e implementare dei workaround. Al momento in cui scriviamo, l’unico modo per eliminare i messaggi in Kafka è attendere la scadenza della conservazione dei messaggi o utilizzare argomenti compatti che prevedono la pubblicazione di messaggi tombali, il che non è fattibile in tutti gli ambienti e non si adatta a tutti i casi d’uso.
HashiCorp Vault offre la crittografia come servizio e, in effetti, può aiutarci a implementare una soluzione senza ricorrere a workaround, né nel codice dell’applicazione né nel modello di dati Kafka.
Crittografia Vault come servizio
Il motore dei segreti di Vault Transit gestisce le operazioni crittografiche sui dati in transito senza conservare alcuna informazione. Ciò consente di introdurre facilmente la crittografia in applicazioni esistenti o nuove, eseguendo una semplice richiesta HTTP.
Vault gestisce in modo completo e trasparente il ciclo di vita delle chiavi di crittografia, per cui né gli sviluppatori né gli operatori devono preoccuparsi della conformità e della rotazione delle chiavi, mentre i dati memorizzati in modo sicuro possono sempre essere crittografati e decrittografati finché il Vault è accessibile.
Integrazione di Kafka
E se invece di cercare di eliminare selettivamente i dati che l’applicazione non è autorizzata a conservare, ci limitassimo a fare in modo che l’applicazione (o chiunque altro) non possa leggere i dati in nessun caso? Ciò equivarrebbe alla rimozione fisica dei dati, proprio come richiesto dalla conformità al GDPR. Questo risultato può essere ottenuto crittografando selettivamente le informazioni che si desidera eliminare e gettando via la chiave quando viene richiesta l’eliminazione.
Tuttavia, è necessario eseguire la crittografia e la decrittografia in modo trasparente per l’applicazione, per ridurre lo sforzo di refactoring e di integrazione per ciascuna delle applicazioni che utilizzano Kafka e per sbloccare questa funzionalità per le applicazioni che non possono essere adattate.
Le API di Kafka supportano gli intercettori per la produzione e il consumo dei messaggi, che sono l’anello della catena in cui sfruttare la crittografia di Vault come servizio. All’interno dell’intercettore, possiamo eseguire la trasformazione dei messaggi necessaria:
- prima che un record venga inviato a Kafka, l’intercettore esegue la crittografia e adatta il contenuto del record con i dati crittografati
- prima che un record venga restituito a un client consumer, l’intercettore esegue la decodifica e adatta il contenuto del record con i dati decodificati
Cancellazione logica
Questo ci permette di cancellare tutti i messaggi Kafka relativi a un singolo utente? Sì, ed è molto semplice. Se la chiave di crittografia che utilizziamo per criptare i dati nei messaggi Kafka è diversa per ogni utente della nostra applicazione, possiamo procedere alla cancellazione della chiave di crittografia per garantire che non sia più possibile leggere i dati dell’utente.
Replica al di fuori dell’UE
Dato che ora i dati sensibili memorizzati nel nostro cluster Kafka sono crittografati a riposo, è possibile replicare il nostro cluster Kafka al di fuori dell’UE, ad esempio per scopi di disaster recovery. I dati saranno accessibili solo agli utenti che hanno le giuste autorizzazioni per eseguire le operazioni di crittografia nel Vault.
Parte 2: Aspetti tecnici
Nella parte precedente abbiamo illustrato l’idea generale alla base dell’integrazione di HashiCorp Vault e Apache Kafka per l’esecuzione di una crittografia a grana fine a riposo dei messaggi, al fine di soddisfare i requisiti di conformità al GDPR all’interno di Kafka. In questa parte, invece, facciamo un’immersione profonda su come dare vita a questa idea.
Motore per i segreti di Vault Transit
Il motore dei segreti di Vault Transit fa parte di Vault Open Source ed è molto semplice da utilizzare. Per configurare il motore è sufficiente abilitarlo e creare alcune chiavi di crittografia:
Anche le operazioni di crittografia possono essere eseguite in modo molto semplice, basta fornire dati in chiaro codificati in base64:
Il testo cifrato risultante avrà l’aspetto di vault:v1: – dove v1 rappresenta la prima generazione di chiavi, dato che non è ancora stata ruotata.
E la decrittazione? Si tratta di un’altra chiamata all’API:
L’integrazione di Encryption as a Service di Vault all’interno della vostra applicazione diventa davvero facile da implementare e non richiede alcuna modifica della base di codice esistente.
Intercettore del produttore Kafka
L’API Producer Interceptor può intercettare ed eventualmente mutare i record ricevuti dal produttore prima che vengano pubblicati sul cluster Kafka. In questo scenario, l’obiettivo è quello di eseguire la crittografia all’interno di questo intercettore, per evitare di inviare dati in chiaro al cluster Kafka…
L’integrazione della crittografia nel Producer Interceptor è semplice, dato che il metodo onSend viene invocato un messaggio alla volta.
Intercettore del consumatore Kafka
L’API Consumer Interceptor può intercettare ed eventualmente modificare i record ricevuti dal consumatore. In questo scenario, vogliamo eseguire la decodifica dei dati ricevuti dal cluster Kafka e restituire i dati in chiaro al consumatore.
L’integrazione della decodifica con Consumer Interceptor è un po’ più complicata perché si è voluto sfruttare le capacità di decodifica in batch di Vault, per ridurre al minimo le chiamate all’API di Vault.
Utilizzo
Una volta creati gli intercettori, per abilitarli è sufficiente configurare il client Consumer o Producer:
o
Si noti che la classe di serializzazione dei valori e delle chiavi deve essere impostata su StringSerializer, poiché Vault Transit può gestire solo stringhe contenenti dati base64. Il client che invoca le API Kafka Producer e Consumer, tuttavia, è in grado di elaborare qualsiasi tipo di dati supportati, in base al serializzatore o deserializzatore configurato nelle proprietà interceptor.value.serializer o interceptor.value.deserializer.
Conclusioni
Il motore per i segreti di HashiCorp Vault Transit è sicuramente il componente tecnologico da sfruttare per soddisfare i requisiti crittografici delle applicazioni, anche quando si tratta di componenti legacy. L’intero set di funzionalità offerte da HashiCorp Vault semplifica la modernizzazione delle applicazioni dal punto di vista della sicurezza, consentendo agli sviluppatori di concentrarsi sulla logica di business piuttosto che dedicare tempo alla ricerca di un modo per gestire correttamente i segreti.
Autore: Simone Ripamonti, DevOps Engineer @Bitrock