Crittografia in MySQL: archivio delle chiavi

In vista dell'inizio di un nuovo ciclo del corso «Basi di dati» abbiamo preparato per voi la traduzione di un articolo utile.

Crittografia in MySQL: archivio delle chiavi

La crittografia dei dati trasparente (Transparent Data Encryption, TDE) è disponibile in Percona Server for MySQL e MySQL da tempo. Ma vi siete mai chiesti come funziona sotto il cofano e quale impatto può avere TDE sul vostro server? In questa serie di articoli, esamineremo come TDE opera internamente. Iniziamo con la gestione delle chiavi, poiché è necessaria per qualsiasi tipo di crittografia. Successivamente, esamineremo in dettaglio come funziona la crittografia in Percona Server for MySQL/MySQL e quali funzionalità aggiuntive sono disponibili in Percona Server for MySQL.

MySQL Keyring

Keyring è un plugin che consente al server di richiedere, creare e rimuovere chiavi in un file locale (keyring_file) o su un server remoto (ad esempio, in HashiCorp Vault). Le chiavi vengono sempre memorizzate nella cache localmente per accelerarne l'accesso.

I plugin possono essere suddivisi in due categorie:

  • Archiviazione locale. Ad esempio, un file locale (chiamiamo questo archiviazione di chiavi basata su file, file-based keyring).
  • Archiviazione remota. Ad esempio, Vault Server (chiamiamo questo archiviazione di chiavi basata su server, server-based keyring).

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

Quando si utilizza l'archiviazione su file, all'avvio viene caricato tutto il contenuto dell'archiviazione: key id, key user, key type e la chiave stessa.

Nel caso dell'archiviazione su server (ad esempio, un server Vault), all'avvio vengono caricati solo key id e key user, quindi il recupero di tutte le chiavi non rallenta l'avvio. Le chiavi vengono caricate in modo pigro, cioè la chiave stessa viene caricata da Vault solo quando è effettivamente necessaria. Dopo il caricamento, la chiave viene memorizzata nella cache in memoria, per evitare in futuro di doverla richiedere tramite connessioni TLS al server Vault. Vediamo ora quali informazioni sono presenti nell'archiviazione delle chiavi.

Le informazioni sulla chiave contengono quanto segue:

  • key id — identificatore della chiave, ad esempio:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • key type — tipo di chiave, basato sull'algoritmo di crittografia utilizzato, possibili valori: «AES», «RSA» o «DSA».
  • key length — 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, la Master Key, questo campo è vuoto. Se la chiave viene creata utilizzando keyring_udf, questo campo indica il proprietario della chiave.
  • la chiave stessa

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

Ci sono anche differenze nella memorizzazione e nella rimozione delle chiavi.

Il file storage funziona più velocemente. Si potrebbe supporre che lo storage delle chiavi sia una semplice registrazione singola della chiave in un file, ma non è così: ci sono più operazioni in corso. Per ogni modifica dello storage dei file, viene prima creata una copia di backup di tutto il contenuto. Supponiamo che il file si chiami my_biggest_secrets, la copia di backup sarà my_biggest_secrets.backup. Poi viene aggiornato la cache (vengono aggiunte o rimosse chiavi) e, se tutto è andato a buon fine, la cache viene riportata nel file. In rari casi, come un guasto del server, puoi vedere questo file di backup. Il file di backup viene eliminato al prossimo caricamento delle chiavi (di solito dopo il riavvio del server).

Quando si salva o si elimina una chiave nel keystore del server, il keystore deve connettersi al server MySQL con i comandi "invia la chiave" / "richiedi l'eliminazione della chiave".

Torniamo alla velocità di avvio del server. Oltre al fatto che la velocità di avvio è influenzata dal keystore stesso, c'è anche la questione di quante chiavi dal keystore devono essere ottenute all'avvio. Questo è particolarmente importante per i keystore dei server. Durante l'avvio, il server verifica quale chiave è necessaria per le tabelle cifrate / gli spazi delle tabelle e richiede la chiave dal keystore. Su un server "pulito" con una Master Key — la crittografia deve avere una sola Master Key, che deve essere estratta dal keystore. Tuttavia, potrebbe essere necessaria anche una maggiore quantità di chiavi, ad esempio, quando un server di backup ripristina un backup dal server principale. In tali casi, è necessario prevedere la rotazione della Master Key. Questo sarà approfondito in articoli futuri, anche se qui vorrei sottolineare che un server che utilizza più Master Key potrebbe avviarsi leggermente più a lungo, soprattutto quando utilizza un keystore server.

Ora parliamo un po' di più su keyring_file. Quando ho sviluppato keyring_file, ero preoccupato anche su come controllare le modifiche a keyring_file durante il funzionamento del server. Nella versione 5.7 il controllo veniva effettuato in base alle statistiche del file, che non era una soluzione ideale, ed è stato sostituito nella versione 8.0 con un checksum SHA256.

Al primo avvio, keyring_file calcola le statistiche del file e il checksum, che vengono memorizzati dal server, e le modifiche vengono apportate solo se coincidono. Quando il file viene modificato, il checksum viene aggiornato.

Abbiamo già trattato molte questioni relative ai key store. Tuttavia, c'è un altro argomento importante che spesso viene dimenticato o malinteso: la separazione delle chiavi per server.

Cosa intendo? Ogni server (ad esempio, Percona Server) in un cluster deve avere uno spazio dedicato sul server Vault, dove il Percona Server deve memorizzare le proprie chiavi. Ogni Master Key salvato nel deposito contiene il GUID del server Percona Server all'interno del suo identificatore. Perché è importante? Immagina di avere un solo Vault Server e tutti i Percona Server nel cluster utilizzano questo unico Vault Server. Il problema è evidente. Se tutti i Percona Server utilizzassero un Master Key senza identificatori unici, ad esempio, id = 1, id = 2, ecc., tutti i server nel cluster utilizzerebbero la stessa Master Key. Questo è ciò che fornisce il GUID: una distinzione tra i server. Perché allora discutere della separazione delle chiavi tra i server, se esiste già un GUID unico? C'è un altro plugin: keyring_udf. Con questo plugin, l'utente del tuo server può memorizzare le proprie chiavi sul server Vault. Il problema si presenta quando l'utente crea una chiave, ad esempio, sul server server1 e poi tenta di creare una chiave con lo stesso identificatore su server2, ad esempio:

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

Attendere. Entrambi i server utilizzano lo stesso Vault Server, non dovrebbe la funzione keyring_key_store terminare con un errore sul server server2? È interessante notare che se si tenta di fare lo stesso su un singolo server, si otterrà un errore:

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

Corretto, ROB_1 esiste già.

Discutiamo prima del secondo esempio. Come abbiamo già detto in precedenza, keyring_vault o qualsiasi altro plugin di archiviazione (keyring) memorizza nella cache tutti gli identificatori delle chiavi in memoria. Pertanto, dopo aver creato una nuova chiave, ROB_1 viene aggiunto a server1 e, oltre a inviare questa chiave a Vault, la chiave viene anche aggiunta alla cache. Ora, quando cerchiamo di aggiungere la stessa chiave una seconda volta, keyring_vault controlla se quella chiave esiste nella cache e restituisce un errore.

Nel primo caso la situazione è diversa. Nei server server1 e server2 ci sono cache separate. Dopo aver aggiunto ROB_1 alla cache delle chiavi sul server server1 e sul server Vault, la cache delle chiavi su server2 non è sincronizzata. Nella cache di server2 non esiste la chiave ROB_1. Pertanto, la chiave ROB_1 viene scritta nel keyring_key_store e sul server Vault, il quale sovrascrive (!) il valore precedente. Ora la chiave ROB_1 sul server Vault è pari a 543210987654321. È interessante notare che il server Vault non blocca tali operazioni e sovrascrive tranquillamente il valore precedente.

Ora vediamo perché la separazione tra i server su Vault può essere importante — quando si utilizza keyring_udf e si vogliono memorizzare le chiavi in Vault. Come si può garantire tale separazione sul server Vault?

Ci sono due modi per separare su Vault. È possibile creare punti di montaggio diversi per ogni server o utilizzare percorsi differenti all'interno di un unico punto di montaggio. È meglio mostrare questo con degli esempi. Quindi, iniziamo a guardare prima i punti di montaggio separati:

--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 = server2_mount
token = (...)
vault_ca = (...)

Qui si vede che server1 e server2 utilizzano punti di montaggio diversi. Quando si separano i percorsi, la configurazione apparirà come segue:

--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/server2
token = (...)
vault_ca = (...)

In questo caso, entrambi i server utilizzano lo stesso punto di montaggio "mount_point", ma percorsi diversi. Quando si crea il primo segreto sul server server1 in questo percorso, il server Vault crea automaticamente la directory "server1". Per server2 è lo stesso. Quando si elimina l'ultimo segreto in mount_point/server1 o mount_point/server2, il server Vault elimina anche queste directory. Se stai utilizzando la separazione dei percorsi, devi creare solo un punto di montaggio e modificare i file di configurazione affinché i server utilizzino percorsi separati. Il punto di montaggio può essere creato attraverso una richiesta HTTP. Con CURL è possibile farlo nel seguente 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) rispettano i parametri del file di configurazione. Certamente, è possibile utilizzare gli strumenti di Vault per fare la stessa cosa. Ma è più semplice automatizzare la creazione del punto di montaggio. Spero che queste informazioni siano utili e ci vediamo nei prossimi articoli di questa serie.

Crittografia in MySQL: archivio delle chiavi

Leggi di più:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster