2001: Segurizando el acceso a un servidor MySQL sin odiseas

Cloud, Seguridad

Trevenque Group » Blog » 2001: Segurizando el acceso a un servidor MySQL sin odiseas

Hace unos días, desplegando un servidor MySQL para un cliente, recordaba una de mis escenas favoritas de esa película de culto que es para mí «2001: Una odisea en el espacio».

La escena discurre con Dave Bowman desprovisto de su casco espacial y desde la nave auxiliar EVA pidiéndole encarecidamente a HAL que abriese la puerta de la cámara de las cápsulas para regresar con el cadáver de Frank Poole, que había muerto tras intentar arreglar una avería ficticia en el sistema de comunicaciones generada por el propio HAL.

Tras un breve intento de ignorar las órdenes de Dave, HAL responde de forma negativa, alegando que quiere demasiado a esta máquina (él mismo) como para permitir que se le ponga en peligro.

Aunque quede lejos de este post hablar sobre la capacidad de HAL de tomar conciencia de sí mismo (sentir miedo ante la desconexión) y, sobre todo, la decisión de proteger la misión que está por encima incluso de los integrantes humanos que la componen, en nuestro trabajo diario a veces perjudicamos los servicios en pos de segurizarlos. Esto es, cerramos la puerta de la cámara de las cápsulas pese a que nuestro querido piloto Dave quiere entrar.

Teniendo siempre en cuenta la recomendación de que, a menor superficie de exposición, menor probabilidad de intrusión, tenemos que encontrar un punto medio (o un conjunto de medidas técnicas) que permita que nuestro servicio no sea una caja cerrada completamente inaccesible que, por definición, dejaría de ser considerado ya un servicio.

Divagado ya por el espacio exterior del mundo del cine y enlazada nuestra historia, os paso a contar cómo segurizar un servidor MySQL para no tener que cerrar nuestra cámara de las cápsulas.

Pasos Previos

Partimos de un entorno de dos máquinas virtuales con Ubuntu 16.04 instalado. Una tendrá el servidor MySQL 5.7 instalado y la otra, el cliente de MySQL (mysql-client) de la misma versión.

Verificando el estado de la conexión

Hemos creado un usuario secure dentro del servidor MySQL para no conectar directamente con el usuario root en el servidor.

Verificaremos si nuestro servidor tiene soporte de SSL y nuestro cliente hace uso de él de la siguiente forma:

# Conectamos desde el cliente al servidor con el usuario secure.
gtk@mysql-client$ mysql -u secure -h 172.17.219.42 -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.25-0ubuntu0.16.04.2 (Ubuntu)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> \s
--------------
mysql  Ver 14.14 Distrib 5.7.25, for Linux (x86_64) using  EditLine wrapper

Connection id:          3
Current database:
Current user:           secure@mysql-client.mshome.net
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.7.25-0ubuntu0.16.04.2 (Ubuntu)
Protocol version:       10
Connection:             172.17.219.42 via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8
TCP port:               3306
Uptime:                 8 sec

Threads: 1  Questions: 5  Slow queries: 0  Opens: 107  Flush tables: 1  Open tables: 26  Queries per second avg: 0.625
--------------

# Verificamos si el servidor tiene soporte de conexión segura 
mysql> show variables like '%ssl%';
+---------------+----------+
| 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)

Como podemos ver, nuestra conexión no está usando el protocolo seguro SSL.

Generando certificados y claves SSL/TLS

Para habilitar las conexiones seguras mediante SSL tenemos que generar en primera instancia un conjunto de certificados y claves que configuraremos en el motor MySQL. En Ubuntu existe un script ya preparado para esta tarea que se llama mysql_ssl_rsa_setup.

Estos ficheros se crearán en el path /var/lib/mysql, donde reside el directorio de datos de MySQL, y el usuario mysql que corre el motor debe poder acceder a ellas.

# Generamos los ficheros necesarios para configurar ssl en el motor
gtk@mysql-server:~$ sudo mysql_ssl_rsa_setup --uid=mysql
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'
-----

Habilitando el soporte SSL en el servidor MySQL

En la versión actual de MySQL para Ubuntu el motor trata de buscar los ficheros necesarios para habilitar SSL en su directorio de datos, donde nosotros los hemos generado.

De esta manera, reiniciando el servidor MySQL quedaría configurado para habilitar el soporte SSL.

# Reiniciamos el motor de base de datos
gtk@mysql-server:~$ sudo systemctl restart mysql

# Revisamos desde el cliente la conexión al motor
gtk@mysql-client:~$ mysql -u secure -p -h 172.17.219.42
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.25-0ubuntu0.16.04.2 (Ubuntu)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like '%ssl%';
+---------------+-----------------+
| 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,03 sec)

# Si verificamos el estado de la conexión encontramos el cifrado en uso
# Cipher in use is DHE-RSA-AES256-SHA
mysql> \s
--------------
mysql  Ver 14.14 Distrib 5.7.25, for Linux (x86_64) using  EditLine wrapper

Connection id:          4
Current database:
Current user:           secure@mysql-client.mshome.net
SSL:                    Cipher in use is DHE-RSA-AES256-SHA
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.7.25-0ubuntu0.16.04.2 (Ubuntu)
Protocol version:       10
Connection:             172.17.219.42 via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8
TCP port:               3306
Uptime:                 4 min 9 sec

Threads: 2  Questions: 9  Slow queries: 0  Opens: 109  Flush tables: 1  Open tables: 28  Queries per second avg: 0.036
--------------

Uso obligatorio de SSL en MySQL

Ahora hemos habilitado el soporte SSL pero las conexiones al motor aún se pueden realizar de forma insegura.

Para obligar a que el motor MySQL sólo acepte conexiones seguras tendremos que editar el fichero my.cnf para agregar las siguientes líneas.

# /etc/mysql/my.cnf
# Más info en: https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_require_secure_transport

require_secure_transport = ON

Probando la conexión no cifrada para verificar el soporte

Ahora, y después de reiniciar el motor mediante sudo systemctl restart mysql, nuestro motor MySQL sólo aceptará conexiones cifradas.

Podemos probarlo intentando conectar nuestro usuario sin soporte ssl de la siguiente manera:

gtk@mysql-client:~$ mysql -u secure -p -h 172.17.219.42 --ssl-mode=disabled
Enter password:
ERROR 3159 (HY000): Connections using insecure transport are prohibited while --require_secure_transport=ON.

Como podemos ver, si obligamos a que nuestro cliente se intente conectar sin soporte SSL la conexión no se realiza.

Validando el certificado de cliente

Hasta ahora hemos configurado el motor MySQL para que use exclusivamente conexiones cifradas, pero esto no valida que el cliente utilice un certificado que lo identifique exclusivamente.

Para proceder con esta validación lo primero que haremos será modificar nuestro usuario secure para que tenga dicha limitación en el motor.

gtk@mysql-server:~$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.25-0ubuntu0.16.04.2 (Ubuntu)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> ALTER USER 'secure'@'%' REQUIRE x509;
Query OK, 0 rows affected (0,00 sec)

La parte importante del ALTER USER es el REQUIRE x509, esto obliga al usuario secure a utilizar un certificado validado por nuestra CA para conectar.

Necesitamos transferir ahora nuestro certificado y nuestra CA para que el cliente pueda utilizarlos en su conexión.

Crearemos un directorio mysql-ssl en nuestro equipo cliente y guardaremos allí los ficheros ca.pem y client-cert.pem que están alojados en el directorio de datos del motor MySQL (/var/lib/mysql).

# Creamos directorio y aplicamos permisos
gtk@mysql-client:~$ mkdir mysql-ssl
gtk@mysql-client:~$ chmod 700 mysql-ssl

# Copiamos mediante SCP los ficheros ca.pem y client-cert.pem
gtk@mysql-server:~$ sudo scp /var/lib/mysql/ca.pem gtk@172.17.219.41:/home/gtk/mysql-ssl/
ca.pem                                                                               100% 1107     1.1KB/s   00:00
gtk@mysql-server:~$ sudo scp /var/lib/mysql/client-cert.pem gtk@172.17.219.41:/home/gtk/mysql-ssl/
client-cert.pem                                                                      100% 1107     1.1KB/s   00:00
gtk@mysql-server:~$ sudo scp /var/lib/mysql/client-key.pem gtk@172.17.219.41:/home/gtk/mysql-ssl/
client-key.pem                                                                       100% 1679     1.6KB/s   00:00

# Verificamos que tenemos los ficheros en su sitio
gtk@mysql-client:~/mysql-ssl$ ls -larth
total 20K
drwxr-xr-x 4 gtk gtk 4,0K mar 26 00:44 ..
-rw-r--r-- 1 gtk gtk 1,1K mar 26 00:47 ca.pem
-rw-r--r-- 1 gtk gtk 1,1K mar 26 00:47 client-cert.pem
-rw------- 1 gtk gtk 1,7K mar 26 00:53 client-key.pem
drwx------ 2 gtk gtk 4,0K mar 26 00:53 .

Ya disponemos de los ficheros necesarios para configurar el acceso validado desde el cliente, ahora necesitamos configurar el fichero de conexión del cliente que se alojará en ~/my.cnf.

ssl-ca = ~/mysql-ssl/ca.pem
ssl-cert = ~/mysql-ssl/client-cert.pem
ssl-key = ~/mysql-ssl/client-key.pem

Y podemos probar la conexión:

# Conectando sin el fichero ~/.my.cnf
gtk@mysql-client:~$ mv .my.cnf .my.cnf.bak
gtk@mysql-client:~$ mysql -u secure -p -h 172.17.219.42
Enter password:
ERROR 1045 (28000): Access denied for user 'secure'@'mysql-client.mshome.net' (using password: YES)

# Conectando con el fichero ~/.my.cnf
gtk@mysql-client:~$ mv .my.cnf.bak .my.cnf
gtk@mysql-client:~$ mysql -u secure -p -h 172.17.219.42
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.25-0ubuntu0.16.04.2 (Ubuntu)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> \s
--------------
mysql  Ver 14.14 Distrib 5.7.25, for Linux (x86_64) using  EditLine wrapper

Connection id:          6
Current database:
Current user:           secure@mysql-client.mshome.net
SSL:                    Cipher in use is DHE-RSA-AES256-SHA
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.7.25-0ubuntu0.16.04.2 (Ubuntu)
Protocol version:       10
Connection:             172.17.219.42 via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8
TCP port:               3306
Uptime:                 28 min 45 sec

Threads: 1  Questions: 13  Slow queries: 0  Opens: 115  Flush tables: 1  Open tables: 34  Queries per second avg: 0.007
--------------

De esta manera, validamos que el certificado de cliente que acabamos de configurar permite la conexión de nuestro cliente exclusivamente.

Aunque puede parecer un poco complejo, esta configuración nos permite segurizar el acceso al motor MySQL mediante SSL y validando el certificado utilizado que hemos configurado previamente.

¿Te ha gustado? ¡Compártelo!

Logo Trevenque

trevenque group

Ofrecemos un conjunto de servicios completos para que puedas desarrollar tu negocio, gestionar tus datos de manera inteligente y tomar decisiones rentables.

Deja un comentario

Artículos similares

Sigue de cerca la actualidad de Grupo Trevenque y las últimas tendencias tecnológicas y de Business Intelligence.

Ver todas las noticias