Enkripsi MySQL: penyimpanan kunci

Menjelang awal set baru untuk kursus "Database" kami telah menyiapkan terjemahan dari artikel yang berguna untuk Anda.






Enkripsi Data Transparan (TDE) telah ada sejak lama di Server Percona untuk MySQL dan MySQL. Tapi pernahkah Anda bertanya-tanya bagaimana cara kerjanya di bawah tenda dan apa dampak TDE pada server Anda? Dalam seri artikel ini, kita akan melihat bagaimana TDE bekerja secara internal. Mari kita mulai dengan penyimpanan kunci, karena ini diperlukan agar enkripsi apa pun berfungsi. Kemudian kita akan melihat lebih dekat cara kerja enkripsi di Server Percona untuk MySQL / MySQL dan fitur tambahan apa saja yang tersedia di Server Percona untuk MySQL.



Gantungan Kunci MySQL



Keyring adalah plugin yang memungkinkan server untuk meminta, membuat dan menghapus kunci di file lokal (keyring_file) atau di server jarak jauh (seperti di HashiCorp Vault). Kunci selalu disimpan dalam cache secara lokal untuk mempercepat pengambilan.



Plugin dapat dibagi menjadi dua kategori:



  • Penyimpanan lokal. Misalnya, file lokal (kami menyebutnya keyring berbasis file).
  • Penyimpanan jarak jauh. Misalnya Vault Server (kami menyebutnya keyring berbasis server).


Pemisahan ini penting karena berbagai jenis penyimpanan berperilaku sedikit berbeda, tidak hanya saat menyimpan dan mengambil kunci, tetapi juga saat memulai.



Saat menggunakan penyimpanan file, saat startup, seluruh konten penyimpanan dimuat ke dalam cache: id kunci, pengguna kunci, jenis kunci, dan kunci itu sendiri.



Dalam kasus back-end vault (seperti server Vault), hanya key id dan key user yang dimuat saat startup, jadi mendapatkan semua kunci tidak akan memperlambat startup. Kunci dimuat dengan malas. Artinya, kunci itu sendiri dimuat dari Vault hanya jika benar-benar diperlukan. Setelah dimuat, kunci tersebut di-cache dalam memori sehingga di masa mendatang tidak perlu mengaksesnya melalui koneksi TLS ke Server Vault. Selanjutnya, mari kita lihat informasi apa yang ada di penyimpanan kunci.



Informasi utama berisi yang berikut ini:



  • key id — , :

    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • key type — , , : «AES», «RSA» «DSA».
  • key length — , AES: 16, 24 32, RSA 128, 256, 512 DSA 128, 256 384.
  • user — . , , Master Key, . keyring_udf, .


Kuncinya secara unik diidentifikasi oleh pasangan: key_id, pengguna.



Ada juga perbedaan dalam penyimpanan dan pembuangan kunci.



Penyimpanan file lebih cepat. Orang mungkin berasumsi bahwa penyimpanan kunci adalah penulisan kunci satu kali yang sederhana ke sebuah file, tetapi tidak - ada lebih banyak operasi yang terjadi di sini. Modifikasi apa pun pada penyimpanan file pertama-tama akan membuat cadangan semua konten. Misalkan file bernama my_biggest_secrets, maka backup akan menjadi my_biggest_secrets.backup. Selanjutnya, cache diubah (kunci ditambahkan atau dihapus), dan jika semuanya berhasil, cache di-flush ke sebuah file. Dalam kasus yang jarang terjadi, seperti kerusakan server, Anda mungkin melihat file cadangan ini. File cadangan dihapus saat kunci dimuat lagi (biasanya setelah server dimulai ulang).



Saat menyimpan atau menghapus kunci di repositori server, repositori harus terhubung ke server MySQL dengan perintah "send the key" / "request key deletion".



Mari kembali ke kecepatan startup server. Selain fakta bahwa penyimpanan itu sendiri memengaruhi kecepatan peluncuran, ada juga pertanyaan tentang berapa banyak kunci dari penyimpanan yang perlu Anda dapatkan saat memulai. Tentu saja, ini sangat penting untuk penyimpanan back-end. Saat startup, server memeriksa kunci mana yang diperlukan untuk tabel / tablespaces terenkripsi dan meminta kunci dari penyimpanan. Pada server "bersih" dengan Enkripsi Kunci Master, harus ada satu Kunci Utama, yang harus diambil dari penyimpanan. Namun, lebih banyak kunci mungkin diperlukan, misalnya, saat memulihkan cadangan dari server utama ke server cadangan. Dalam kasus seperti itu, rotasi Master Key harus disediakan. Ini akan dibahas lebih detail di artikel mendatang, meskipun di sini saya ingin menunjukkan bahwa server,menggunakan beberapa Kunci Master mungkin membutuhkan waktu lebih lama untuk memulai, terutama saat menggunakan penyimpanan kunci sisi server.



Sekarang mari kita bicara lebih banyak tentang keyring_file. Ketika saya mengembangkan keyring_file, saya juga prihatin tentang cara memeriksa perubahan keyring_file saat server sedang berjalan. Di 5.7, pemeriksaan dilakukan berdasarkan statistik file, yang bukan merupakan solusi ideal, dan di 8.0 diganti dengan checksum SHA256.



Pertama kali Anda menjalankan keyring_file, statistik file dan checksum dihitung dan diingat oleh server, dan perubahan diterapkan hanya jika cocok. Checksum diperbarui ketika file diubah.



Kami telah membahas banyak pertanyaan tentang keystore. Namun, ada topik penting lain yang sering dilupakan atau disalahpahami - berbagi kunci di seluruh server.



Apa yang saya maksud? Setiap server (misalnya, Percona Server) di cluster harus memiliki lokasi terpisah di server Vault tempat Percona Server harus menyimpan kuncinya. Setiap Master Key yang disimpan dalam repositori berisi GUID dari Server Percona di dalam pengenalnya. Mengapa ini penting? Bayangkan Anda hanya memiliki satu Server Vault dan semua Server Percona di kluster menggunakan Server Vault tunggal tersebut. Masalahnya tampak jelas. Jika semua Server Percona menggunakan Master Key tanpa pengenal unik, seperti id = 1, id = 2, dll., Maka semua server di cluster akan menggunakan Master Key yang sama. Inilah yang disediakan GUID - perbedaan antara server. Lalu mengapa berbicara tentang berbagi kunci antar server ketika GUID unik sudah ada? Ada satu plugin lagi - keyring_udf.Dengan plugin ini, pengguna server Anda dapat menyimpan kunci mereka di server Vault. Masalah terjadi saat pengguna membuat kunci, misalnya, di server1, dan kemudian mencoba membuat kunci dengan ID yang sama di server2, misalnya:



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


Tunggu. Kedua server menggunakan Server Vault yang sama, bukankah seharusnya fungsi keyring_key_store gagal di server2? Menariknya, jika Anda mencoba melakukan hal yang sama di server yang sama, Anda akan mendapatkan error:



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


Benar, ROB_1 sudah ada.



Mari kita bahas contoh kedua dulu. Seperti yang kami katakan sebelumnya, keyring_vault atau plugin keyring lainnya akan menyimpan semua ID kunci di memori. Jadi, setelah membuat kunci baru, ROB_1 ditambahkan ke server1, dan selain mengirim kunci ini ke Vault, kunci tersebut juga ditambahkan ke cache. Sekarang, saat kami mencoba menambahkan kunci yang sama untuk kedua kalinya, keyring_vault memeriksa apakah kunci ini ada di cache dan menimbulkan kesalahan.



Dalam kasus pertama, situasinya berbeda. Server1 dan server2 memiliki cache terpisah. Setelah menambahkan ROB_1 ke cache kunci di server1 dan Vault, cache kunci di server2 tidak sinkron. Tidak ada kunci ROB_1 dalam cache di server2. Dengan demikian, kunci ROB_1 ditulis ke keyring_key_store dan ke server Vault, yang sebenarnya menimpa (!) Nilai sebelumnya. Sekarang kunci ROB_1 di server Vault adalah 543210987654321. Menariknya, server Vault tidak memblokir tindakan tersebut dan dengan mudah menimpa nilai lama.



Sekarang kita dapat melihat mengapa pemisahan menurut server per Vault bisa menjadi penting - saat Anda menggunakan keyring_udf dan ingin menyimpan kunci di Vault. Bagaimana Anda memberikan pemisahan ini di server Vault?



Ada dua cara untuk membagi menjadi Vault. Anda dapat membuat titik pemasangan yang berbeda untuk setiap server, atau menggunakan jalur berbeda dalam titik pemasangan yang sama. Ini paling baik diilustrasikan dengan contoh. Jadi mari kita lihat masing-masing titik pemasangan:



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


Di sini Anda dapat melihat bahwa server1 dan server2 menggunakan titik pemasangan yang berbeda. Saat memisahkan jalur, konfigurasinya akan terlihat seperti ini:



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


Dalam kasus ini, kedua server menggunakan mount_point yang sama, tetapi jalur yang berbeda. Ketika rahasia pertama dibuat di server1 di sepanjang jalur ini, Vault secara otomatis membuat direktori "server1". Untuk server2, semuanya sama. Saat Anda menghapus rahasia terakhir di mount_point / server1 atau mount_point / server2, server Vault juga menghapus direktori tersebut. Jika Anda menggunakan pemisahan jalur, Anda hanya perlu membuat satu titik pemasangan dan mengubah file konfigurasi sehingga server menggunakan jalur terpisah. Titik pemasangan dapat dibuat menggunakan permintaan HTTP. Dengan CURL, itu bisa dilakukan seperti ini:



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


Semua bidang (TOKEN, VAULT_CA, VAULT_URL, SECRET_MOUNT_POINT) sesuai dengan parameter di file konfigurasi. Anda tentu saja dapat menggunakan utilitas Vault untuk melakukan hal yang sama. Tetapi ini membuatnya lebih mudah untuk mengotomatiskan pembuatan titik pemasangan. Saya harap informasi ini bermanfaat bagi Anda dan sampai jumpa di artikel berikutnya dalam seri ini.





Baca lebih banyak:






All Articles