Cómo configurar SSL/TLS para MySQL en Ubuntu 18.04

Introducción

MySQL es el sistema de gestión de bases de datos relacionales de código abierto más popular del mundo. Si bien los administradores de paquetes modernos han reducido parte de la fricción para que MySQL esté en funcionamiento, todavía hay una configuración adicional que se debe realizar después de instalarlo. Uno de los aspectos más importantes para pasar un tiempo extra es la seguridad.

Por defecto, MySQL está configurado para aceptar solo conexiones locales o conexiones que se originan en la misma máquina donde está instalado MySQL. Si necesitas acceder a tu base de datos MySQL desde una ubicación remota, es importante que lo hagas de manera segura.

En esta guía, demostraremos cómo configurar MySQL en Ubuntu 18.04 para aceptar conexiones remotas con cifrado SSL/TLS.

Prerrequisitos

Para completar esta guía, necesitarás:

  • Dos servidores Ubuntu 18.04. Usaremos uno de estos servidores como el servidor MySQL, mientras que usaremos el otro como la máquina cliente. Debes crear un usuario no root con privilegios sudo y habilitar un firewall con ufw cada uno de estos servidores.
  • En una de las máquinas, instala y configura el servidor MySQL. A medida que sigas esta guía, asegúrate de configurar tu usuario root de MySQL para autenticarse con una contraseña, como se describe en el Paso 3 de la guía, ya que es necesario para conectarse a MySQL usando TCP en lugar del socket Unix local.

Ten en cuenta que, a lo largo de esta guía, se hará referencia al servidor en el que instaló MySQL como MySQL server y cualquier comando que deba ejecutarse en esta máquina se mostrará con un indicador, como este:

De manera similar, esta guía se referirá al otro servidor como MySQL client y cualquier comando que deba ejecutarse en esa máquina se mostrará con un indicador similar a este:

Ten esto en cuenta al seguir este tutorial para evitar confusiones.

Paso 1 – Comprobación del estado actual de SSL/TLS de MySQL

Antes de realizar cambios en la configuración, puedes verificar el estado actual de SSL/TLS en la instancia del servidor MySQL.

Utiliza el siguiente comando para comenzar una sesión de MySQL como usuario root de MySQL. Este comando incluye la opción –p, que le indica a mysql que te solicite una contraseña para iniciar sesión.

También incluye la opción –h que se utiliza para especificar el host al que te conectarás. En este caso, apunta a 127.0.0.1 la interfaz de bucle de retorno IPv4 también conocida como localhost.

Esto obligará al cliente a conectarse con TCP en lugar de usar el archivo de socket local. MySQL intenta hacer conexiones a través de un archivo socket de Unix por defecto.

Por lo general, esto es más rápido y más seguro, ya que estas conexiones solo pueden realizarse localmente y no tienen que pasar por todas las comprobaciones y operaciones de enrutamiento que deben realizar las conexiones TCP. Sin embargo, la conexión con TCP nos permite verificar el estado de SSL de la conexión:

Se te solicitará la contraseña de root de MySQL que elegiste cuando instalaste y configuraste MySQL. Después de ingresarla, serás lanzado a una sesión interactiva de MySQL.

Puedes muestrar el estado de las variables SSL/TLS emitiendo el siguiente comando:

Resultado

Las variables have_openssl y have_ssl se marcan como DISABLED. Esto significa que la funcionalidad SSL se ha compilado en el servidor, pero que aún no está habilitada.

Comprueba el estado de tu conexión actual para confirmar esto:

Como lo indica la salida anterior, SSL no está actualmente en uso para esta conexión, aunque estés conectado a través de TCP.

Cierra la sesión actual de MySQL cuando hayas terminado:

Ahora que has confirmado que tu servidor MySQL no está usando SSL, puedes pasar al siguiente paso, donde comenzarás el proceso de habilitación de SSL generando algunos certificados y claves. Esto permitirá que tu servidor y cliente se comuniquen entre sí de forma segura.

Paso 2 – Generación de certificados y claves SSL/TLS

Para habilitar las conexiones SSL a MySQL, primero debes generar el certificado apropiado y los archivos de clave. Las versiones 5.7 y posteriores de MySQL proporcionan una utilidad llamada mysql_ssl_rsa_setup que ayuda a simplificar este proceso.

La versión de MySQL que instalaste siguiendo el prerrequisito del tutorial de MySQL incluye esta utilidad, por lo que la usaremos aquí para generar los archivos necesarios.

El proceso de MySQL debe ser capaz de leer los archivos generados, así que usa la opción –uid para declarar a mysql como el usuario del sistema que debe poseer los archivos generados:

Resultado

Esto producirá una salida similar a la siguiente:

Estos nuevos archivos se almacenarán en el directorio de datos de MySQL, ubicado por defecto en /var/lib/mysql. Comprueba los archivos generados escribiendo:

Estos archivos son la clave y los pares de certificados para la autoridad de certificación (que comienza con “ca”), el proceso del servidor MySQL (que comienza con “server”) y para los clientes MySQL (que comienzan con “client”).

Además, los archivos private_key.pempublic_key.pem son utilizados por MySQL para transferir contraseñas de forma segura cuando no se usa SSL.

Ahora que tienes el certificado y los archivos de clave necesarios, continúa para habilitar el uso de SSL en tu instancia de MySQL.

Paso 3: habilitación de conexiones SSL en el servidor MySQL

Las versiones modernas de MySQL buscan los archivos de certificado apropiados dentro del directorio de datos de MySQL cada vez que se inicia el servidor. Debido a esto, no necesitarás modificar la configuración de MySQL para habilitar SSL.

En su lugar, habilita SSL reiniciando el servicio MySQL:

Después de reiniciar, abre una nueva sesión de MySQL usando el mismo comando que antes. El cliente MySQL intentará conectarse automáticamente utilizando SSL si el servidor lo admite:

Echemos otro vistazo a la misma información que solicitamos la última vez. Comprueba los valores de las variables relacionadas con SSL:

Las variables have_opensslhave_ssl ahora están en YES lugar de DISABLED. Por otra parte, las variables ssl_ca, ssl_certssl_key se han rellenado con los nombres de los archivos respectivos que acabas de generar.

A continuación, verifica nuevamente los detalles de la conexión:

Esta vez, se muestra el cifrado SSL específico, lo que indica que SSL se está utilizando para asegurar la conexión.

Cerrar sesión

Debes salir de nuevo de la sesión:

Tu servidor es ahora capaz de utilizar el cifrado, pero se requiere una configuración adicional para permitir el acceso remoto y ordenar el uso de conexiones seguras.

Paso 4 – Configuración de conexiones seguras para clientes remotos

Ahora que has habilitado SSL en el servidor MySQL, puedes comenzar a configurar el acceso remoto seguro. Para hacer esto, configurarás tu servidor MySQL para que requiera que las conexiones remotas se realicen a través de SSL, debes enlazar MySQL para escuchar en una interfaz pública y ajustar las reglas de firewall de tu sistema para permitir conexiones externas

Actualmente, el servidor MySQL está configurado para aceptar conexiones SSL de los clientes. Sin embargo, todavía permitirá conexiones sin cifrar si así lo solicita el cliente.

Podemos cambiar esto activando la opción require_secure_transport. Esto requiere que todas las conexiones se realicen con SSL o con un socket Unix local. Dado que los sockets Unix solo son accesibles desde el propio servidor, la única opción de conexión disponible para usuarios remotos será con SSL.

Para habilitar esta configuración, abre el archivo de configuración de MySQL en tu editor de texto preferido. Aquí, vamos a utilizar nano:

Dentro habrá dos directivas !includedir que se utilizan para generar archivos de configuración adicionales. Debes agregar tu propia configuración debajo de estas líneas para que anule cualquier configuración en conflicto encontrada en estos archivos de configuración adicionales.

Editando la configuración

Inicia creando una sección [mysqld] para dirigir el proceso del servidor MySQL. Bajo ese encabezado de sección, debes establecer require_secure_transport en ON, lo que obligará a MySQL a permitir solo conexiones seguras:

De forma predeterminada, MySQL está configurado para escuchar solo las conexiones que se originan en 127.0.0.1 la dirección IP de loopback que representa a localhost . Esto significa que MySQL está configurado para escuchar solo las conexiones que se originan en la máquina en la que está instalado el servidor MySQL.

Para permitir que MySQL escuche las conexiones externas, debes configurarlo para escuchar las conexiones en una dirección IP externa. Para hacer esto, puedes agregar la configuración bind-address y que apunte a 0.0.0.0, una dirección IP comodín que representa todas las direcciones IP. Esencialmente, esto obligará a MySQL a escuchar las conexiones en cada interfaz.

Configuración de IP Externa

Nota: También puedes configurar la dirección IP pública de bind-address en tu servidor MySQL. Sin embargo, debes recordar actualizar tu archivo my.cnf si alguna vez migras tu base de datos a otra máquina.

Después de agregar estas líneas, guarda y cierra el archivo. Si has utilizado nano para editar el archivo, puedes hacerlo pulsando CTRL+X, Y y a continuación ENTER.

A continuación, reinicia MySQL para aplicar la nueva configuración:

Verifica que MySQL esté escuchando en 0.0.0.0 en lugar de 127.0.0.1, para ello debes escribir:

La salida de este comando se verá así:

El 0.0.0.0 resaltado en la salida anterior indica que MySQL está escuchando las conexiones en todas las interfaces disponibles.

A continuación, tienes que permitir conexiones MySQL a través del firewall de tu servidor. Agrega una excepción a tus reglas ufw escribiendo:

Con eso, los intentos de conexión remota ahora pueden llegar a tu servidor MySQL. Sin embargo, actualmente no tienes ningún usuario configurado que pueda conectarse desde una máquina remota.

Crearemos y configuraremos un usuario de MySQL que pueda conectarse desde la máquina de tu cliente en el siguiente paso.

Paso 5 – Creando un usuario MySQL dedicado

En este punto, tu servidor MySQL rechazará cualquier intento de conexión desde una máquina cliente remota. Esto se debe a que los usuarios de MySQL existentes solo están configurados para conectarse localmente desde el servidor MySQL.

Para resolver esto, crearás un usuario dedicado que solo podrá conectarse desde la máquina de tu cliente.

Para crear dicho usuario, vuelve a iniciar sesión en MySQL como usuario root:

Desde el indicador, crea un nuevo usuario remoto con el comando CREATE USER. Puedes nombrar a este usuario como quieras, pero en esta guía lo llamaremos mysql_user.

Creando el usuario

Asegúrate de especificar la dirección IP de la máquina cliente en la parte del host de la especificación del usuario para restringir las conexiones a esa máquina y reemplazar password con una contraseña segura de tu elección.

Además, para algunas redundancias en caso de que la opción require_secure_transport esté desactivada en el futuro, especifica que este usuario requiere SSL al incluir la cláusula REQUIRE SSL, como se muestra aquí:

A continuación, otorga al nuevo usuario permisos a las bases de datos o tablas a las que debería tener acceso. Para demostrar, crea una base de datos llamada example:

Luego, otorga a tu nuevo usuario acceso a esta base de datos y todas tus tablas:

A continuación, elimina los privilegios para aplicar esas configuraciones inmediatamente:

Luego sal de nuevo al shell cuando hayas terminado:

Tu servidor MySQL ahora está configurado para permitir conexiones desde tu usuario remoto. Para probar que puedes conectarte a MySQL con éxito, deberás instalar el paquete mysql-client en MySQL client.

Probando la conexión

Inicia sesión en su máquina cliente con ssh

Luego actualiza el índice de paquetes de la máquina cliente:

E instala mysql-client con el siguiente comando:

Cuando se te solicite, confirma la instalación presionando ENTER.

Una vez que APT termina de instalar el paquete, ejecuta el siguiente comando para probar si puedes conectarte al servidor con éxito. Este comando incluye la opción -u de usuario para especificar mysql_user y la opción –h para especificar la dirección IP del servidor MySQL:

Después de enviar la contraseña, iniciarás sesión en el servidor remoto. Usa \s para verificar el estado del servidor y confirmar que tu conexión es segura:

Tienes que regresar de nuevo a la shell

Has confirmado que puedes conectarte a MySQL con SSL. Sin embargo, aún no has confirmado que el servidor MySQL esté rechazando conexiones inseguras. Para probar esto, intenta conectarte una vez más, pero esta vez agrega –ssl-mode=disabled al comando de inicio de sesión. Esto le indicará a mysql-client que intente una conexión sin cifrar:

Después de ingresar tu contraseña cuando se te solicite, tu conexión será rechazada:

Esto muestra que las conexiones SSL están permitidas mientras que las conexiones no cifradas son rechazadas.

En este punto, tu servidor MySQL ha sido configurado para aceptar conexiones remotas seguras. Puedes detenerte aquí si esto satisface tus requisitos de seguridad, pero hay algunas piezas adicionales que puedes colocar para mejorar la seguridad y la confianza entre tus dos servidores.

Paso 6 – (Opcional) Configuración de la validación para las conexiones MySQL

Actualmente, tu servidor MySQL está configurado con un certificado SSL firmado por una autoridad de certificación (CA) generada localmente. El par de claves y el certificado del servidor son suficientes para proporcionar el cifrado de las conexiones entrantes.

Sin embargo, todavía no estás aprovechando por completo la relación de confianza que puede proporcionar una autoridad de certificación. Al distribuir el certificado de CA a los clientes, así como el certificado y la clave del cliente, ambas partes pueden proporcionar una prueba de que sus certificados fueron firmados por una autoridad de certificados de confianza mutua. Esto puede ayudar a prevenir conexiones falsificadas de servidores maliciosos.

Para implementar este resguardo adicional y opcional, transferiremos los archivos SSL apropiados a la máquina cliente, crearemos un archivo de configuración del cliente y modificaremos el usuario remoto de MySQL para requerir un certificado confiable.

Nota: El proceso para transferir el certificado de CA, el certificado del cliente y la clave del cliente al cliente MySQL descrito en los siguientes párrafos implica mostrar el contenido de cada archivo cat, copiar esos contenidos en el portapapeles y pegarlos en un archivo nuevo en la máquina cliente. Si bien es posible copiar estos archivos directamente con un programa como scpsftp, esto también requiere que configures las claves SSH para ambos servidores a fin de permitirles comunicarse a través de SSH.

Nuestro objetivo aquí es mantener la cantidad de vías posibles para conectarte a tu servidor MySQL al mínimo. Si bien este proceso es un poco más laborioso que transferir los archivos directamente, es igualmente seguro y no requiere que abras una conexión SSH entre las dos máquinas.

Creando el directorio

Inicia creando un directorio en MySQL client en el directorio de inicio de tu usuario no root. Asígnale el nombre de client-ssl:

Debido a que la clave del certificado es confidencial, bloquea el acceso a este directorio para que solo el usuario actual pueda acceder a él:

En MySQL server, muestra el contenido del certificado de CA escribiendo:

Copia la salida completa, incluidas las líneas BEGIN CERTIFICATEEND CERTIFICATE, a tu portapapeles.

En MySQL client, crea un archivo con el mismo nombre dentro del nuevo directorio:

Dentro de este, pega el contenido del certificado copiado desde tu portapapeles. Guarda y cierra el archivo cuando hayas terminado.

A continuación, muestra el certificado de cliente en MySQL server:

Copia el contenido del archivo a tu portapapeles. Una vez más, recuerda incluir la primera y la última línea.

Abre un archivo con el mismo nombre en MySQL client dentro del directorio client-ssl:

Pega los contenidos desde tu portapapeles. Guarda y cierra el archivo.

Finalmente, muestra el contenido del archivo de clave del cliente en MySQL server:

Copia los contenidos mostrados, incluyendo la primera y la última línea, a tu portapapeles.

En MySQL client, abre un archivo con el mismo nombre en el directorio client-ssl:

Pega los contenidos desde tu portapapeles. Guarda y cierra el archivo.

Configurando el servidor

La máquina cliente ahora tiene todas las credenciales necesarias para acceder al servidor MySQL. Sin embargo, el servidor MySQL aún no está configurado para requerir certificados de confianza para las conexiones de clientes.

Para cambiar esto, inicia sesión en la cuenta root de MySQL nuevamente en MySQL server:

Desde aquí, cambia los requisitos de seguridad para tu usuario remoto. En lugar de la cláusula REQUIRE SSL, aplica la cláusula REQUIRE X509. Esto implica toda la seguridad proporcionada por la cláusula REQUIRE SSL, pero adicionalmente requiere que el cliente que se conecta presente un certificado firmado por una autoridad de certificación en la que el servidor MySQL confía.

Para ajustar los requisitos del usuario, usa el comando ALTER USER:

Luego elimina los cambios para asegurarte de que se apliquen inmediatamente:

Debes salir de nuevo a la shell cuando hayas terminado:

A continuación, verifica si puedes validar ambas partes cuando te conectes.

En MySQL client, primero intenta conectarte sin proporcionar los certificados de cliente:

Como se esperaba, el servidor rechaza la conexión cuando no se presenta un certificado de cliente.

Ahora, conecta durante el uso de –ssl-ca, –ssl-certy y –ssl-ke las opciones para apuntar a los archivos relevantes dentro del directorio ~/client-ssl:

Le has proporcionado al cliente las claves y certificados adecuados, por lo que este intento será exitoso:

Iniciando sesión

Vuelve a iniciar sesión para recuperar el acceso a tu sesión de shell:

Ahora que has confirmado el acceso al servidor, implementemos una pequeña mejora de usabilidad para evitar tener que especificar los archivos de certificado cada vez que te conectes.

Dentro de tu directorio de inicio en la máquina MySQL client, crea un archivo de configuración oculto llamado ~/.my.cnf:

En la parte superior del archivo, crea una sección llamada [client]. Por debajo, añade las opciones ssl-ca, ssl-certssl-key y apunta a los respectivos ficheros que has copiado desde el servidor. Se verá así:

La opción ssl-ca le dice al cliente que verifique que el certificado presentado por el servidor MySQL está firmado por la autoridad de certificación que señalaste. Esto permite al cliente confiar en que se está conectado a un servidor MySQL de confianza.

Del mismo modo, las opciones ssl-certssl-key apuntan a los archivos necesarios para demostrar al servidor MySQL que también tiene un certificado que ha sido firmado por la misma autoridad de certificación. Lo necesitarás si deseas que el servidor MySQL verifique que la CA también confió en el cliente.

Guarda y cierra el archivo cuando hayas terminado.

Ahora, te puedes conectar con el servidor MySQL sin agregar las opciones –ssl-ca–ssl-cert–ssl-key en la línea de comandos:

Tu cliente y servidor ahora presentarán certificados cuando negocien la conexión. Cada parte está configurada para verificar el certificado remoto con el certificado de CA que tiene localmente.

Conclusión

Tu servidor MySQL ahora está configurado para requerir conexiones seguras de clientes remotos. Además, si siguiste los pasos para validar las conexiones mediante la autoridad de certificación, ambos lados establecen cierto nivel de confianza de que la parte remota es legítima.