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

Introducción

MySQL es el sistema de gestión de base de datos relacional de código abierto más popular del mundo. Los gestores de paquetes modernos han reducido algo de fricción para que MySQL funcione y se ejecute, pero todavía hay alguna configuración que debe hacerse después de la instalación. Una de las áreas más importantes para pasar algún tiempo extra es la seguridad.

De forma predeterminada, MySQL está configurado para aceptar sólo conexiones locales. Si necesita permitir conexiones remotas, es importante hacerlo de forma segura. En esta guía, vamos a demostrar cómo configurar MySQL en Ubuntu 16.04 para aceptar conexiones remotas con cifrado SSL / TLS.

Requisitos previos

Para seguir esta guía, necesitará dos servidores Ubuntu 16.04. Vamos a utilizar uno como el servidor MySQL y el otro como el cliente. Cree un usuario no root con sudoprivilegios en cada uno de estos servidores.

En la primera máquina, debe tener el servidor MySQL instalado y configurado.

En la segunda máquina, instale el paquete de cliente MySQL . Puede actualizar el aptíndice del paquete e instalar el software necesario escribiendo:

  • sudo apt-get update
  • sudo apt-get install mysql-client

Cuando el servidor y el cliente estén listos, continúe a continuación.

Compruebe el estado actual de SSL / TLS

Antes de comenzar, podemos comprobar el estado actual de SSL / TLS en nuestra instancia de servidor MySQL .

Inicie sesión en una sesión MySQL utilizando el rootusuario MySQL. Usaremos -hpara especificar la interfaz de bucle local de IPv4 para forzar al cliente a conectarse con TCP en lugar de usar el archivo de socket local. Esto nos permitirá comprobar el estado SSL de las conexiones TCP:

  • mysql -u root -p -h 127.0.0.1

Se le pedirá la rootcontraseña de MySQL que seleccionó durante el proceso de instalación. Después, usted será lanzado en una sesión interactiva de MySQL.

Muestre el estado de las variables SSL / TLS escribiendo:

  • SHOW VARIABLES LIKE ‘%ssl%’;
Output
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| have_openssl  | DISABLED |
| have_ssl      | DISABLED |
| ssl_ca        |          |
| ssl_capath    |          |
| ssl_cert      |          |
| ssl_cipher    |          |
| ssl_crl       |          |
| ssl_crlpath   |          |
| ssl_key       |          |
+---------------+----------+
9 rows in set (0.01 sec)

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

Compruebe el estado de nuestra conexión actual para confirmar:

  • \s
Output
--------------
mysql  Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using  EditLine wrapper

Connection id:      30
Current database:   
Current user:       root@localhost
SSL:         Not in use
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server version:     5.7.17-0ubuntu0.16.04.1 (Ubuntu)
Protocol version:   10
Connection:      127.0.0.1 via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8
TCP port:       3306
Uptime:         3 hours 38 min 44 sec

Threads: 1  Questions: 70  Slow queries: 0  Opens: 121  Flush tables: 1  Open tables: 40  Queries per second avg: 0.005
--------------

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

Cierre la sesión actual de MySQL cuando haya terminado:

  • exit

Ahora podemos empezar a configurar MySQL para SSL para asegurar nuestras conexiones.

Generar certificados y claves SSL / TLS

Para habilitar las conexiones SSL a MySQL, primero necesitamos generar el certificado apropiado y los archivos clave. Una utilidad llamada mysql_ssl_rsa_setupse proporciona con MySQL 5.7 y superior para simplificar este proceso. Ubuntu 16.04 tiene una versión compatible de MySQL, por lo que podemos usar este comando para generar los archivos necesarios.

Los archivos se crearán en el directorio de datos de MySQL, ubicado en /var/lib/mysql. Necesitamos el proceso de MySQL para poder leer los archivos generados, así que pasaremos mysqlcomo el usuario que debe poseer los archivos generados:

  • sudo mysql_ssl_rsa_setup –uid=mysql

La generación producirá una salida que se verá así:

Output
Generating a 2048 bit RSA private key
...................................+++
.....+++
writing new private key to 'ca-key.pem'
-----
Generating a 2048 bit RSA private key
......+++
.................................+++
writing new private key to 'server-key.pem'
-----
Generating a 2048 bit RSA private key
......................................................+++
.................................................................................+++
writing new private key to 'client-key.pem'
-----

Compruebe los archivos generados escribiendo:

  • sudo find /var/lib/mysql -name ‘*.pem’ -ls
Output
   256740      4 -rw-r--r--   1 mysql    mysql        1078 Mar 17 17:24 /var/lib/mysql/server-cert.pem
   256735      4 -rw-------   1 mysql    mysql        1675 Mar 17 17:24 /var/lib/mysqlsql/ca-key.pem<^>
   256739      4 -rw-r--r--   1 mysql    mysql         451 Mar 17 17:24 /var/lib/mysqlsql/public_key.pem<^>
   256741      4 -rw-------   1 mysql    mysql        1679 Mar 17 17:24 /var/lib/mysqlsql/client-key.pem<^>
   256737      4 -rw-r--r--   1 mysql    mysql        1074 Mar 17 17:24 /var/lib/mysqlsql/ca.pem<^>
   256743      4 -rw-r--r--   1 mysql    mysql        1078 Mar 17 17:24 /var/lib/mysqlsql/client-cert.pem<^>
   256736      4 -rw-------   1 mysql    mysql        1675 Mar 17 17:24 /var/lib/mysqlsql/private_key.pem<^>
   256738      4 -rw-------   1 mysql    mysql        1675 Mar 17 17:24 /var/lib/mysqlsql/server-key.pem<^>

La última columna muestra los nombres de archivo generados. Las columnas centrales que muestran “mysql” indican que los archivos generados tienen la propiedad correcta del usuario y del grupo.

Estos archivos son la clave y pares de certificados para la autoridad de certificación (comenzando con “ca”), el proceso del servidor MySQL (que comienza con “servidor”) y para clientes MySQL (comenzando con “cliente”). Además, los archivos private_key.pempublic_key.pemson utilizados por MySQL para transferir de forma segura la contraseña cuando no se utiliza SSL.

Habilitar conexiones SSL en el servidor MySQL

Las versiones modernas de MySQL buscarán los archivos de certificados apropiados dentro del directorio de datos de MySQL cuando se inicie el servidor. Debido a esto, en realidad no necesitamos modificar la configuración de MySQL para habilitar SSL.

Podemos reiniciar el servicio MySQL en su lugar:

  • sudo systemctl restart mysql

Después de reiniciar, abra una nueva sesión de MySQL usando el mismo comando que antes. El cliente MySQL intentará automáticamente conectarse usando SSL si es soportado por el servidor:

  • mysql -u root -p -h 127.0.0.1

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

  • SHOW VARIABLES LIKE ‘%ssl%’;
Output
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| have_openssl  | YES             |
| have_ssl      | YES             |
| ssl_ca        | ca.pem          |
| ssl_capath    |                 |
| ssl_cert      | server-cert.pem |
| ssl_cipher    |                 |
| ssl_crl       |                 |
| ssl_crlpath   |                 |
| ssl_key       | server-key.pem  |
+---------------+-----------------+
9 rows in set (0.00 sec)

Las variables have_opensslhave_sslleen “SI” en lugar de “DISABLED” esta vez. Por otra parte, las ssl_cassl_certssl_keylas variables se han rellenado con los nombres de los certificados correspondientes que generamos.

A continuación, compruebe los detalles de conexión de nuevo:

  • \s
Output
--------------
. . .
SSL:            Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection:      127.0.0.1 via TCP/IP
. . .
--------------

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

Salir de nuevo a la cáscara:

  • exit

Nuestro servidor ahora es capaz de usar cifrado, pero se requiere alguna configuración adicional para permitir el acceso remoto y el mandato de uso de conexiones seguras.

Configuración de conexiones seguras para clientes remotos

Ahora que tenemos SSL disponible en el servidor, podemos comenzar a configurar el acceso remoto seguro. Para ello, necesitamos:

  • Requiere SSL para conexiones remotas
  • Vincular a una interfaz pública
  • Crear usuario MySQL para conexiones remotas
  • Ajuste nuestras reglas de firewall para permitir conexiones externas

Configurar acceso remoto con SSL obligatorio

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

Podemos arreglar esto activando la require_secure_transportopción. Esto requiere que todas las conexiones se realicen con SSL o con un socket Unix local. Dado que los sockets Unix sólo son accesibles desde el propio servidor, la única opción de conexión abierta a los usuarios remotos será con SSL.

Para habilitar esta configuración, abra el /etc/mysql/my.cnfarchivo en su editor de texto:

  • sudo nano /etc/mysql/my.cnf

En el interior, habrá dos !includedirdirectivas utilizadas para crear archivos de configuración adicionales. Tendremos que poner nuestra propia configuración debajo de estas líneas para que anulen cualquier configuración conflictiva.

Comience por crear una [mysqld]sección para orientar el proceso del servidor MySQL. Bajo ese encabezado de sección, establezca require_secure_transporten ON:

/etc/mysql/my.cnf
. . .

!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/

[mysqld]
# Require clients to connect either using SSL
# or through a local socket file
require_secure_transport = ON

Esa línea es la única configuración necesaria para reforzar las conexiones seguras.

De forma predeterminada MySQL está configurado para sólo escuchar las conexiones que se originan en el equipo local. Para configurarlo para que escuche las conexiones remotas, podemos configurar la bind-addressinterfaz a otra.

Para permitir que MySQL acepte conexiones en cualquiera de sus interfaces, podemos establecer bind-addressen “0.0.0.0”:

/etc/mysql/my.cnf
. . .

!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/

[mysqld]
# Require clients to connect either using SSL
# or through a local socket file
require_secure_transport = ON
bind-address = 0.0.0.0

Guarde y cierre el archivo cuando haya terminado.

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

  • sudo systemctl restart mysql

Compruebe que MySQL está escuchando en “0.0.0.0” en lugar de “127.0.0.1” escribiendo:

  • sudo netstat -plunt
Output
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      4330/mysqld     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1874/sshd       
tcp6       0      0 :::22                   :::*                    LISTEN      1874/sshd

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

A continuación, debemos permitir las conexiones de MySQL a través de nuestro firewall. Cree una excepción escribiendo:

  • sudo ufw allow mysql
Output
Rule added
Rule added (v6)

Los intentos de conexión remota ahora deben ser capaces de llegar a nuestro servidor MySQL.

Configurar un usuario MySQL remoto

El servidor MySQL está escuchando ahora conexiones remotas, pero actualmente no tenemos configurados ningún usuario que pueda conectarse desde un equipo externo.

Inicie sesión en MySQL como rootusuario para empezar:

  • mysql -u root -p

En el interior, puede crear un nuevo usuario remoto utilizando el CREATE USERcomando. Utilizaremos la dirección IP de nuestra máquina cliente en la parte del host de la especificación del usuario para restringir las conexiones a esa máquina.

Para una cierta redundancia en caso de que la require_secure_transportopción esté desactivada en el futuro, también especificaremos durante la creación de cuenta que este usuario necesita SSL incluyendo la REQUIRE SSLcláusula:

  • CREATE USER ‘remote_user‘@’mysql_client_IP‘ IDENTIFIED BY ‘password‘ REQUIRE SSL;

A continuación, conceda los nuevos permisos de usuario en las bases de datos o tablas a las que debería tener acceso. Para demostrar, crearemos una examplebase de datos y daremos nuestra nueva propiedad de usuario:

  • CREATE DATABASE example;
  • GRANT ALL ON example.* TO ‘remote_user‘@’mysql_client_IP‘;

A continuación, vacíe los privilegios para aplicarlos inmediatamente:

  • FLUSH PRIVILEGES;

Salir de nuevo a la cáscara cuando haya terminado:

  • exit

Nuestro servidor está configurado para permitir conexiones a nuestro usuario remoto.

Prueba de conexiones remotas

En la máquina cliente MySQL , pruebe para asegurarse de que puede conectarse al servidor correctamente. Utilice la -uopción para especificar el usuario remoto y la -hopción para especificar la dirección IP del servidor MySQL:

  • mysql -u remote_user -p -h mysql_server_IP

Después de especificar la contraseña, se conectará al servidor remoto.

Compruebe que su conexión sea segura:

  • \s
Output
--------------
. . .
SSL:         Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection:      mysql_server_IP via TCP/IP
. . .
--------------

Salir de nuevo a la cáscara:

  • exit

A continuación, intente conectarse inseguro:

  • mysql -u remote_user -p -h mysql_server_IP –ssl-mode=disabled

Después de que se le solicite su contraseña, su conexión debe ser rechazada:

Output
ERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_server_IP' (using password: YES)

Esto es lo que estábamos trabajando hacia. Muestra que las conexiones SSL están permitidas, mientras que las conexiones no cifradas son rechazadas.

En este punto, nuestro servidor MySQL ha sido configurado para aceptar conexiones remotas de forma segura. Usted puede parar aquí si esto satisface sus requisitos de seguridad, pero hay algunas piezas adicionales que podemos poner en su lugar para aumentar nuestra seguridad y confiar más.

Configuración de validación para conexiones MySQL (opcional)

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

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

Para implementar esta salvaguardia extra opcional, tendremos que:

  • Transferir los archivos SSL apropiados a la máquina cliente
  • Crear un archivo de configuración de cliente
  • Modificar a nuestro usuario remoto para que requiera un certificado de confianza

Transferir los certificados de cliente a la máquina cliente

Para empezar, necesitamos apoderarnos de los archivos de certificados de cliente y CA de MySQL del servidor MySQL y colocarlos en el cliente MySQL.

Comience haciendo un directorio en el cliente de MySQL en el directorio casero del usuario que usted utilizará para conectar. Llame a esto client-ssl:

  • mkdir ~/client-ssl

Dado que la clave de certificado es sensible, debemos bloquear el acceso a este directorio para que sólo el usuario actual pueda acceder a él:

  • chmod 700 ~/client-ssl

Ahora, podemos copiar la información del certificado al nuevo directorio.

En la máquina del servidor MySQL , muestre el contenido del certificado de CA escribiendo:

  • sudo cat /var/lib/mysql/ca.pem
Output
-----BEGIN CERTIFICATE-----

. . .

-----END CERTIFICATE-----

Copie la salida completa, incluyendo las líneas BEGIN CERTIFICATEEND CERTIFICATEal portapapeles.

En el cliente MySQL , cree un archivo con el mismo nombre dentro del nuevo directorio:

  • nano ~/client-ssl/ca.pem

En el interior, pegue el contenido del certificado copiado de su portapapeles. Guarde y cierre el archivo cuando haya terminado.

A continuación, muestre el certificado de cliente en el servidor MySQL :

  • sudo cat /var/lib/mysql/client-cert.pem
Output
-----BEGIN CERTIFICATE-----

. . .

-----END CERTIFICATE-----

De nuevo, copie el contenido en el portapapeles. Recuerde incluir la primera y la última línea.

Abra un archivo con el mismo nombre en el cliente MySQL dentro del client-ssldirectorio:

  • nano ~/client-ssl/client-cert.pem

Pegue el contenido de su portapapeles. Guarde y cierre el archivo.

Finalmente, muestra el contenido del archivo de claves del cliente en el servidor MySQL :

  • sudo cat /var/lib/mysql/client-key.pem
Output
-----BEGIN RSA PRIVATE KEY-----

. . .

-----END RSA PRIVATE KEY-----

Copie el contenido mostrado, incluyendo la primera y última línea, en el portapapeles.

En el cliente MySQL , abra un archivo con el mismo nombre en el client-ssldirectorio:

  • nano ~/client-ssl/client-key.pem

Pegue el contenido de su portapapeles. Guarde y cierre el archivo.

La máquina cliente debe tener ahora todas las credenciales necesarias para acceder al servidor MySQL. A continuación, debemos modificar nuestro usuario remoto.

Requerir un certificado de una entidad emisora ​​de confianza para el usuario remoto

Actualmente, el cliente MySQL tiene los archivos disponibles para presentar su certificado al servidor cuando se conecta. Sin embargo, el servidor todavía no está configurado para requerir el certificado de cliente de una CA de confianza.

Para cambiar esto, vuelva a iniciar sesión en la cuenta raíz de MySQL en el servidor MySQL :

  • mysql -u root -p

A continuación, necesitamos cambiar los requisitos para nuestro usuario remoto. En lugar de la REQUIRE SSLcláusula, necesitamos aplicar la REQUIRE X509cláusula. Esto implica toda la seguridad proporcionada por el requisito anterior, pero además requiere que el cliente de conexión presente un certificado firmado por una autoridad de certificado en la que confía el servidor MySQL.

Para ajustar los requisitos del usuario, utilice el ALTER USERcomando:

  • ALTER USER ‘remote_user‘@’mysql_client_IP‘ REQUIRE X509;

Limpie los cambios para asegurarse de que se aplican inmediatamente:

  • FLUSH PRIVILEGES;

Salir de nuevo a la cáscara cuando haya terminado:

  • exit

A continuación, podemos probar para asegurarnos de que aún podamos conectarnos.

Validación del certificado de prueba al conectar

Ahora es un buen momento para comprobar si podemos validar a ambas partes cuando nos conectamos.

En el cliente MySQL , primero intente conectarse sin proporcionar los certificados de cliente:

  • mysql -u remote_user -p -h mysql_server_IP
Output
ERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_client_IP' (using password: YES)

Sin proporcionar el certificado de cliente, el servidor rechaza la conexión.

Ahora, conecte durante el uso de los --ssl-ca--ssl-cert--ssl-keylas opciones para apuntar a los archivos relevantes dentro del ~/client-ssldirectorio:

  • mysql -u remote_user -p -h mysql_server_IP –ssl-ca=~/client-ssl/ca.pem –ssl-cert=~/client-ssl/client-cert.pem –ssl-key=~/client-ssl/client-key.pem

Debe iniciar sesión correctamente. Regrese para recuperar el acceso a su sesión de shell:

  • exit

Ahora que hemos confirmado el acceso al servidor, podemos implementar una pequeña mejora de la usabilidad.

Crear un archivo de configuración de MySQL Client

Para evitar tener que especificar los archivos de certificado cada vez que se conecte, podemos crear un archivo de configuración de cliente MySQL sencillo.

Dentro de su directorio de inicio en la máquina cliente MySQL , cree un archivo oculto llamado ~/.my.cnf:

  • nano ~/.my.cnf

En la parte superior del archivo, cree una sección llamada [client]. Por debajo, podemos establecer las ssl-cassl-certssl-keylas opciones para apuntar a los archivos que copian desde el servidor. Debe tener un aspecto como este:

mi noticia
[client]
ssl-ca = ~/client-ssl/ca.pem
ssl-cert = ~/client-ssl/client-cert.pem
ssl-key = ~/client-ssl/client-key.pem

La ssl-caopción le dice al cliente que verifique que el certificado presentado por el servidor MySQL esté firmado por la autoridad de certificación a la que nos hemos referido. Esto permite al cliente confiar en que se está conectando a un servidor MySQL de confianza.

Las opciones ssl-certssl-keyapuntan a los archivos necesarios para probar al servidor MySQL que también tiene un certificado que ha sido firmado por la misma autoridad de certificación. Necesitamos esto si queremos que el servidor MySQL verifique que la CA también confía en el cliente.

Guarde y cierre el archivo cuando haya terminado.

Ahora, se puede conectar con el servidor MySQL sin agregar el --ssl-ca--ssl-cert--ssl-keyopciones en la línea de comandos:

  • mysql -u remote_user -p -h mysql_server_ip

Ahora su cliente y servidor deben presentar certificados al negociar la conexión. Cada parte está configurada para verificar el certificado remoto con el certificado de CA que tiene localmente.

Conclusión

Su servidor MySQL ahora debe estar configurado para requerir conexiones seguras para clientes remotos. Además, si siguió los pasos para validar las conexiones utilizando la autoridad de certificación, los dos lados establecen un nivel de confianza que la parte remota es legítima.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *