Cifrado en MySQL: almacenamiento de claves

Con la próxima apertura del nuevo ciclo del curso «Bases de Datos» hemos preparado para ustedes la traducción de un artículo útil.

Cifrado en MySQL: almacenamiento de claves

El cifrado transparente de datos (Transparent Data Encryption, TDE) se introdujo en Percona Server for MySQL y MySQL hace bastante tiempo. Pero, ¿alguna vez se han preguntado cómo funciona internamente y qué impacto puede tener TDE en su servidor? En esta serie de artículos exploraremos cómo funciona TDE por dentro. Comenzaremos con el almacenamiento de claves, ya que es necesario para cualquier cifrado. Luego examinaremos en detalle cómo funciona el cifrado en Percona Server for MySQL/MySQL y qué funcionalidades adicionales ofrece Percona Server for MySQL.

MySQL Keyring

Keyring son complementos que permiten al servidor solicitar, crear y eliminar claves en un archivo local (keyring_file) o en un servidor remoto (por ejemplo, en HashiCorp Vault). Las claves siempre se almacenan en caché localmente para acelerar su recuperación.

Los complementos se pueden dividir en dos categorías:

  • Almacenamiento local. Por ejemplo, un archivo local (lo llamamos almacenamiento de claves basado en archivos, file-based keyring).
  • Almacenamiento remoto. Por ejemplo, un servidor Vault (lo llamamos almacenamiento de claves basado en servidor, server-based keyring).

Esta división es importante porque diferentes tipos de almacenamiento se comportan un poco de manera diferente no solo al almacenar y recuperar claves, sino también al iniciar.

Al usar el almacenamiento basado en archivos, el contenido completo del almacenamiento se carga en la caché al iniciar: id de clave, usuario de clave, tipo de clave y la propia clave.

En el caso del almacenamiento basado en servidor (por ejemplo, el servidor Vault), al iniciar solo se cargan el id de clave y el usuario de clave, por lo que la obtención de todas las claves no ralentiza el inicio. Las claves se cargan de manera perezosa, es decir, la clave en sí se carga desde Vault solo cuando realmente se necesita. Después de la carga, la clave se almacena en la memoria para que no sea necesario volver a acceder a ella a través de conexiones TLS al servidor Vault. A continuación, veamos qué información contiene el almacenamiento de claves.

La información sobre la clave contiene lo siguiente:

  • id de clave — el identificador de la clave, por ejemplo:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • tipo de clave — el tipo de clave, basado en el algoritmo de cifrado utilizado, posibles valores: «AES», «RSA» o «DSA».
  • longitud de clave — la longitud de la clave en bytes, AES: 16, 24 o 32, RSA 128, 256, 512 y DSA 128, 256 o 384.
  • usuario — propietario de la clave. Si la clave es del sistema, como la Master Key, este campo estará vacío. Si la clave se crea usando keyring_udf, este campo indica el propietario de la clave.
  • la propia clave

La clave se identifica de manera inequívoca por un par: key_id, user.

También hay diferencias en el almacenamiento y eliminación de claves.

El almacenamiento de archivos es más rápido. Se podría suponer que el almacenamiento de claves es simplemente una grabación única de la clave en un archivo, pero no es así: aquí se realizan más operaciones. Ante cualquier modificación del almacenamiento de archivos, primero se crea una copia de seguridad de todo el contenido. Supongamos que el archivo se llama my_biggest_secrets, entonces la copia de seguridad será my_biggest_secrets.backup. A continuación, se modifica la caché (se agregan o eliminan claves) y, si todo se realiza con éxito, la caché se restablece en el archivo. En raras ocasiones, como en un fallo del servidor, puede que veas este archivo de copia de seguridad. El archivo de copia de seguridad se elimina en la siguiente carga de claves (generalmente después de reiniciar el servidor).

Al guardar o eliminar una clave en el almacenamiento del servidor, el almacenamiento debe conectarse al servidor MySQL con los comandos 'enviar clave' / 'solicitar eliminación de clave'.

Regresando a la velocidad de inicio del servidor. Además de que el almacenamiento en sí afecta la velocidad de inicio, también existe la cuestión de cuántas claves del almacenamiento es necesario obtener al iniciar. Por supuesto, esto es especialmente importante para los almacenamientos de servidores. Al iniciarse, el servidor verifica qué clave es necesaria para las tablas cifradas / espacios de tablas y solicita la clave del almacenamiento. En un servidor 'limpio' con cifrado de Master Key, debe haber una sola Master Key que se debe extraer del almacenamiento. Sin embargo, puede ser necesaria una mayor cantidad de claves, por ejemplo, cuando en un servidor de respaldo se restaura una copia de seguridad del servidor principal. En tales casos, se debe considerar la rotación de la Master Key. Esto se abordará con más detalle en artículos futuros, aunque aquí quisiera señalar que un servidor que utiliza múltiples Master Keys puede tardar un poco más en arrancar, especialmente cuando se utiliza el almacenamiento de claves del servidor.

Ahora hablemos un poco más sobre keyring_file. Cuando desarrollé keyring_file, también me preocupaba cómo verificar los cambios en keyring_file durante el funcionamiento del servidor. En 5.7, la verificación se realizaba sobre la base de estadísticas del archivo, lo cual no era una solución ideal, y en 8.0 fue reemplazada por un hash SHA256.

En el primer inicio, se calcula la estadística y el hash del archivo keyring_file, que son almacenados por el servidor, y los cambios se aplican solo si coinciden. Al modificar el archivo, se actualiza el hash.

Ya hemos tratado muchos temas sobre los almacenes de claves. Sin embargo, hay un tema importante que a menudo se olvida o se entiende mal: la separación de claves entre servidores.

¿A qué me refiero? Cada servidor (por ejemplo, Percona Server) en un clúster debe tener su propio lugar en el servidor Vault, donde Percona Server debe almacenar sus claves. Cada Master Key almacenado en el depósito contiene el GUID del servidor Percona Server dentro de su identificador. ¿Por qué es importante? Imagina que tienes solo un servidor Vault y todos los Percona Server en el clúster utilizan ese único servidor Vault. El problema parece obvio. Si todos los Percona Server utilizaran un Master Key sin identificadores únicos, por ejemplo, id = 1, id = 2, etc., entonces todos los servidores en el clúster usarían el mismo Master Key. Lo que proporciona el GUID es la separación entre servidores. ¿Por qué hablar entonces de la separación de claves entre servidores si ya existe un GUID único? Hay otro complemento: keyring_udf. Con este complemento, un usuario de tu servidor puede almacenar sus claves en el servidor Vault. El problema surge cuando el usuario crea una clave, por ejemplo, en el servidor server1, y luego intenta crear una clave con el mismo identificador en server2, por ejemplo:

--server1:
select keyring_key_store('ROB_1','AES',"123456789012345");
1
--1 significa finalización exitosa
--server2:
select keyring_key_store('ROB_1','AES',"543210987654321");
1

Espera. Ambos servidores utilizan el mismo servidor Vault, ¿no debería la función keyring_key_store terminar con un error en el servidor server2? Curiosamente, si intentas hacer lo mismo en un solo servidor, recibirás un error:

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

Correcto, ROB_1 ya existe.

Primero, discutamos el segundo ejemplo. Como mencionamos anteriormente, keyring_vault o cualquier otro complemento de almacenamiento (keyring) almacena en caché todos los identificadores de claves en memoria. Así, después de crear una nueva clave, ROB_1 se añade en server1, y además de enviar esta clave a Vault, la clave también se agrega a la caché. Ahora, cuando intentamos agregar la misma clave por segunda vez, keyring_vault verifica si esta clave existe en la caché y genera un error.

En el primer caso, la situación es diferente. Los servidores server1 y server2 tienen cachés separados. Después de agregar ROB_1 a la caché de claves en server1 y en el servidor Vault, la caché de claves en server2 no está sincronizada. En la caché de server2 no hay clave ROB_1. Por lo tanto, la clave ROB_1 se almacena en keyring_key_store y en el servidor Vault, que efectivamente sobrescribe (!) el valor anterior. Ahora la clave ROB_1 en el servidor Vault es igual a 543210987654321. Curiosamente, el servidor Vault no bloquea tales acciones y reescribe fácilmente el valor antiguo.

Ahora vemos por qué la separación en servidores en Vault puede ser importante, cuando se utiliza keyring_udf y se desea almacenar claves en Vault. ¿Cómo asegurar tal separación en el servidor Vault?

Hay dos métodos para la separación en Vault. Se pueden crear diferentes puntos de montaje para cada servidor o usar diferentes rutas dentro de un mismo punto de montaje. Esto se puede mostrar mejor con ejemplos. Así que empecemos primero con puntos de montaje separados:

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

Aquí se puede ver que server1 y server2 utilizan diferentes puntos de montaje. Al separar las rutas, la configuración se verá de la siguiente manera:

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

En este caso, ambos servidores utilizan el mismo punto de montaje «mount_point», pero diferentes rutas. Al crear el primer secreto en el servidor server1 en esta ruta, el servidor Vault crea automáticamente el directorio «server1». Lo mismo sucede con server2. Cuando eliminas el último secreto en mount_point/server1 o mount_point/server2, el servidor Vault también elimina estos directorios. Si utilizas la separación de rutas, debes crear solo un punto de montaje y modificar los archivos de configuración para que los servidores usen rutas separadas. El punto de montaje se puede crear mediante una solicitud HTTP. Con CURL, se puede hacer de la siguiente manera:

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

Todos los campos (TOKEN, VAULT_CA, VAULT_URL, SECRET_MOUNT_POINT) corresponden a los parámetros del archivo de configuración. Por supuesto, se pueden utilizar utilidades de Vault para hacer lo mismo. Pero es más sencillo automatizar la creación del punto de montaje. Espero que esta información te resulte útil y nos vemos en los próximos artículos de esta serie.

Cifrado en MySQL: almacenamiento de claves

Leer más:

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster