Enkripsi di MySQL: Keystore

Untuk mengantisipasi dimulainya pendaftaran baru untuk kursus "basis data" Kami telah menyiapkan terjemahan artikel yang bermanfaat untuk Anda.

Enkripsi di MySQL: Keystore

Enkripsi Data Transparan (TDE) muncul di Server Percona untuk MySQL dan MySQL selama beberapa waktu. Namun pernahkah Anda memikirkan cara kerjanya dan apa dampak TDE pada server Anda? Dalam rangkaian artikel ini kita akan melihat cara kerja TDE secara internal. Mari kita mulai dengan penyimpanan kunci, karena ini diperlukan agar enkripsi apa pun dapat berfungsi. Kemudian kita akan melihat lebih dekat cara kerja enkripsi di Percona Server for MySQL/MySQL dan fitur tambahan apa yang dimiliki Percona Server for MySQL.

Gantungan Kunci MySQL

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

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, namun juga saat menjalankannya.

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 penyimpanan berbasis server (seperti Vault Server), hanya id kunci dan pengguna kunci yang dimuat saat startup, sehingga mendapatkan semua kunci tidak memperlambat startup. Kunci dimuat dengan lambat. Artinya, kunci itu sendiri dimuat dari Vault hanya jika benar-benar diperlukan. Setelah diunduh, kunci disimpan dalam cache di memori sehingga tidak perlu diakses melalui koneksi TLS ke Server Vault di masa mendatang. Selanjutnya, mari kita lihat informasi apa saja yang ada di penyimpanan kunci.

Informasi utama berisi hal-hal berikut:

  • id kunci — pengidentifikasi kunci, misalnya:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • jenis kunci — jenis kunci berdasarkan algoritma enkripsi yang digunakan, nilai yang mungkin: “AES”, “RSA” atau “DSA”.
  • panjang kunci — panjang kunci dalam byte, AES: 16, 24 atau 32, RSA 128, 256, 512 dan DSA 128, 256 atau 384.
  • pemakai - pemilik kunci. Jika kuncinya adalah sistem, misalnya Master Key, maka kolom ini kosong. Jika kunci dibuat menggunakan keyring_udf, maka bidang ini mengidentifikasi pemilik kunci tersebut.
  • kunci itu sendiri

Kuncinya diidentifikasi secara unik oleh pasangan: key_id, pengguna.

Ada juga perbedaan dalam menyimpan dan menghapus kunci.

Penyimpanan file lebih cepat. Anda mungkin berpikir bahwa penyimpanan kunci hanya menulis kunci ke sebuah file satu kali, namun tidak, masih banyak lagi yang terjadi di sini. Setiap kali modifikasi penyimpanan file dilakukan, salinan cadangan semua konten dibuat terlebih dahulu. Katakanlah file tersebut bernama my_biggest_secrets, maka salinan cadangannya adalah my_biggest_secrets.backup. Selanjutnya, cache diubah (kunci ditambahkan atau dihapus) dan, jika semuanya berhasil, cache diatur ulang ke file. Dalam kasus yang jarang terjadi, seperti kegagalan server, Anda mungkin melihat file cadangan ini. File cadangan akan dihapus saat kunci dimuat lagi (biasanya setelah server di-restart).

Saat menyimpan atau menghapus kunci di penyimpanan server, penyimpanan tersebut harus terhubung ke server MySQL dengan perintah “kirim kunci” / “request key deletion”.

Mari kembali ke kecepatan startup server. Selain fakta bahwa kecepatan peluncuran dipengaruhi oleh brankas itu sendiri, ada juga masalah berapa banyak kunci dari brankas yang perlu diambil saat startup. Tentu saja ini sangat penting terutama untuk penyimpanan server. Saat startup, server memeriksa kunci mana yang diperlukan untuk tabel/ruang tabel terenkripsi dan meminta kunci dari penyimpanan. Pada server “bersih” dengan enkripsi Master Key, harus ada satu Master Key yang harus diambil dari penyimpanan. Namun, jumlah kunci yang lebih besar mungkin diperlukan, misalnya, ketika server cadangan memulihkan cadangan dari server utama. Dalam kasus seperti ini, rotasi Kunci Master harus disediakan. Hal ini akan dibahas lebih rinci di artikel mendatang, meskipun di sini saya ingin mencatat bahwa server yang menggunakan beberapa Kunci Master mungkin memerlukan 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 khawatir 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, yang diingat oleh server, dan perubahan hanya diterapkan jika cocok. Ketika file berubah, checksum diperbarui.

Kami telah membahas banyak pertanyaan tentang brankas kunci. Namun, ada topik penting lainnya yang sering dilupakan atau disalahpahami: berbagi kunci antar server.

Apa yang saya maksud? Setiap server (misalnya, Percona Server) di cluster harus memiliki lokasi terpisah di Vault Server tempat Server Percona harus menyimpan kuncinya. Setiap Kunci Master yang disimpan di penyimpanan berisi GUID Server Percona di dalam pengidentifikasinya. 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. Apa yang disediakan GUID adalah perbedaan antar server. Lalu mengapa berbicara tentang berbagi kunci antar server jika GUID unik sudah ada? Ada plugin lain - keyring_udf. Dengan plugin ini, pengguna server Anda dapat menyimpan kuncinya di server Vault. Masalah terjadi ketika pengguna membuat kunci di server1, misalnya, lalu 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 Vault Server yang sama, bukankah fungsi keyring_key_store gagal di server2? Menariknya, jika Anda mencoba melakukan hal yang sama di satu server, Anda akan menerima pesan kesalahan:

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

Betul, ROB_1 sudah ada.

Mari kita bahas contoh kedua terlebih dahulu. Seperti yang kami katakan sebelumnya, keyring_vault atau plugin keyring lainnya menyimpan semua ID kunci dalam 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 tersebut 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 server Vault, cache kunci di server2 tidak sinkron. Tidak ada kunci ROB_2 di cache di server1. Jadi, 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 partisi server di Vault menjadi penting - ketika Anda menggunakan keyring_udf dan ingin menyimpan kunci di Vault. Bagaimana cara mencapai pemisahan ini di server Vault?

Ada dua cara untuk mempartisi ke dalam Vault. Anda dapat membuat titik pemasangan berbeda untuk setiap server, atau menggunakan jalur berbeda dalam titik pemasangan yang sama. Hal ini paling baik diilustrasikan dengan contoh. Jadi mari kita lihat masing-masing titik pemasangan terlebih dahulu:

--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 mount 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 hal ini, kedua server menggunakan titik pemasangan "mount_point" yang sama, tetapi jalurnya berbeda. Saat Anda membuat rahasia pertama di server1 menggunakan jalur ini, server Vault secara otomatis membuat direktori “server1”. Untuk server2 semuanya serupa. 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 harus membuat hanya satu titik pemasangan dan mengubah file konfigurasi sehingga server menggunakan jalur terpisah. Titik pemasangan dapat dibuat menggunakan permintaan HTTP. Menggunakan CURL ini 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 file konfigurasi. Tentu saja, Anda dapat menggunakan utilitas Vault untuk melakukan hal yang sama. Namun lebih mudah untuk mengotomatiskan pembuatan titik pemasangan. Saya harap informasi ini bermanfaat bagi Anda dan sampai jumpa di artikel berikutnya dalam seri ini.

Enkripsi di MySQL: Keystore

Baca selengkapnya:

Sumber: www.habr.com

Tambah komentar