Crittografia in MySQL: keystore

In attesa dell'inizio di una nuova iscrizione al corso "Banca dati" Abbiamo preparato per te la traduzione di un articolo utile.

Crittografia in MySQL: keystore

È apparsa la crittografia trasparente dei dati (TDE). Server Percona per MySQL e MySQL per un bel po' di tempo. Ma hai mai pensato a come funziona dietro le quinte e quale impatto può avere TDE sul tuo server? In questa serie di articoli esamineremo come funziona internamente TDE. Cominciamo con l'archiviazione delle chiavi, poiché è necessaria per il funzionamento di qualsiasi crittografia. Quindi daremo un'occhiata più da vicino a come funziona la crittografia in Percona Server for MySQL/MySQL e quali funzionalità aggiuntive ha Percona Server for MySQL.

Portachiavi MySQL

I keyring sono plugin che consentono al server di interrogare, creare ed eliminare chiavi in ​​un file locale (keyring_file) o su un server remoto (come HashiCorp Vault). Le chiavi vengono sempre memorizzate nella cache locale per accelerarne il recupero.

I plugin possono essere suddivisi in due categorie:

  • Memoria locale. Ad esempio, un file locale (lo chiamiamo portachiavi basato su file).
  • Archiviazione remota. Ad esempio, Vault Server (lo chiamiamo portachiavi basato su server).

Questa separazione è importante perché diversi tipi di archiviazione si comportano in modo leggermente diverso, non solo durante l'archiviazione e il recupero delle chiavi, ma anche durante l'esecuzione.

Quando si utilizza un archivio di file, all'avvio, l'intero contenuto dell'archivio viene caricato nella cache: ID chiave, utente chiave, tipo di chiave e la chiave stessa.

Nel caso di un archivio lato server (come Vault Server), all'avvio vengono caricati solo l'ID chiave e l'utente chiave, quindi ottenere tutte le chiavi non rallenta l'avvio. Le chiavi vengono caricate pigramente. Cioè, la chiave stessa viene caricata dal Vault solo quando è effettivamente necessaria. Una volta scaricata, la chiave viene memorizzata nella cache in modo che non sia necessario accedervi in ​​futuro tramite connessioni TLS al Vault Server. Successivamente, esaminiamo quali informazioni sono presenti nell'archivio chiavi.

Le informazioni chiave contengono quanto segue:

  • codice identificativo della chiave — identificatore chiave, ad esempio:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • tipo di chiave — tipo di chiave in base all'algoritmo di crittografia utilizzato, valori possibili: “AES”, “RSA” o “DSA”.
  • lunghezza chiave — lunghezza della chiave in byte, AES: 16, 24 o 32, RSA 128, 256, 512 e DSA 128, 256 o 384.
  • Utente -proprietario della chiave. Se la chiave è di sistema, ad esempio Master Key, questo campo è vuoto. Se una chiave viene creata utilizzando keyring_udf, questo campo identifica il proprietario della chiave.
  • la chiave stessa

La chiave è identificata univocamente dalla coppia: key_id, user.

Esistono anche differenze nella memorizzazione e nell'eliminazione delle chiavi.

L'archiviazione dei file è più veloce. Potresti pensare che un archivio di chiavi stia semplicemente scrivendo la chiave su un file una volta, ma no, c'è altro da fare qui. Ogni volta che viene apportata una modifica all'archiviazione dei file, viene prima creata una copia di backup di tutto il contenuto. Diciamo che il file si chiama my_biggest_secrets, quindi la copia di backup sarà my_biggest_secrets.backup. Successivamente, la cache viene modificata (le chiavi vengono aggiunte o eliminate) e, se tutto va a buon fine, la cache viene reimpostata su un file. In rari casi, ad esempio in caso di guasto del server, potresti visualizzare questo file di backup. Il file di backup viene eliminato al successivo caricamento delle chiavi (solitamente dopo il riavvio del server).

Quando si salva o si elimina una chiave in un server di archiviazione, lo spazio di archiviazione deve connettersi al server MySQL con i comandi "invia la chiave" / "richiedi cancellazione della chiave".

Torniamo alla velocità di avvio del server. Oltre al fatto che la velocità di avvio è influenzata dal vault stesso, c'è anche il problema di quante chiavi dal vault devono essere recuperate all'avvio. Naturalmente, questo è particolarmente importante per l'archiviazione del server. All'avvio, il server controlla quale chiave è richiesta per le tabelle/tablespace crittografati e richiede la chiave dall'archivio. Su un server "pulito" con crittografia Master Key, deve essere presente una Master Key, che deve essere recuperata dall'archivio. Tuttavia, potrebbe essere necessario un numero maggiore di chiavi, ad esempio, quando il server di backup ripristina un backup dal server primario. In tali casi è opportuno prevedere la rotazione della Chiave Master. Questo argomento verrà trattato più in dettaglio negli articoli futuri, anche se qui vorrei sottolineare che un server che utilizza più chiavi master potrebbe richiedere un po' più tempo per l'avvio, soprattutto quando si utilizza un archivio chiavi lato server.

Ora parliamo ancora un po' di keyring_file. Durante lo sviluppo di keyring_file, ero anche preoccupato di come verificare le modifiche di keyring_file mentre il server era in esecuzione. Nella versione 5.7 il controllo veniva eseguito in base alle statistiche dei file, il che non era una soluzione ideale, mentre nella versione 8.0 è stato sostituito con un checksum SHA256.

La prima volta che esegui keyring_file, vengono calcolate le statistiche del file e un checksum, che vengono ricordati dal server, e le modifiche vengono applicate solo se corrispondono. Quando il file cambia, il checksum viene aggiornato.

Abbiamo già trattato molte domande sugli archivi di chiavi. Tuttavia, c’è un altro argomento importante che spesso viene dimenticato o frainteso: la condivisione delle chiavi tra server.

Ciò che intendo? Ciascun server (ad esempio Percona Server) nel cluster deve avere una posizione separata sul Vault Server in cui Percona Server deve archiviare le proprie chiavi. Ogni Chiave Master salvata nello storage contiene all'interno del suo identificatore il GUID del Percona Server. Perché è importante? Immagina di avere un solo Vault Server e che tutti i Percona Server nel cluster utilizzino quel singolo Vault Server. Il problema sembra ovvio. Se tutti i server Percona utilizzassero una chiave master senza identificatori univoci, come id = 1, id = 2, ecc., tutti i server nel cluster utilizzerebbero la stessa chiave master. Ciò che fornisce il GUID è la distinzione tra i server. Perché allora parlare di condivisione delle chiavi tra server se esiste già un GUID univoco? C'è un altro plugin: keyring_udf. Con questo plugin, l'utente del tuo server può archiviare le proprie chiavi sul server Vault. Il problema si verifica quando un utente crea una chiave sul server1, ad esempio, e poi tenta di creare una chiave con lo stesso ID sul server2, ad esempio:

--server1:
select keyring_key_store('ROB_1','AES',"123456789012345");
1
--1 значит успешное завершение
--server2:
select keyring_key_store('ROB_1','AES',"543210987654321");
1

Aspettare. Entrambi i server utilizzano lo stesso Vault Server, la funzione keyring_key_store non dovrebbe fallire sul server2? È interessante notare che, se provi a fare lo stesso su un server, riceverai un errore:

--server1:
select keyring_key_store('ROB_1','AES',"123456789012345");
1
select keyring_key_store('ROB_1','AES',"543210987654321");
0

Esatto, ROB_1 esiste già.

Parliamo prima del secondo esempio. Come abbiamo detto prima, keyring_vault o qualsiasi altro plugin per portachiavi memorizza nella cache tutti gli ID delle chiavi in ​​memoria. Pertanto, dopo aver creato una nuova chiave, ROB_1 viene aggiunto al server1 e, oltre a inviare questa chiave a Vault, la chiave viene anche aggiunta alla cache. Ora, quando proviamo ad aggiungere la stessa chiave una seconda volta, keyring_vault controlla se la chiave esiste nella cache e genera un errore.

Nel primo caso la situazione è diversa. Server1 e server2 hanno cache separate. Dopo aver aggiunto ROB_1 alla cache delle chiavi sul server1 e al server del Vault, la cache delle chiavi sul server2 non è sincronizzata. Non è presente alcuna chiave ROB_2 nella cache sul server1. Pertanto, la chiave ROB_1 viene scritta nel keyring_key_store e nel server del Vault, che in realtà sovrascrive (!) il valore precedente. Ora la chiave ROB_1 sul server del Vault è 543210987654321. È interessante notare che il server del Vault non blocca tali azioni e sovrascrive facilmente il vecchio valore.

Ora possiamo capire perché il partizionamento del server in Vault può essere importante: quando si utilizza keyring_udf e si desidera archiviare le chiavi in ​​Vault. Come ottenere questa separazione su un server Vault?

Esistono due modi per partizionare in Vault. È possibile creare punti di montaggio diversi per ciascun server oppure utilizzare percorsi diversi all'interno dello stesso punto di montaggio. Ciò è meglio illustrato con esempi. Quindi diamo prima un'occhiata ai singoli punti di montaggio:

--server1:
vault_url = http://127.0.0.1:8200
secret_mount_point = server1_mount
token = (...)
vault_ca = (...)

--server2:
vault_url = http://127.0.0.1:8200
secret_mount_point = sever2_mount
token = (...)
vault_ca = (...)

Qui puoi vedere che server1 e server2 utilizzano punti di montaggio diversi. Quando si dividono i percorsi, la configurazione sarà simile a questa:

--server1:
vault_url = http://127.0.0.1:8200
secret_mount_point = mount_point/server1
token = (...)
vault_ca = (...)
--server2:
vault_url = http://127.0.0.1:8200
secret_mount_point = mount_point/sever2
token = (...)
vault_ca = (...)

In questo caso, entrambi i server utilizzano lo stesso punto di montaggio "mount_point", ma percorsi diversi. Quando crei il primo segreto sul server1 utilizzando questo percorso, il server del Vault crea automaticamente una directory "server1". Per server2 tutto è simile. Quando elimini l'ultimo segreto in mount_point/server1 o mount_point/server2, il server del Vault elimina anche quelle directory. Nel caso in cui utilizzi la separazione dei percorsi, devi creare un solo punto di montaggio e modificare i file di configurazione in modo che i server utilizzino percorsi separati. È possibile creare un punto di montaggio utilizzando una richiesta HTTP. Usando CURL questo può essere fatto in questo modo:

curl -L -H "X-Vault-Token: TOKEN" –cacert VAULT_CA
--data '{"type":"generic"}' --request POST VAULT_URL/v1/sys/mounts/SECRET_MOUNT_POINT

Tutti i campi (TOKEN, VAULT_CA, VAULT_URL, SECRET_MOUNT_POINT) corrispondono ai parametri del file di configurazione. Naturalmente, puoi utilizzare le utilità di Vault per fare lo stesso. Ma è più semplice automatizzare la creazione di un punto di montaggio. Spero che queste informazioni ti siano utili e ci vediamo nei prossimi articoli di questa serie.

Crittografia in MySQL: keystore

Per saperne di più:

Fonte: habr.com

Aggiungi un commento