Κρυπτογράφηση σε MySQL: Keystore

Εν αναμονή της έναρξης νέας εγγραφής για το μάθημα "Βάση δεδομένων" ετοίμασε μια μετάφραση ενός χρήσιμου άρθρου για εσάς.

Κρυπτογράφηση σε MySQL: Keystore

Η κρυπτογράφηση διαφανών δεδομένων (TDE) εμφανίστηκε στο Διακομιστής Percona για MySQL και MySQL εδώ και αρκετό καιρό. Αλλά έχετε σκεφτεί ποτέ πώς λειτουργεί κάτω από την κουκούλα και τι αντίκτυπο μπορεί να έχει το TDE στον διακομιστή σας; Σε αυτήν τη σειρά άρθρων, θα ρίξουμε μια ματιά στον τρόπο λειτουργίας του TDE εσωτερικά. Ας ξεκινήσουμε με την αποθήκευση κλειδιών, καθώς απαιτείται για να λειτουργήσει οποιαδήποτε κρυπτογράφηση. Στη συνέχεια, θα ρίξουμε μια πιο προσεκτική ματιά στο πώς λειτουργεί η κρυπτογράφηση στον Percona Server για MySQL/MySQL και ποιες πρόσθετες δυνατότητες είναι διαθέσιμες στον Percona Server για MySQL.

MySQL Keyring

Τα μπρελόκ είναι πρόσθετα που επιτρέπουν στον διακομιστή να κάνει ερώτημα, να δημιουργεί και να διαγράφει κλειδιά σε ένα τοπικό αρχείο (keyring_file) ή σε έναν απομακρυσμένο διακομιστή (για παράδειγμα, στο HashiCorp Vault). Τα κλειδιά αποθηκεύονται πάντα τοπικά για να επιταχυνθεί η ανάκτηση.

Τα πρόσθετα μπορούν να χωριστούν σε δύο κατηγορίες:

  • Τοπική αποθήκευση. Για παράδειγμα, ένα τοπικό αρχείο (το ονομάζουμε μπρελόκ που βασίζεται σε αρχείο).
  • απομακρυσμένη αποθήκευση. Για παράδειγμα Vault Server (τον ονομάζουμε μπρελόκ που βασίζεται σε διακομιστή).

Αυτός ο διαχωρισμός είναι σημαντικός επειδή οι διαφορετικοί τύποι αποθήκευσης συμπεριφέρονται ελαφρώς διαφορετικά όχι μόνο κατά την αποθήκευση και ανάκτηση κλειδιών, αλλά και κατά την εκκίνηση.

Όταν χρησιμοποιείτε την αποθήκευση αρχείων, όλα τα περιεχόμενα του χώρου αποθήκευσης φορτώνονται στην κρυφή μνήμη κατά την εκκίνηση: αναγνωριστικό κλειδιού, χρήστης κλειδιού, τύπος κλειδιού και το ίδιο το κλειδί.

Στην περίπτωση ενός back-end store (για παράδειγμα, ο διακομιστής Vault), μόνο το αναγνωριστικό κλειδιού και ο βασικός χρήστης φορτώνονται κατά την εκκίνηση, επομένως η λήψη όλων των κλειδιών δεν επιβραδύνει την εκκίνηση. Τα κλειδιά φορτώνονται νωχελικά. Δηλαδή, το ίδιο το κλειδί φορτώνεται από το Vault μόνο όταν είναι πραγματικά απαραίτητο. Μετά τη λήψη, το κλειδί αποθηκεύεται προσωρινά στη μνήμη, έτσι ώστε στο μέλλον να μην υπάρχει ανάγκη πρόσβασης σε αυτό μέσω συνδέσεων TLS στον διακομιστή Vault. Στη συνέχεια, εξετάστε ποιες πληροφορίες υπάρχουν στο χώρο αποθήκευσης κλειδιών.

Οι βασικές πληροφορίες περιέχουν τα ακόλουθα:

  • αναγνωριστικό κλειδιού - αναγνωριστικό κλειδιού, για παράδειγμα:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • τύπος κλειδιού - τύπος κλειδιού με βάση τον αλγόριθμο κρυπτογράφησης που χρησιμοποιείται, πιθανές τιμές: "AES", "RSA" ή "DSA".
  • μήκος κλειδιού - Μήκος κλειδιού σε byte, AES: 16, 24 ή 32, RSA 128, 256, 512 και DSA 128, 256 ή 384.
  • χρήστη είναι ο κάτοχος του κλειδιού. Εάν το κλειδί είναι κλειδί συστήματος, όπως το Κύριο κλειδί, τότε αυτό το πεδίο είναι κενό. Εάν το κλειδί έχει δημιουργηθεί χρησιμοποιώντας το keyring_udf, τότε αυτό το πεδίο υποδεικνύει τον κάτοχο του κλειδιού.
  • το ίδιο το κλειδί

Το κλειδί προσδιορίζεται μοναδικά από το ζεύγος: key_id, χρήστης.

Υπάρχουν επίσης διαφορές στην αποθήκευση και τη διαγραφή κλειδιών.

Η αποθήκευση αρχείων είναι ταχύτερη. Μπορεί να πιστεύετε ότι το keystore είναι απλώς μια εφάπαξ εγγραφή του κλειδιού σε ένα αρχείο, αλλά δεν είναι - υπάρχουν περισσότερα που συμβαίνουν εδώ. Κάθε φορά που τροποποιείται ένας χώρος αποθήκευσης αρχείου, πρώτα δημιουργείται αντίγραφο ασφαλείας όλου του περιεχομένου. Ας υποθέσουμε ότι το αρχείο ονομάζεται my_biggest_secrets, τότε το αντίγραφο ασφαλείας θα είναι my_biggest_secrets.backup. Στη συνέχεια, η προσωρινή μνήμη αλλάζει (προστίθενται ή αφαιρούνται τα κλειδιά) και, εάν όλα είναι επιτυχή, η προσωρινή μνήμη απορρίπτεται σε ένα αρχείο. Σε σπάνιες περιπτώσεις, όπως κατάρρευση διακομιστή, ενδέχεται να δείτε αυτό το αρχείο αντιγράφου ασφαλείας. Το αρχείο αντιγράφου ασφαλείας διαγράφεται την επόμενη φορά που θα φορτωθούν τα κλειδιά (συνήθως μετά από επανεκκίνηση διακομιστή).

Κατά την αποθήκευση ή τη διαγραφή ενός κλειδιού στο χώρο αποθήκευσης διακομιστή, το κατάστημα πρέπει να συνδεθεί στον διακομιστή MySQL με τις εντολές "αποστολή κλειδιού" / "Αίτημα διαγραφής κλειδιού".

Ας επιστρέψουμε στην ταχύτητα εκκίνησης του διακομιστή. Εκτός από το γεγονός ότι το ίδιο το θησαυροφυλάκιο επηρεάζει την ταχύτητα εκκίνησης, υπάρχει επίσης το ερώτημα πόσα κλειδιά από το θησαυροφυλάκιο πρέπει να ληφθούν κατά την εκκίνηση. Φυσικά, αυτό είναι ιδιαίτερα σημαντικό για τις αποθήκες διακομιστή. Κατά την εκκίνηση, ο διακομιστής ελέγχει ποιο κλειδί χρειάζεται για τους κρυπτογραφημένους πίνακες/χώρους πινάκων και ζητά το κλειδί από το χώρο αποθήκευσης. Σε έναν "καθαρό" διακομιστή με κύριο κλειδί - πρέπει να υπάρχει ένα κύριο κλειδί για κρυπτογράφηση, το οποίο πρέπει να ανακτηθεί από την αποθήκευση. Ωστόσο, ενδέχεται να απαιτούνται περισσότερα κλειδιά, για παράδειγμα, όταν επαναφέρεται ένα αντίγραφο ασφαλείας από τον κύριο διακομιστή σε έναν διακομιστή αναμονής. Σε τέτοιες περιπτώσεις, θα πρέπει να παρέχεται η εναλλαγή του κύριου κλειδιού. Αυτό θα συζητηθεί με περισσότερες λεπτομέρειες σε μελλοντικά άρθρα, αν και εδώ θα ήθελα να σημειώσω ότι ένας διακομιστής που χρησιμοποιεί πολλαπλά κύρια κλειδιά μπορεί να χρειαστεί λίγο περισσότερο χρόνο για να ξεκινήσει, ειδικά όταν χρησιμοποιείται αποθήκευση κλειδιών διακομιστή.

Τώρα ας μιλήσουμε λίγο περισσότερο για το keyring_file. Όταν σχεδίαζα το keyring_file, ανησυχούσα επίσης για το πώς να ελέγξω για αλλαγές στο keyring_file ενώ ο διακομιστής εκτελείται. Στο 5.7, ο έλεγχος έγινε βάσει στατιστικών αρχείων, κάτι που δεν ήταν ιδανικό, και στο 8.0 αντικαταστάθηκε με άθροισμα ελέγχου SHA256.

Την πρώτη φορά που εκτελείται το keyring_file, τα στατιστικά στοιχεία του αρχείου και το άθροισμα ελέγχου υπολογίζονται και απομνημονεύονται από τον διακομιστή και οι αλλαγές εφαρμόζονται μόνο εάν ταιριάζουν. Όταν αλλάξει το αρχείο, το άθροισμα ελέγχου ενημερώνεται.

Έχουμε ήδη καλύψει πολλές ερωτήσεις σχετικά με τα keystores. Ωστόσο, υπάρχει ένα άλλο σημαντικό θέμα που συχνά ξεχνιέται ή παρεξηγείται - η κοινή χρήση κλειδιών μεταξύ των διακομιστών.

Τι εννοώ? Κάθε διακομιστής (για παράδειγμα, διακομιστής Percona) στο σύμπλεγμα πρέπει να έχει μια ξεχωριστή θέση στο διακομιστή Vault στον οποίο ο διακομιστής Percona πρέπει να αποθηκεύσει τα κλειδιά του. Κάθε κύριο κλειδί που είναι αποθηκευμένο στο θησαυροφυλάκιο περιέχει το GUID διακομιστή Percona στο αναγνωριστικό του. Γιατί είναι σημαντικό? Φανταστείτε ότι έχετε μόνο έναν διακομιστή Vault και όλοι οι διακομιστές Percona στο σύμπλεγμα χρησιμοποιούν αυτόν τον μοναδικό διακομιστή Vault. Το πρόβλημα φαίνεται προφανές. Εάν όλοι οι διακομιστές Percona χρησιμοποιούσαν ένα κύριο κλειδί χωρίς μοναδικά αναγνωριστικά, όπως id = 1, id = 2, κ.λπ., τότε όλοι οι διακομιστές στο σύμπλεγμα θα χρησιμοποιούσαν το ίδιο Κύριο κλειδί. Αυτό παρέχει το GUID - τη διάκριση μεταξύ διακομιστών. Γιατί τότε μιλάμε για κοινή χρήση κλειδιών μεταξύ διακομιστών, εάν υπάρχει ήδη ένα μοναδικό GUID; Υπάρχει ένα άλλο πρόσθετο - keyring_udf. Με αυτό το πρόσθετο, ένας χρήστης του διακομιστή σας μπορεί να αποθηκεύσει τα κλειδιά του στον διακομιστή Vault. Το πρόβλημα παρουσιάζεται όταν ένας χρήστης δημιουργεί ένα κλειδί, για παράδειγμα, στον διακομιστή1 και, στη συνέχεια, προσπαθεί να δημιουργήσει ένα κλειδί με το ίδιο αναγνωριστικό στον διακομιστή2, για παράδειγμα:

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

Περίμενε. Και οι δύο διακομιστές χρησιμοποιούν τον ίδιο διακομιστή Vault, δεν θα πρέπει να αποτύχει η λειτουργία keyring_key_store στον διακομιστή2; Είναι ενδιαφέρον ότι αν προσπαθήσετε να κάνετε το ίδιο στον ίδιο διακομιστή, θα λάβετε ένα σφάλμα:

--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 προστίθεται στον διακομιστή1 και εκτός από την αποστολή αυτού του κλειδιού στο Vault, το κλειδί προστίθεται και στην κρυφή μνήμη. Τώρα, όταν προσπαθούμε να προσθέσουμε το ίδιο κλειδί για δεύτερη φορά, το keyring_vault ελέγχει αν το κλειδί υπάρχει στην κρυφή μνήμη και βγάζει ένα σφάλμα.

Στην πρώτη περίπτωση, η κατάσταση είναι διαφορετική. Ο διακομιστής 1 και ο διακομιστής 2 έχουν ξεχωριστές κρυφές μνήμες. Μετά την προσθήκη του ROB_1 στην κρυφή μνήμη του κλειδιού στον διακομιστή1 και στον διακομιστή Vault, η κρυφή μνήμη του κλειδιού στον διακομιστή2 είναι εκτός συγχρονισμού. Η κρυφή μνήμη στο διακομιστή2 δεν περιέχει το κλειδί 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 = (...)

Εδώ μπορείτε να δείτε ότι ο διακομιστής1 και ο διακομιστής2 χρησιμοποιούν διαφορετικά σημεία προσάρτησης. Με τον διαχωρισμό διαδρομής, η διαμόρφωση θα μοιάζει με αυτό:

--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" αλλά διαφορετικές διαδρομές. Όταν δημιουργείτε το πρώτο μυστικό στον διακομιστή1 χρησιμοποιώντας αυτήν τη διαδρομή, ο διακομιστής 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: Keystore

Διαβάστε περισσότερα:

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο