Enkripcija u MySQL: skladište ključeva

Uoči početka novog upisa na tečaj «Baze podataka» pripremili smo za vas prijevod korisnog članka.

Enkripcija u MySQL: skladište ključeva

Transparentno šifriranje podataka (Transparent Data Encryption, TDE) uvedeno je u Percona Server for MySQL i MySQL već dosta davno. No, jeste li se ikada zapitali kako to funkcionira ispod haube i kakav utjecaj TDE može imati na vaš server? U ovoj seriji članaka istražit ćemo kako TDE funkcionira iznutra. Počet ćemo od pohrane ključeva, budući da je ona potrebna za rad svakog šifriranja. Zatim ćemo detaljno razmotriti kako šifriranje radi u Percona Server for MySQL/MySQL i koje dodatne mogućnosti postoje u Percona Server for MySQL.

MySQL Keyring

Keyring su dodaci koji omogućuju serveru zahtijevanje, stvaranje i brisanje ključeva u lokalnoj datoteci (keyring_file) ili na udaljenom serveru (na primjer, u HashiCorp Vault). Ključevi se uvijek lokalno keširaju kako bi se ubrzalo njihovo preuzimanje.

Dodaci se mogu podijeliti u dvije kategorije:

  • Lokalna pohrana. Na primjer, lokalna datoteka (nazivamo je pohranom ključeva temeljenom na datoteci, file-based keyring).
  • Udaljena pohrana. Na primjer, Vault Server (nazivamo ga pohranom ključeva temeljenom na serveru, server-based keyring).

Ova podjela je važna jer se različiti tipovi pohrana ponašaju malo drugačije ne samo pri pohranjivanju i preuzimanju ključeva, već i pri pokretanju.

Kada se koristi pohrana temeljena na datoteci, pri pokretanju se učitava sav sadržaj pohrane u keš: key id, key user, key type i sam ključ.

U slučaju pohrane temeljenje na serveru (kao što je server Vault), pri pokretanju se učitava samo key id i key user, stoga preuzimanje svih ključeva ne usporava pokretanje. Ključevi se učitavaju lijeno. To znači da se sam ključ učitava iz Vault-a samo kada zaista zatreba. Nakon učitavanja, ključ se kešira u memoriji, kako ne bi bilo potrebe ponovno se obraćati za njim putem TLS veza na Vault Server. Dalje ćemo razmotriti koje informacije sadrži pohrana ključeva.

Informacije o ključu sadrže sljedeće:

  • key id — identifikator ključa, na primjer:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • key type — tip ključa, temeljen na korištenom algoritmu šifriranja, moguće vrijednosti: «AES», «RSA» ili «DSA».
  • key length — duljina ključa u bajtovima, AES: 16, 24 ili 32, RSA 128, 256, 512 i DSA 128, 256 ili 384.
  • korisnik — vlasnik ključa. Ako je ključ sistemski, na primjer, Master Key, ovo polje će biti prazno. Ako je ključ kreiran pomoću keyring_udf, ovo polje označava vlasnika ključa.
  • sam ključ

Ključ se jedinstveno identificira parom: key_id, user.

Također postoje razlike u pohranjivanju i brisanju ključeva.

Datotečko pohranjivanje radi brže. Možemo pretpostaviti da je pohrana ključeva jednostavna jednokratna upisivanje ključa u datoteku, ali nije — ovdje se odvija više operacija. Prilikom svake modifikacije datotečkog pohranjivanja prvo se izrađuje sigurnosna kopija cijelog sadržaja. Recimo da datoteka zove my_biggest_secrets, tada će sigurnosna kopija biti my_biggest_secrets.backup. Zatim se mijenja predmemorija (dodaju ili uklanjaju ključevi) i, ako je sve uspješno provedeno, predmemorija se vraća u datoteku. U rijetkim slučajevima, kao što je kvar poslužitelja, možete vidjeti ovu datoteku sigurnosne kopije. Datoteka sigurnosne kopije se briše pri sljedećem učitavanju ključeva (obično nakon ponovnog pokretanja poslužitelja).

Prilikom spremanja ili brisanja ključa u poslužiteljskom pohranjivanju, pohrana se mora povezati s MySQL poslužiteljem s naredbama "pošalji ključ" / "zatraži brisanje ključa".

Vratimo se brzini pokretanja poslužitelja. Osim što na brzinu pokretanja utječe samo pohranjivanje, postoji i pitanje koliko ključeva iz pohrane treba dobiti prilikom pokretanja. Naravno, to je posebno važno za poslužiteljske pohrane. Prilikom pokretanja, poslužitelj provjerava koji ključ je potreban za šifrirane tablice / tablične prostore i zatraži ključ iz pohrane. Na "čistom" poslužitelju s Master Key — šifriranjem trebao bi biti jedan Master Key koji treba izvući iz pohrane. Međutim, može biti potrebno i više ključeva, na primjer, kada se na rezervnom poslužitelju obnavlja sigurnosna kopija s glavnog poslužitelja. U takvim slučajevima treba predvidjeti rotaciju Master Key. O tome će se detaljnije raspravljati u budućim člancima, iako bih ovdje želio napomenuti da poslužitelj koji koristi više Master Key može se pokretati malo duže, posebno pri korištenju poslužiteljske pohrane ključeva.

Sada razgovarajmo malo više o keyring_file. Kada sam razvijao keyring_file, također me brinulo kako provjeriti promjenu keyring_file tijekom rada poslužitelja. U 5.7 provjera se vršila na temelju statistike datoteke, što nije bilo idealno rješenje, i u 8.0 zamijenjeno je kontrolnom sumom SHA256.

Pri prvom pokretanju keyring_file izračunava se statistika datoteke i kontrolna suma, koje poslužitelj pohranjuje, a promjene se rade samo ako se podudaraju. Kada se datoteka promijeni, kontrolna suma se ažurira.

Već smo razmotrili mnoga pitanja o spremištima ključeva. Međutim, postoji još jedna važna tema o kojoj se često zaboravlja ili se pogrešno razumije — razdvajanje ključeva po poslužiteljima.

Što mislim? Svaki poslužitelj (npr. Percona Server) u klasteru mora imati posebno mjesto na poslužitelju Vault, gdje Percona Server treba pohranjivati svoje ključeve. U svakom Master Key pohranjenom u spremištu nalazi se GUID poslužitelja Percona Server unutar svog identifikatora. Zašto je to važno? Zamislite da imate samo jedan Vault Server i svi Percona Server u klasteru koriste taj jedan Vault Server. Problem se čini očitim. Da su svi Percona Server koristili Master Key bez jedinstvenih identifikatora, npr. id = 1, id = 2 itd., svi bi poslužitelji u klasteru koristili isti Master Key. A to je ono što osigurava GUID — razdvajanje između poslužitelja. Zašto onda govoriti o razdvajanju ključeva između poslužitelja, ako već postoji jedinstveni GUID? Postoji još jedan dodatak — keyring_udf. Uz pomoć ovog dodatka korisnik vašeg poslužitelja može pohranjivati svoje ključeve na poslužitelju Vault. Problem nastaje kada korisnik stvara ključ, npr. na poslužitelju server1, a zatim pokušava stvoriti ključ s istim identifikatorom na server2, na primjer:

--server1:
select keyring_key_store('ROB_1','AES',"123456789012345");
1
--1 znači uspješan završetak
--server2:
select keyring_key_store('ROB_1','AES',"543210987654321");
1

Čekajte. Obojica poslužitelja koriste isti Vault Server, zar funkcija keyring_key_store ne bi trebala završiti s greškom na poslužitelju server2? Zanimljivo je da ako pokušate učiniti isto na jednom poslužitelju, dobit ćete grešku:

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

Točno, ROB_1 već postoji.

Prvo ćemo razgovarati o drugom primjeru. Kao što smo ranije spomenuli, keyring_vault ili bilo koji drugi spremnik (keyring) kešira sve identifikatore ključeva u memoriji. Tako, nakon što se novi ključ kreira, ROB_1 se dodaje na server1, i osim slanja tog ključa u Vault, ključ se također dodaje u keš. Sada, kada pokušavamo dodati taj isti ključ drugi put, keyring_vault provjerava postoji li taj ključ u kešu i izbacuje grešku.

U prvom slučaju situacija je drugačija. Na serverima server1 i server2 postoje odvojeni keševi. Nakon dodavanja ROB_1 u keš ključeva na serveru server1 i serveru Vault, keš ključeva na serveru server2 nije sinkroniziran. U kešu na serveru server2 nema ključa ROB_1. Tako se ključ ROB_1 zapisuje u keyring_key_store i na server Vault, koji zapravo prepisuje (!) prethodnu vrijednost. Sada je ključ ROB_1 na serveru Vault jednak 543210987654321. Zanimljivo je da server Vault ne blokira takve radnje i jednostavno prepisuje staru vrijednost.

Sada vidimo zašto je odvajanje po serverima na Vaultu bitno — kada koristite keyring_udf i želite pohraniti ključeve u Vault. Kako osigurati takvo odvajanje na serveru Vault?

Postoje dva načina odvajanja na Vaultu. Možete stvoriti različite točke montiranja za svaki server ili koristiti različite puteve unutar jedne točke montiranja. Najbolje je to pokazati na primjerima. Dakle, prvo ćemo pogledati odvojene točke montiranja:

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

Ovdje je vidljivo da server1 i server2 koriste različite točke montiranja. Kada su putevi odvojeni, konfiguracija će izgledati ovako:

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

U ovom slučaju, oba servera koriste istu tačku montiranja «mount_point», ali različite putanje. Kada se prvi tajni podatak kreira na serveru server1 na ovoj putanji, server Vault automatski kreira direktorijum «server1». Za server2 je sve isto. Kada obrišete poslednji tajni podatak u mount_point/server1 ili mount_point/server2, server Vault takođe briše te direktorijume. U slučaju da koristite razdvajanje putanja, morate napraviti samo jednu tačku montiranja i izmeniti konfiguracione datoteke kako bi serveri koristili odvojene putanje. Tačku montiranja možete kreirati putem HTTP zahteva. Ovo je moguće uraditi sa CURL-om na sledeći način:

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

Sva polja (TOKEN, VAULT_CA, VAULT_URL, SECRET_MOUNT_POINT) odgovaraju parametrima datoteke konfiguracije. Naravno, možete koristiti Vault alate za postizanje istog. Ali je tako lakše automatizovati kreiranje tačke montiranja. Nadam se da će vam ove informacije biti korisne, i vidimo se u sledećim člancima ove serije.

Enkripcija u MySQL: skladište ključeva

Čitajte više:

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster