Cifrado en MySQL: Almacén de claves

En previsión del inicio de una nueva matrícula para el curso "Base de datos" Hemos preparado una traducción de un artículo útil para usted.

Cifrado en MySQL: Almacén de claves

El cifrado de datos transparente (TDE) apareció en Servidor Percona para MySQL y MySQL desde hace bastante tiempo. Pero ¿alguna vez has pensado en cómo funciona internamente y qué impacto puede tener TDE en tu servidor? En esta serie de artículos veremos cómo funciona TDE internamente. Comencemos con el almacenamiento de claves, ya que es necesario para que funcione cualquier cifrado. Luego, veremos más de cerca cómo funciona el cifrado en Percona Server para MySQL/MySQL y qué características adicionales tiene Percona Server para MySQL.

Llavero MySQL

Los llaveros son complementos que permiten al servidor consultar, crear y eliminar claves en un archivo local (keyring_file) o en un servidor remoto (como 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 conjunto de claves basado en archivos).
  • Almacenamiento remoto. Por ejemplo, Vault Server (lo llamamos llavero basado en servidor).

Esta separación es importante porque los distintos tipos de almacenamiento se comportan de forma ligeramente diferente, no sólo al almacenar y recuperar claves, sino también al ejecutarlas.

Cuando se utiliza un almacenamiento de archivos, al iniciar, todo el contenido del almacenamiento se carga en la caché: ID de clave, usuario de clave, tipo de clave y la clave misma.

En el caso de un almacén del lado del servidor (como Vault Server), solo se cargan la identificación de la clave y el usuario de la clave al inicio, por lo que obtener todas las claves no ralentiza el inicio. Las claves se cargan con pereza. Es decir, la clave en sí se carga desde Vault solo cuando realmente es necesaria. Una vez descargada, la clave se almacena en caché en la memoria para que no sea necesario acceder a ella a través de conexiones TLS al servidor Vault en el futuro. A continuación, veamos qué información está presente en el almacén de claves.

La información clave contiene lo siguiente:

  • identificación clave — identificador de clave, por ejemplo:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • tipo de clave — tipo de clave según el algoritmo de cifrado utilizado, valores posibles: “AES”, “RSA” o “DSA”.
  • longitud de la clave — longitud de clave en bytes, AES: 16, 24 o 32, RSA 128, 256, 512 y DSA 128, 256 o 384.
  • usuario - dueño de la llave. Si la clave es del sistema, por ejemplo, Master Key, entonces este campo está vacío. Si se crea una clave usando keyring_udf, este campo identifica al propietario de la clave.
  • la clave misma

La clave se identifica de forma única mediante el par: key_id, usuario.

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

El almacenamiento de archivos es más rápido. Se podría pensar que un almacén de claves consiste simplemente en escribir la clave en un archivo una vez, pero no, aquí hay más cosas que hacer. Siempre que se realiza una modificación en el almacenamiento de archivos, primero se crea una copia de seguridad de todo el contenido. Digamos que el archivo se llama my_biggest_secrets, entonces la copia de seguridad será my_biggest_secrets.backup. A continuación, se cambia el caché (se agregan o eliminan claves) y, si todo es exitoso, el caché se restablece a un archivo. En casos excepcionales, como una falla del servidor, es posible que vea este archivo de respaldo. El archivo de copia de seguridad se elimina la próxima vez que se cargan las claves (normalmente después de reiniciar el servidor).

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

Volvamos a la velocidad de inicio del servidor. Además del hecho de que la velocidad de inicio se ve afectada por la propia bóveda, también existe la cuestión de cuántas claves de la bóveda deben recuperarse al inicio. Por supuesto, esto es especialmente importante para el almacenamiento en servidores. Al inicio, el servidor comprueba qué clave se requiere para las tablas/espacios de tablas cifrados y solicita la clave del almacenamiento. En un servidor "limpio" con cifrado de clave maestra, debe haber una clave maestra, que debe recuperarse del almacenamiento. Sin embargo, es posible que se requiera una mayor cantidad de claves, por ejemplo, cuando el servidor de respaldo está restaurando una copia de seguridad del servidor primario. En tales casos, se debe prever la rotación de la llave maestra. Esto se tratará con más detalle en artículos futuros, aunque aquí me gustaría señalar que un servidor que utiliza varias claves maestras puede tardar un poco más en iniciarse, especialmente cuando se utiliza un almacén de claves del lado del servidor.

Ahora hablemos un poco más sobre keyring_file. Cuando estaba desarrollando keyring_file, también me preocupaba cómo verificar los cambios en keyring_file mientras el servidor se estaba ejecutando. En 5.7, la verificación se realizaba basándose en estadísticas de archivos, lo que no era una solución ideal, y en 8.0 se reemplazó con una suma de verificación SHA256.

La primera vez que ejecuta keyring_file, se calculan las estadísticas del archivo y una suma de verificación, que el servidor recuerda y los cambios solo se aplican si coinciden. Cuando el archivo cambia, la suma de comprobación se actualiza.

Ya hemos cubierto muchas preguntas sobre los almacenes de claves. Sin embargo, hay otro tema importante que a menudo se olvida o se malinterpreta: compartir claves entre servidores.

¿Lo que quiero decir? Cada servidor (por ejemplo, Percona Server) en el clúster debe tener una ubicación separada en Vault Server en la que Percona Server debe almacenar sus claves. Cada clave maestra guardada en el almacenamiento contiene el GUID del servidor Percona dentro de su identificador. ¿Por qué es importante? Imagine que tiene solo un servidor Vault y todos los servidores Percona en el clúster usan ese único servidor Vault. El problema parece obvio. Si todos los servidores Percona usaran una clave maestra sin identificadores únicos, como id = 1, id = 2, etc., entonces todos los servidores del clúster usarían la misma clave maestra. Lo que proporciona el GUID es la distinción entre servidores. ¿Por qué entonces hablar de compartir claves entre servidores si ya existe un GUID único? Hay otro complemento: keyring_udf. Con este complemento, el usuario de su servidor puede almacenar sus claves en el servidor Vault. El problema ocurre cuando un usuario crea una clave en el servidor1, por ejemplo, y luego intenta crear una clave con el mismo ID en el servidor2, por ejemplo:

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

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

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

Así es, ROB_1 ya existe.

Analicemos primero el segundo ejemplo. Como dijimos anteriormente, keyring_vault o cualquier otro complemento de llavero almacena en caché todos los ID de clave en la memoria. Entonces, después de crear una nueva clave, ROB_1 se agrega al servidor1 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 la clave existe en el caché y arroja un error.

En el primer caso la situación es diferente. El servidor1 y el servidor2 tienen cachés separados. Después de agregar ROB_1 al caché de claves en el servidor1 y al servidor Vault, el caché de claves en el servidor2 no está sincronizado. No hay ninguna clave ROB_2 en la memoria caché del servidor 1. Por lo tanto, la clave ROB_1 se escribe en keyring_key_store y en el servidor Vault, que en realidad sobrescribe (!) el valor anterior. Ahora la clave ROB_1 en el servidor Vault es 543210987654321. Curiosamente, el servidor Vault no bloquea tales acciones y sobrescribe fácilmente el valor anterior.

Ahora podemos ver por qué la partición del servidor en Vault puede ser importante: cuando utiliza keyring_udf y desea almacenar claves en Vault. ¿Cómo lograr esta separación en un servidor Vault?

Hay dos formas de realizar particiones en Vault. Puede crear diferentes puntos de montaje para cada servidor o utilizar diferentes rutas dentro del mismo punto de montaje. Esto se ilustra mejor con ejemplos. Entonces, veamos primero los puntos de montaje individuales:

--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í puede ver que el servidor1 y el servidor2 utilizan diferentes puntos de montaje. Al dividir las rutas, la configuración se verá así:

--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 rutas diferentes. Cuando crea el primer secreto en el servidor1 usando esta ruta, el servidor Vault crea automáticamente un directorio "servidor1". Para el servidor2 todo es similar. Cuando elimina el último secreto en punto_montaje/servidor1 o punto_montaje/servidor2, el servidor Vault también elimina esos directorios. En caso de que utilice la separación de rutas, debe crear solo un punto de montaje y cambiar los archivos de configuración para que los servidores utilicen rutas separadas. Se puede crear un punto de montaje mediante una solicitud HTTP. Usando CURL esto se puede hacer así:

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, puedes utilizar las utilidades de Vault para hacer lo mismo. Pero es más fácil automatizar la creación de un punto de montaje. Espero que encuentres útil esta información y nos vemos en los próximos artículos de esta serie.

Cifrado en MySQL: Almacén de claves

Lee mas:

Fuente: habr.com

Añadir un comentario