Kryptering i MySQL: nøglelagring

I forklaringen af den nye optagelse til kurset «Databaser» vi har forberedt en oversættelse af en nyttig artikel til dig.

Kryptering i MySQL: nøglelagring

Transparent datakryptering (Transparent Data Encryption, TDE) er blevet introduceret i Percona Server for MySQL og MySQL for længe siden. Men har du nogensinde tænkt over, hvordan det fungerer under overfladen, og hvilken indvirkning TDE kan have på din server? I denne artikelserie vil vi se på, hvordan TDE fungerer internt. Vi starter med nøglelagring, da det er nødvendigt for al kryptering. Derefter vil vi undersøge, hvordan kryptering fungerer i Percona Server for MySQL/MySQL og hvilke ekstra funktioner der er i Percona Server for MySQL.

MySQL Keyring

Keyring er plugins, der tillader serveren at anmode om, oprette og slette nøgler i en lokal fil (keyring_file) eller på en fjernserver (f.eks. i HashiCorp Vault). Nøglerne caches altid lokalt for at fremskynde adgangen.

Plugins kan opdeles i to kategorier:

  • Lokalt lager. For eksempel en lokal fil (vi kalder dette filbaseret nøglelager, file-based keyring).
  • Fjernlager. For eksempel Vault Server (vi kalder dette serverbaseret nøglelager, server-based keyring).

Denne opdeling er vigtig, fordi forskellige typer lagre opfører sig lidt forskelligt, ikke kun ved opbevaring og hentning af nøgler, men også ved opstart.

Når der anvendes et filbaseret lager, indlæses alt indholdet af lageret i cachen ved opstart: nøgle-id, nøglebruger, nøgletype og selve nøglen.

I tilfælde af et serverbaseret lager (f.eks. Vault server) indlæses kun nøgle-id og nøglebruger ved opstart, så hentning af alle nøgler ikke forsinker opstarten. Nøglerne indlæses 'lazy'. Det vil sige, at selve nøglen kun indlæses fra Vault, når den faktisk er nødvendig. Efter indlæsning caches nøglen i hukommelsen for at undgå fremtidige TLS-forbindelser til Vault Server. Lad os se, hvilken information der er til stede i nøglelageret.

Oplysningerne om nøglen indeholder følgende:

  • nøgle-id — identifikator for nøglen, f.eks.:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • nøgletype — typen af nøglen, baseret på den anvendte krypteringsalgoritme, mulige værdier: "AES", "RSA" eller "DSA".
  • nøglelængde — længden af nøglen i bytes, AES: 16, 24 eller 32, RSA 128, 256, 512 og DSA 128, 256 eller 384.
  • user — ejer af nøglen. Hvis nøglen er en systemnøgle, f.eks. Master Key, er dette felt tomt. Hvis nøglen oprettes ved hjælp af keyring_udf, angiver dette felt ejer af nøglen.
  • selve nøglen

Nøglen identificeres entydigt af et par: key_id, user.

Der er også forskelle i opbevaring og sletning af nøgler.

Filopbevaringen fungerer hurtigere. Man kunne antage, at nøgleopbevaringen er en simpel engangsindskrivning af nøglen i filen, men det er ikke tilfældet — der sker flere operationer her. Ved enhver ændring af filopbevaringen oprettes først en sikkerhedskopi af alt indholdet. Lad os sige, at filen hedder my_biggest_secrets, så vil sikkerhedskopien hedde my_biggest_secrets.backup. Derefter ændres cachen (nøgler føjes til eller fjernes fra) og, hvis alt går godt, nulstilles cachen til filen. I sjældne tilfælde, såsom serverfejl, kan du se denne sikkerhedskopsfil. Sikkerhedskopsfilen slettes ved næste indlæsning af nøglerne (normalt efter genstart af serveren).

Når en nøgle gemmes eller slettes i serveropbevaringen, skal opbevaringen oprette forbindelse til MySQL-serveren med kommandoerne "send nøgle" / "anmod om sletning af nøgle".

Lad os vende tilbage til serverens opstartshastighed. Udover at selve opbevaringen påvirker opstartshastigheden, er der også spørgsmålet om, hvor mange nøgler fra opbevaringen der skal hentes ved opstart. Det er selvfølgelig især vigtigt for serveropbevaringer. Ved opstart kontrollerer serveren, hvilken nøgle der er nødvendig for de krypterede tabeller / tabelrum, og anmoder om nøglen fra opbevaringen. På en "ren" server med Master Key - kryptering skal der være en Master Key, der skal hentes fra opbevaringen. Dog kan der være behov for flere nøgler, for eksempel når en sikkerhedskopi fra hovedserveren genoprettes på en reserve server. I sådanne tilfælde bør der overvejes rotation af Master Key. Dette vil blive behandlet mere i fremtidige artikler, men her vil jeg gerne påpege, at en server, der bruger flere Master Keys, kan starte lidt længere tid, især når man bruger serveropbevaringen til nøgler.

Lad os nu tale lidt mere om keyring_file. Da jeg udviklede keyring_file, var jeg også bekymret for, hvordan man skulle tjekke ændringerne af keyring_file, mens serveren kørte. I 5.7 blev kontrollen udført baseret på filens statistik, hvilket ikke var en perfekt løsning, og i 8.0 blev det ændret til en SHA256-kontrollsum.

Ved første opstart beregner keyring_file filens statistik og kontrolsum, som gemmes af serveren, og ændringer anvendes kun, hvis de stemmer overens. Ved ændring af filen opdateres kontrolsummen.

Vi har allerede drøftet mange emner omkring nøglelagre. Men der er et vigtigt emne, som ofte glemmes eller misforstås — opdelingen af nøgler mellem serverne.

Hvad mener jeg med det? Hver server (f.eks. Percona Server) i klyngen skal have sit eget område på Vault-serveren, hvor Percona Server skal opbevare sine nøgler. Hver Master Key gemt i lageret indeholder GUID'en for Percona Server inden for sin identifikator. Hvorfor er det vigtigt? Forestil dig, at du kun har én Vault-server, og alle Percona Server i klyngen bruger denne ene Vault-server. Problemet virker åbenlyst. Hvis alle Percona Server brugte Master Key uden unikke identifikatorer, f.eks. id = 1, id = 2 osv., ville alle servere i klyngen bruge den samme Master Key. Det, som GUID'en muliggør — adskillelse mellem servere. Hvorfor tale om at opdele nøgler mellem serverne, når der allerede findes en unik GUID? Der er en anden plugin — keyring_udf. Med denne plugin kan brugeren af din server gemme sine nøgler på Vault-serveren. Problemet opstår, når brugeren opretter en nøgle, f.eks. på server1, og derefter forsøger at oprette en nøgle med den samme identifikator på server2, f.eks.:

--server1:
select keyring_key_store('ROB_1','AES',"123456789012345");
1
--1 betyder succesfuld afslutning
--server2:
select keyring_key_store('ROB_1','AES',"543210987654321");
1

Vent lige. Begge servere bruger den samme Vault-server, skulle funktionen keyring_key_store ikke afslutte med en fejl på server2? Interessant, at hvis du prøver at gøre det samme på én server, vil du få en fejl:

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

Korrekt, ROB_1 eksisterer allerede.

Lad os først diskutere det andet eksempel. Som vi allerede har nævnt, cacher keyring_vault eller enhver anden lagringsplugin (keyring) alle nøgle-ID'er i hukommelsen. Så efter oprettelse af en ny nøgle, tilføjes ROB_1 til server1, og ud over at sende denne nøgle til Vault, tilføjes nøgle også til cachen. Nu, når vi forsøger at tilføje den samme nøgle igen, kontrollerer keyring_vault, om denne nøgle findes i cachen, og giver en fejlmeddelelse.

I det første tilfælde er situationen en anden. På serverne server1 og server2 er der separate cacher. Efter at have tilføjet ROB_1 til cache nøglerne på server1 og server Vault, er cache nøglerne på server2 ikke synkroniseret. Der er ingen nøgle ROB_1 i cachen på server2. Derfor skrives nøgle ROB_1 til keyring_key_store og til server Vault, som faktisk overskriver (!) den tidligere værdi. Nu er nøgle ROB_1 på server Vault lig med 543210987654321. Det er interessant, at server Vault ikke blokerer sådanne handlinger og blot overskriver den gamle værdi.

Nu ser vi, hvorfor opdeling efter servere på Vault kan være vigtigt — når du bruger keyring_udf og ønsker at gemme nøgler i Vault. Hvordan sikrer man en sådan opdeling på server Vault?

Der er to måder at opdele på Vault. Du kan oprette forskellige monteringspunkter for hver server eller bruge forskellige stier inden for et monteringspunkt. Det bedste er at vise det med eksempler. Så lad os først se på separate monteringspunkter:

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

Her kan vi se, at server1 og server2 bruger forskellige monteringspunkter. Ved opdeling af stier vil konfigurationen se således ud:

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

I dette tilfælde bruger begge servere det samme monteringspunkt «mount_point», men forskellige stier. Når den første hemmelighed oprettes på serveren server1 på denne sti, opretter Vault-serveren automatisk en mappe «server1». For server2 er alt det samme. Når du sletter den sidste hemmelighed i mount_point/server1 eller mount_point/server2, sletter Vault-serveren også disse mapper. Hvis du anvender stiadskillelse, skal du kun oprette én monteringspunkt og ændre konfigurationsfilerne, så serverne bruger separate stier. Monteringspunktet kan oprettes ved hjælp af en HTTP-anmodning. Med CURL kan det gøres på følgende måde:

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

Alle felter (TOKEN, VAULT_CA, VAULT_URL, SECRET_MOUNT_POINT) svarer til parametrene i konfigurationsfilen. Selvfølgelig kan man bruge Vault-værktøjer til at gøre det samme. Men det er lettere at automatisere oprettelsen af monteringspunktet. Jeg håber, denne information vil være nyttig for dig, og vi ses i de næste artikler i denne serie.

Kryptering i MySQL: nøglelagring

Læs mere:

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster