Szyfrowanie w MySQL: magazyn kluczy

W oczekiwaniu na rozpoczęcie nowych zapisów na kurs "Baza danych" Przygotowaliśmy dla Ciebie tłumaczenie przydatnego artykułu.

Szyfrowanie w MySQL: magazyn kluczy

Pojawiło się przezroczyste szyfrowanie danych (TDE). Serwer Percona dla MySQL i MySQL już od dłuższego czasu. Ale czy zastanawiałeś się kiedyś, jak to działa pod maską i jaki wpływ TDE może mieć na Twój serwer? W tej serii artykułów przyjrzymy się wewnętrznemu działaniu TDE. Zacznijmy od przechowywania kluczy, ponieważ jest ono wymagane do działania dowolnego szyfrowania. Następnie przyjrzymy się bliżej, jak działa szyfrowanie w Percona Server for MySQL/MySQL i jakie dodatkowe funkcje posiada Percona Server for MySQL.

Brelok MySQL

Pliki kluczy to wtyczki, które umożliwiają serwerowi wysyłanie zapytań, tworzenie i usuwanie kluczy w pliku lokalnym (plik_kluczy) lub na serwerze zdalnym (na przykład w skarbcu HashiCorp). Klucze są zawsze przechowywane lokalnie w pamięci podręcznej, aby przyspieszyć ich odzyskiwanie.

Wtyczki można podzielić na dwie kategorie:

  • Lokalny magazyn. Na przykład plik lokalny (nazywamy go zbiorem kluczy opartym na plikach).
  • zdalne przechowywanie. Na przykład serwer Vault (nazywamy to zbiorem kluczy opartym na serwerze).

To rozdzielenie jest ważne, ponieważ różne typy pamięci zachowują się nieco inaczej, nie tylko podczas przechowywania i odzyskiwania kluczy, ale także podczas ich uruchamiania.

Podczas korzystania z magazynu plików cała zawartość magazynu jest ładowana do pamięci podręcznej podczas uruchamiania: identyfikator klucza, użytkownik klucza, typ klucza i sam klucz.

W przypadku sklepu opartego na serwerze (takiego jak Vault Server) podczas uruchamiania ładowany jest tylko identyfikator klucza i użytkownik klucza, więc uzyskanie wszystkich kluczy nie spowalnia uruchamiania. Klucze ładują się leniwie. Oznacza to, że sam klucz jest ładowany z Vault tylko wtedy, gdy jest rzeczywiście potrzebny. Po pobraniu klucz jest buforowany w pamięci, dzięki czemu w przyszłości nie będzie trzeba uzyskiwać do niego dostępu za pośrednictwem połączeń TLS z serwerem Vault. Następnie zastanów się, jakie informacje znajdują się w magazynie kluczy.

Kluczowe informacje zawierają następujące informacje:

  • identyfikator klucza - identyfikator klucza, np.:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • typ klucza - typ klucza w zależności od zastosowanego algorytmu szyfrowania, możliwe wartości: „AES”, „RSA” lub „DSA”.
  • długość klucza - długość klucza w bajtach, AES: 16, 24 lub 32, RSA 128, 256, 512 i DSA 128, 256 lub 384.
  • użytkownik jest właścicielem klucza. Jeśli kluczem jest system, np. klucz główny, to pole to jest puste. Jeśli klucz jest tworzony za pomocą keyring_udf, to pole identyfikuje właściciela klucza.
  • sam klucz

Klucz jest jednoznacznie identyfikowany przez parę: key_id, user.

Istnieją również różnice w przechowywaniu i usuwaniu kluczy.

Przechowywanie plików jest szybsze. Można by pomyśleć, że magazyn kluczy po prostu raz zapisuje klucz do pliku, ale nie, tutaj dzieje się więcej. Za każdym razem, gdy dokonywana jest modyfikacja przechowywania plików, najpierw tworzona jest kopia zapasowa całej zawartości. Załóżmy, że plik nazywa się moje_największe_secrets, wówczas kopią zapasową będzie mój_największy_secrets.backup. Następnie następuje zmiana pamięci podręcznej (dodawanie lub usuwanie kluczy) i jeśli wszystko się powiedzie, pamięć podręczna jest resetowana do pliku. W rzadkich przypadkach, takich jak awaria serwera, możesz zobaczyć ten plik kopii zapasowej. Plik kopii zapasowej zostanie usunięty przy następnym załadowaniu kluczy (zwykle po ponownym uruchomieniu serwera).

Podczas zapisywania lub usuwania klucza w sklepie serwera sklep musi połączyć się z serwerem MySQL za pomocą poleceń „wyślij klucz” / „zażądaj usunięcia klucza”.

Wróćmy do szybkości uruchamiania serwera. Oprócz tego, że na prędkość uruchamiania wpływa sam skarbiec, pojawia się również kwestia tego, ile kluczy ze skarbca należy pobrać przy uruchomieniu. Oczywiście jest to szczególnie ważne w przypadku przechowywania danych na serwerze. Podczas uruchamiania serwer sprawdza, który klucz jest wymagany dla zaszyfrowanych tabel/obszarów tabel i żąda klucza z magazynu. Na „czystym” serwerze z szyfrowaniem klucza głównego musi znajdować się jeden klucz główny, który należy pobrać z magazynu. Jednakże może być wymagana większa liczba kluczy, na przykład gdy serwer kopii zapasowych przywraca kopię zapasową z serwera głównego. W takich przypadkach należy zapewnić rotację klucza głównego. Zostanie to omówione bardziej szczegółowo w przyszłych artykułach, chociaż tutaj chciałbym zauważyć, że uruchomienie serwera korzystającego z wielu kluczy głównych może zająć nieco więcej czasu, szczególnie w przypadku korzystania z magazynu kluczy po stronie serwera.

Porozmawiajmy teraz trochę więcej o pliku kluczy. Kiedy tworzyłem plik kluczy_kluczy, zastanawiałem się również, jak sprawdzić zmiany w pliku kluczy, gdy serwer jest uruchomiony. W wersji 5.7 sprawdzenie odbywało się w oparciu o statystyki plików, co nie było rozwiązaniem idealnym, a w wersji 8.0 zastąpiono je sumą kontrolną SHA256.

Przy pierwszym uruchomieniu keyring_file obliczane są statystyki pliku i suma kontrolna, które są zapamiętywane przez serwer, a zmiany są stosowane tylko wtedy, gdy są zgodne. Kiedy plik się zmienia, suma kontrolna jest aktualizowana.

Omówiliśmy już wiele pytań dotyczących magazynów kluczy. Istnieje jednak inny ważny temat, o którym często się zapomina lub źle rozumie – współdzielenie kluczy między serwerami.

Co miałem na myśli? Każdy serwer (na przykład serwer Percona) w klastrze musi mieć osobną lokalizację na serwerze Vault, w której serwer Percona musi przechowywać swoje klucze. Każdy klucz główny zapisany w magazynie zawiera identyfikator GUID serwera Percona w swoim identyfikatorze. Dlaczego to jest ważne? Załóżmy, że masz tylko jeden serwer Vault i wszystkie serwery Percona w klastrze korzystają z tego pojedynczego serwera Vault. Problem wydaje się oczywisty. Jeśli wszystkie serwery Percona używały klucza głównego bez unikalnych identyfikatorów, takich jak id = 1, id = 2 itd., wówczas wszystkie serwery w klastrze korzystałyby z tego samego klucza głównego. To właśnie zapewnia identyfikator GUID – rozróżnienie między serwerami. Po co więc mówić o udostępnianiu kluczy między serwerami, jeśli istnieje już unikalny identyfikator GUID? Jest jeszcze jedna wtyczka - keyring_udf. Dzięki tej wtyczce użytkownik Twojego serwera może przechowywać swoje klucze na serwerze Vault. Problem występuje, gdy użytkownik tworzy klucz na przykład na serwerze 1, a następnie próbuje utworzyć klucz o tym samym identyfikatorze na serwerze 2, na przykład:

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

Czekać. Obydwa serwery korzystają z tego samego serwera Vault. Czy funkcja keyring_key_store nie powinna zawieść na serwerze 2? Co ciekawe, jeśli spróbujesz zrobić to samo na jednym serwerze, pojawi się błąd:

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

Zgadza się, ROB_1 już istnieje.

Omówmy najpierw drugi przykład. Jak powiedzieliśmy wcześniej, keyring_vault lub jakakolwiek inna wtyczka skarbca (pęk kluczy) buforuje wszystkie identyfikatory kluczy w pamięci. Zatem po utworzeniu nowego klucza ROB_1 jest dodawany do serwera1 i oprócz wysłania tego klucza do Vault, klucz jest również dodawany do pamięci podręcznej. Teraz, gdy próbujemy dodać ten sam klucz po raz drugi, keyring_vault sprawdza, czy klucz istnieje w pamięci podręcznej i zgłasza błąd.

W pierwszym przypadku sytuacja jest inna. Serwer1 i serwer2 mają oddzielne pamięci podręczne. Po dodaniu ROB_1 do pamięci podręcznej kluczy na serwerze 1 i serwerze Vault pamięć podręczna kluczy na serwerze 2 nie jest zsynchronizowana. Pamięć podręczna na serwerze2 nie zawiera klucza ROB_1. W ten sposób klucz ROB_1 jest zapisywany w magazynie kluczy_kluczy i na serwerze Vault, co w rzeczywistości nadpisuje (!) poprzednią wartość. Teraz klucz ROB_1 na serwerze Vault to 543210987654321. Co ciekawe, serwer Vault nie blokuje takich akcji i łatwo nadpisuje starą wartość.

Teraz widzimy, dlaczego segregacja według serwera w Vault może być ważna, jeśli używasz keyring_udf i chcesz przechowywać klucze w Vault. Jak zapewnić taką separację na serwerze Vault?

Istnieją dwa sposoby podziału na Vault. Można utworzyć różne punkty podłączenia dla każdego serwera lub użyć różnych ścieżek w obrębie tego samego punktu podłączenia. Najlepiej zilustrować to przykładami. Przyjrzyjmy się więc najpierw poszczególnym punktom montowania:

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

Tutaj możesz zobaczyć, że serwer1 i serwer2 używają różnych punktów montowania. W przypadku separacji ścieżek konfiguracja będzie wyglądać następująco:

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

W tym przypadku oba serwery używają tego samego punktu podłączenia „punkt_montowania”, ale różnych ścieżek. Kiedy utworzysz pierwszy klucz tajny na serwerze 1 przy użyciu tej ścieżki, serwer Vault automatycznie utworzy katalog „serwer1”. W przypadku serwera 2 wszystko jest takie samo. Po usunięciu ostatniego wpisu tajnego w punkcie_montowania/serwer1 lub punkcie_montowania/serwer2 serwer Vault usuwa również te katalogi. W przypadku korzystania z rozdzielonych ścieżek należy utworzyć tylko jeden punkt podłączenia i zmienić pliki konfiguracyjne tak, aby serwery korzystały z oddzielnych ścieżek. Punkt podłączenia można utworzyć za pomocą żądania HTTP. Używając CURL, można to zrobić w następujący sposób:

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

Wszystkie pola (TOKEN, VAULT_CA, VAULT_URL, SECRET_MOUNT_POINT) odpowiadają parametrom pliku konfiguracyjnego. Oczywiście możesz użyć narzędzi Vault, aby zrobić to samo. Ale łatwiej jest zautomatyzować tworzenie punktu montowania. Mam nadzieję, że te informacje okażą się przydatne. Do zobaczenia w kolejnych artykułach z tej serii.

Szyfrowanie w MySQL: magazyn kluczy

Czytaj więcej:

Źródło: www.habr.com

Dodaj komentarz