Šifriranje v MySQL: shramba ključev

V pričakovanju začetka novega vpisa na tečaj "Baza podatkov" Za vas smo pripravili prevod uporabnega članka.

Šifriranje v MySQL: shramba ključev

Pregledno šifriranje podatkov (TDE) se je pojavilo v Strežnik Percona za MySQL in MySQL kar nekaj časa. Toda ali ste kdaj razmišljali o tem, kako deluje pod pokrovom in kakšen vpliv ima lahko TDE na vaš strežnik? V tej seriji člankov si bomo ogledali, kako TDE deluje interno. Začnimo s shranjevanjem ključev, saj je to potrebno za vsako šifriranje. Nato si bomo podrobneje ogledali, kako deluje šifriranje v strežniku Percona za MySQL/MySQL in katere dodatne funkcije ima strežnik Percona za MySQL.

Obesek za ključe MySQL

Keyring so vtičniki, ki strežniku omogočajo poizvedovanje, ustvarjanje in brisanje ključev v lokalni datoteki (keyring_file) ali na oddaljenem strežniku (kot je HashiCorp Vault). Ključi so vedno lokalno predpomnjeni, da se pospeši njihovo iskanje.

Vtičnike lahko razdelimo v dve kategoriji:

  • Lokalna shramba. Na primer lokalna datoteka (temu pravimo datotečni obesek ključev).
  • Oddaljeno shranjevanje. Na primer Vault Server (temu pravimo strežniški obesek za ključe).

Ta ločitev je pomembna, ker se različne vrste pomnilnika obnašajo nekoliko drugače, ne samo pri shranjevanju in pridobivanju ključev, ampak tudi pri njihovem izvajanju.

Pri uporabi pomnilnika datotek se ob zagonu v predpomnilnik naloži celotna vsebina pomnilnika: ID ključa, uporabnik ključa, tip ključa in sam ključ.

V primeru strežniške shrambe (kot je strežnik Vault Server) se ob zagonu naložita samo ID ključa in uporabnik ključa, zato pridobivanje vseh ključev ne upočasni zagona. Ključi se nalagajo leno. To pomeni, da se sam ključ naloži iz trezorja le, ko je dejansko potreben. Ko je ključ prenesen, je predpomnjen v pomnilniku, tako da v prihodnje do njega ni treba dostopati prek povezav TLS s strežnikom Vault. Nato si poglejmo, katere informacije so prisotne v shrambi ključev.

Ključne informacije vsebujejo naslednje:

  • ID ključa — ključni identifikator, na primer:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • tip ključa — vrsta ključa na podlagi uporabljenega šifrirnega algoritma, možne vrednosti: „AES“, „RSA“ ali „DSA“.
  • dolžina ključa — dolžina ključa v bajtih, AES: 16, 24 ali 32, RSA 128, 256, 512 in DSA 128, 256 ali 384.
  • uporabnik - lastnik ključa. Če je ključ sistemski, na primer glavni ključ, je to polje prazno. Če je ključ ustvarjen z uporabo keyring_udf, potem to polje identificira lastnika ključa.
  • sam ključ

Ključ je enolično identificiran s parom: key_id, user.

Razlike so tudi pri shranjevanju in brisanju ključev.

Shranjevanje datotek je hitrejše. Morda mislite, da shramba ključev preprosto enkrat zapiše ključ v datoteko, vendar ne, tukaj se dogaja več. Kadar koli se izvede sprememba shranjevanja datotek, se najprej ustvari varnostna kopija vse vsebine. Recimo, da se datoteka imenuje my_biggest_secrets, potem bo varnostna kopija my_biggest_secrets.backup. Nato se spremeni predpomnilnik (ključi se dodajo ali izbrišejo) in če je vse uspešno, se predpomnilnik ponastavi na datoteko. V redkih primerih, kot je okvara strežnika, boste morda videli to varnostno kopijo. Datoteka varnostne kopije se izbriše, ko se naslednjič naložijo ključi (običajno po ponovnem zagonu strežnika).

Pri shranjevanju ali brisanju ključa v strežniškem pomnilniku se mora pomnilnik povezati s strežnikom MySQL z ukazi “pošlji ključ” / “zahtevaj izbris ključa”.

Vrnimo se k hitrosti zagona strežnika. Poleg dejstva, da na hitrost zagona vpliva sam trezor, obstaja tudi vprašanje, koliko ključev iz trezorja je treba pridobiti ob zagonu. Seveda je to še posebej pomembno za strežniško shranjevanje. Ob zagonu strežnik preveri, kateri ključ je potreben za šifrirane tabele/prostore tabel, in zahteva ključ iz pomnilnika. Na "čistem" strežniku s šifriranjem z glavnim ključem mora obstajati en glavni ključ, ki ga je treba pridobiti iz pomnilnika. Vendar pa bo morda potrebno večje število ključev, na primer, ko rezervni strežnik obnavlja varnostno kopijo iz primarnega strežnika. V takih primerih je treba zagotoviti rotacijo glavnega ključa. To bo podrobneje obravnavano v prihodnjih člankih, čeprav bi tukaj rad opozoril, da lahko zagon strežnika, ki uporablja več glavnih ključev, traja nekoliko dlje, zlasti če uporabljate shrambo ključev na strani strežnika.

Zdaj pa se pogovorimo še malo o keyring_file. Ko sem razvijal keyring_file, me je skrbelo tudi, kako preveriti spremembe keyring_file, medtem ko strežnik deluje. V 5.7 se je preverjanje izvajalo na podlagi statistike datotek, kar ni bila idealna rešitev, v 8.0 pa je bilo nadomeščeno s kontrolno vsoto SHA256.

Ko prvič zaženete keyring_file, se izračuna statistika datoteke in kontrolna vsota, ki si ju zapomni strežnik, spremembe pa se uporabijo le, če se ujemajo. Ko se datoteka spremeni, se kontrolna vsota posodobi.

Zajeli smo že veliko vprašanj o trezorjih ključev. Vendar obstaja še ena pomembna tema, ki je pogosto pozabljena ali napačno razumljena: deljenje ključev med strežniki.

Kaj mislim? Vsak strežnik (na primer strežnik Percona) v gruči mora imeti ločeno lokacijo na strežniku Vault, v katerem mora strežnik Percona shraniti svoje ključe. Vsak glavni ključ, shranjen v shrambi, vsebuje GUID strežnika Percona znotraj svojega identifikatorja. Zakaj je pomembno? Predstavljajte si, da imate samo en strežnik Vault in vsi strežniki Percona v gruči uporabljajo ta en sam strežnik Vault. Težava se zdi očitna. Če bi vsi strežniki Percona uporabljali glavni ključ brez edinstvenih identifikatorjev, kot je id = 1, id = 2 itd., bi vsi strežniki v gruči uporabljali isti glavni ključ. Kar zagotavlja GUID, je razlikovanje med strežniki. Zakaj potem govoriti o skupni rabi ključev med strežniki, če edinstven GUID že obstaja? Obstaja še en vtičnik - keyring_udf. S tem vtičnikom lahko uporabnik vašega strežnika shrani svoje ključe na strežnik Vault. Težava se pojavi, ko uporabnik na primer ustvari ključ na strežniku1 in nato poskuša ustvariti ključ z istim ID-jem na primer na strežniku2:

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

Počakaj. Oba strežnika uporabljata isti strežnik Vault, ali ne bi morala funkcija keyring_key_store odpovedati na strežniku2? Zanimivo je, da če poskusite narediti isto na enem strežniku, boste prejeli napako:

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

Tako je, ROB_1 že obstaja.

Najprej se pogovorimo o drugem primeru. Kot smo že povedali, keyring_vault ali kateri koli drug vtičnik za obesek ključev predpomni vse ID-je ključev v pomnilnik. Torej se po ustvarjanju novega ključa ROB_1 doda strežniku1 in poleg tega, da se ta ključ pošlje v Vault, se ključ doda tudi v predpomnilnik. Zdaj, ko poskušamo isti ključ dodati drugič, keyring_vault preveri, ali ključ obstaja v predpomnilniku, in vrže napako.

V prvem primeru je situacija drugačna. Strežnik1 in strežnik2 imata ločena predpomnilnika. Po dodajanju ROB_1 v predpomnilnik ključev na strežniku1 in strežniku Vault predpomnilnik ključev na strežniku2 ni sinhroniziran. V predpomnilniku na strežniku2 ni ključa ROB_1. Tako se ključ ROB_1 zapiše v keyring_key_store in v strežnik Vault, ki dejansko prepiše (!) prejšnjo vrednost. Zdaj je ključ ROB_1 na strežniku Vault 543210987654321. Zanimivo je, da strežnik Vault ne blokira takih dejanj in zlahka prepiše staro vrednost.

Zdaj lahko vidimo, zakaj je particioniranje strežnika v Vaultu lahko pomembno – ko uporabljate keyring_udf in želite shraniti ključe v Vault. Kako doseči to ločitev na strežniku Vault?

Obstajata dva načina za particijo v Vault. Ustvarite lahko različne točke namestitve za vsak strežnik ali uporabite različne poti znotraj iste točke namestitve. To je najbolje ponazoriti s primeri. Zato si najprej poglejmo posamezne točke pritrditve:

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

Tukaj lahko vidite, da server1 in server2 uporabljata različni točki priklopa. Pri razdelitvi poti bo konfiguracija videti takole:

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

V tem primeru oba strežnika uporabljata isto točko priklopa "mount_point", vendar različni poti. Ko ustvarite prvo skrivnost na server1 s to potjo, strežnik Vault samodejno ustvari imenik »server1«. Za server2 je vse podobno. Ko izbrišete zadnjo skrivnost v mount_point/server1 ali mount_point/server2, strežnik Vault izbriše tudi te imenike. Če uporabljate ločevanje poti, morate ustvariti samo eno točko vpetja in spremeniti konfiguracijske datoteke, tako da strežniki uporabljajo ločene poti. Točko priklopa lahko ustvarite z uporabo zahteve HTTP. Z uporabo CURL je to mogoče narediti takole:

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

Vsa polja (TOKEN, VAULT_CA, VAULT_URL, SECRET_MOUNT_POINT) ustrezajo parametrom konfiguracijske datoteke. Seveda lahko za isto storite tudi pripomočke Vault. Vendar je lažje avtomatizirati ustvarjanje točke namestitve. Upam, da so vam te informacije koristne in se vidimo v naslednjih člankih te serije.

Šifriranje v MySQL: shramba ključev

Preberi več:

Vir: www.habr.com

Dodaj komentar