Шыфраванне ў MySQL: сховішча ключоў

Напярэдадні старту новага набору на курс «Базы дадзеных» падрыхтавалі для вас перавод карыснага артыкула.

Шыфраванне ў MySQL: сховішча ключоў

Празрыстае шыфраванне дадзеных (Transparent Data Encryption, TDE) з'явілася ў Percona Server for MySQL і MySQL даўнавата. Але ці задумваліся вы калі-небудзь аб тым, як яно працуе пад капотам і які ўплыў TDE можа аказваць на ваш сервер? У гэтай серыі артыкулаў мы разгледзім, як TDE працуе ўсярэдзіне. Пачнём з захоўвання ключоў, бо яно патрабуецца для працы любога шыфравання. Затым падрабязна разгледзім, як працуе шыфраванне ў Percona Server for MySQL/MySQL і якія дадатковыя магчымасці ёсць у Percona Server for MySQL.

MySQL Keyring

Keyring - гэта плагіны, якія дазваляюць серверу запытваць, ствараць і выдаляць ключы ў лакальным файле (keyring_file) або на выдаленым серверы (напрыклад, у HashiCorp Vault). Ключы заўсёды кэшуюцца лакальна, каб паскорыць іх атрыманне.

Даданыя модулі можна падзяліць на дзве катэгорыі:

  • Лакальнае сховішча. Напрыклад, лакальны файл (мы завём гэта файлавым сховішчам ключоў, file-based keyring).
  • Выдаленае сховішча. Напрыклад Vault Server (мы завём гэта серверным сховішчам ключоў, server-based keyring).

Гэты падзел важна, таму што розныя тыпы сховішчаў паводзяць сябе крыху па-рознаму не толькі пры захоўванні і атрыманні ключоў, але і пры запуску.

Пры выкарыстанні файлавага сховішча пры запуску ў кэш загружаецца ўсё змесціва сховішчы: key id, key user, key type і сам ключ.

У выпадку сервернага сховішча (напрыклад, сервер Vault) пры запуску загружаецца толькі key id і key user, таму атрыманне ўсіх ключоў не запавольвае запуск. Ключы загружаюцца ляніва. Гэта значыць сам ключ загружаецца з Vault толькі тады, калі ён фактычна спатрэбіцца. Пасля загрузкі ключ кэшуецца ў памяці, каб у будучыні не было неабходнасці звяртацца за ім праз TLS-злучэнні да Vault Server. Далей разгледзім, якая інфармацыя прысутнічае ў сховішчы ключоў.

Інфармацыя аб ключы змяшчае наступнае:

  • key id - ідэнтыфікатар ключа, напрыклад:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • тып ключа - Тып ключа, заснаваны на выкарыстоўваным алгарытме шыфравання, магчымыя значэнні: "AES", "RSA" або "DSA".
  • даўжыня ключа - Даўжыня ключа ў байтах, AES: 16, 24 або 32, RSA 128, 256, 512 і DSA 128, 256 або 384.
  • карыстальнік - уладальнік ключа. Калі ключ з'яўляецца сістэмным, напрыклад, Master Key, тое гэтае поле пуста. Калі ключ ствараецца з дапамогай keyring_udf, тое гэтае поле пазначае ўладальніка ключа.
  • сам ключ

Ключ адназначна ідэнтыфікуецца парай: key_id, user.

Таксама ёсць адрозненні ў захоўванні і выдаленні ключоў.

Файлавае сховішча працуе хутчэй. Можна выказаць здагадку, што сховішча ключоў - гэта просты аднаразовы запіс ключа ў файл, але не - тут адбываецца больш аперацый. Пры любой мадыфікацыі файлавага сховішча спачатку ствараецца рэзервовая копія ўсяго змесціва. Дапушчальны файл завецца my_biggest_secrets, тады рэзервовая копія будзе my_biggest_secrets.backup. Далей змяняецца кэш (дадаюцца ці выдаляюцца ключы) і, калі ўсё выканана паспяхова, то кэш скідаецца ў файл. У рэдкіх выпадках, такіх як збой сервера, вы можаце ўбачыць гэты файл рэзервовай копіі. Файл рэзервовай копіі выдаляецца пры наступнай загрузцы ключоў (звычайна пасля перазапуску сервера).

Пры захаванні або выдаленні ключа ў серверным сховішчы, сховішча павінна падлучыцца да сервера MySQL з камандамі "адправіць ключ" / "запытаць выдаленне ключа" ("send the key" / "request key deletion").

Давайце вернемся да хуткасці запуску сервера. Акрамя таго, што на хуткасць запуску ўплывае само сховішча, ёсць таксама пытанне аб тым, колькі ключоў са сховішча неабходна атрымаць пры запуску. Вядома, гэта асабліва важна для серверных сховішчаў. Пры запуску сервер правярае, які ключ неабходны для зашыфраваных табліц / таблічных прастор і запытвае ключ са сховішча. На "чыстым" серверы з Master Key - шыфраваннем павінен быць адзін Master Key, які неабходна выняць са сховішча. Аднак можа спатрэбіцца і большая колькасць ключоў, напрыклад, калі на рэзервовым серверы аднаўляецца рэзервовая копія з асноўнага сервера. У такіх выпадках варта прадугледзець ратацыю Master Key. Больш падрабязна гэта будзе разгледжана ў будучых артыкулах, хоць тут я хацеў бы адзначыць, што сервер, які выкарыстоўвае некалькі Master Key можа запускацца крыху даўжэй, асабліва, пры выкарыстанні сервернага сховішчы ключоў.

Цяпер давайце пагаворым яшчэ крыху пра keyring_file. Калі я распрацоўваў keyring_file, мяне таксама непакоіла тое, як правяраць змену keyring_file падчас працы сервера. У 5.7/8.0 праверка выконвалася на аснове статыстыкі файла, што не было ідэальным рашэннем, і ў 256 было заменена на кантрольную суму SHAXNUMX.

Пры першым запуску keyring_file вылічаецца статыстыка файла і кантрольная сума, якія запамінаюцца серверам, і змены прымяняюцца толькі ў тым выпадку, калі яны супадаюць. Пры змене файла кантрольная сума абнаўляецца.

Мы ўжо разгледзелі многія пытанні аб сховішчах ключоў. Аднак ёсць яшчэ адна важная тэма, пра якую часта забываюць ці разумеюць няправільна – падзел ключоў па серверах.

Што я маю на ўвазе? Кожны сервер (напрыклад, Percona Server) у кластары павінен мець асобнае месца на серверы Vault, у якім Percona Server павінен захоўваць свае ключы. У кожным Master Key, захаваным у сховішча ўтрымоўваецца GUID сервера Percona Server усярэдзіне свайго ідэнтыфікатара. Чаму гэта важна? Уявіце, што ў вас есць толькі адзін Vault Server і ўсе Percona Server у кластары выкарыстоўваюць гэты адзіны Vault Server. Праблема здаецца відавочнай. Калі б усе Percona Server выкарыстоўвалі Master Key без унікальных ідэнтыфікатараў, напрыклад, id = 1, id = 2 і т. д., то ўсе серверы ў кластары выкарыстоўвалі б адзін і той жа Master Key. Што і забяспечвае GUID – размежаванне паміж серверамі. Навошта тады казаць аб падзеле ключоў паміж серверамі, калі ўжо існуе ўнікальны GUID? Ёсць яшчэ адна ўбудова – keyring_udf. З дапамогай гэтага плагіна карыстач вашага сервера можа захоўваць свае ключы на ​​серверы Vault. Праблема ўзнікае, калі карыстач стварае ключ, напрыклад, на серверы server1, а затым спрабуе стварыць ключ з такім жа ідэнтыфікатарам на server2, напрыклад:

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

Пачакайце. Абодва сервера выкарыстоўваюць адзін і той жа Vault Server, ці не павінна функцыя keyring_key_store завяршыцца з памылкай на серверы server2? Цікава, што калі вы паспрабуеце зрабіць тое ж самае на адным серверы, то атрымаеце памылку:

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

Правільна, ROB_1 ужо існуе.

Давайце спачатку абмяркуем другі прыклад. Як мы ўжо казалі раней, keyring_vault або любы іншы плягін сховішчаў (keyring) кэшуе ўсе ідэнтыфікатары ключоў у памяці. Такім чынам, пасля стварэння новага ключа, ROB_1 дадаецца на server1, і, акрамя адпраўкі гэтага ключа ў Vault, ключ таксама дадаецца ў кэш. Цяпер, калі мы спрабуем дадаць такі ж ключ у другі раз, keyring_vault правярае, ці існуе гэты ключ у кэшы, і выдае памылку.

У першым выпадку сітуацыя іншая. На серверах server1 і server2 ёсць асобныя кэшы. Пасля дадання ROB_1 у кэш ключоў на серверы server1 і сервер Vault, кэш ключоў на server2 не сінхранізаваны. У кэшы на server2 няма ключа ROB_1. Такім чынам, ключ ROB_1 запісваецца ў keyring_key_store і на сервер Vault, які фактычна перапісвае (!) папярэдняе значэнне. Цяпер ключ ROB_1 на серверы Vault роўны 543210987654321. Цікава, што сервер Vault не блакуе такія дзеянні і папросту перапісвае старое значэнне.

Цяпер мы бачым, чаму падзел па серверах на Vault можа быць важным - калі вы выкарыстоўваеце keyring_udf і хочаце захоўваць ключы ў Vault. Як забяспечыць такі падзел на серверы Vault?

Ёсць два спосабу падзелу на Vault. Можна стварыць розныя кропкі мантавання для кожнага сервера або выкарыстоўваць розныя шляхі ўнутры адной кропкі мантавання. Лепш за ўсё паказаць на прыкладах. Такім чынам, давайце паглядзім спачатку на асобныя кропкі мантавання:

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

Тут відаць, што server1 і server2 выкарыстоўваюць розныя кропкі мантавання. Пры падзеле шляхоў канфігурацыя будзе выглядаць наступным чынам:

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

У дадзеным выпадку абодва сервера выкарыстоўваюць адну і тую ж кропку мантавання "mount_point", але розныя шляхі. Пры стварэнні першага сакрэту на серверы server1 па гэтым шляху сервер Vault аўтаматычна стварае дырэкторыю "server1". Для server2 усё аналагічна. Калі вы выдаляеце апошні сакрэт у mount_point/server1 ці mount_point/server2, то сервер Vault таксама выдаляе гэтыя дырэкторыі. У выпадку, калі вы выкарыстоўваеце падзел шляхоў, вы павінны стварыць толькі адну кропку мантавання і змяніць канфігурацыйныя файлы, каб серверы выкарыстоўвалі асобныя шляхі. Кропку мантавання можна стварыць з дапамогай HTTP-запыту. З дапамогай CURL гэта можна зрабіць наступным чынам:

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

Усе палі (TOKEN, VAULT_CA, VAULT_URL, SECRET_MOUNT_POINT) адпавядаюць параметрам файла канфігурацыі. Вядома, можна выкарыстоўваць утыліты Vault, каб зрабіць тое ж самае. Але так прасцей аўтаматызаваць стварэнне кропкі мантавання. Спадзяюся, гэтая інфармацыя будзе для вас карыснай, і мы ўбачымся ў наступных артыкулах гэтай серыі.

Шыфраванне ў MySQL: сховішча ключоў

Чытаць яшчэ:

Крыніца: habr.com

Дадаць каментар