Serveurs Base de données

MySQL : Chiffrer les échanges SQL de MariaDB avec une couche SSL

Cet article a été mis à jour, vous consultez ici une archive de cet article!
Table des matières

logo-mariadb



Introduction



Je travaille actuellement avec 2 serveurs. Sur l'un, j'ai un serveur Web. Sur l'autre, j'ai mon serveur MariaDB (MySQL).
Ce sont 2 machines physiques, et par défaut les requêtes transitent en clair entre les 2 machines.

Voici l'infrastructure utilisée dans cet article :

centos-www : Serveur Web - 192.168.21.10/24
centos-db : Serveur MariaDB - 192.168.21.11/24

Cet article est réalisé sur CentOS. Si vous utilisez Debian, adaptez. les fichiers de configuration ne sont pas au même endroit.

Prérequis



On installe le serveur MariaDB :

Code BASH :
yum install mariadb-server


Sur le serveur MariaDB, j'autorise MariaDB à écouter sur toutes les IP :

Code BASH :
vi /etc/my.cnf.d/mariadb-server.cnf


Code TEXT :
bind-address=0.0.0.0


Sur le serveur MariaDB, j'autorise dans le pare-feu uniquement l'IP du serveur Web à accéder à MariaDB :

Code BASH :
firewall-cmd --zone=trusted --add-source=192.168.21.10 --permanent
firewall-cmd --zone=trusted --add-service=mysql --permanent
firewall-cmd --reload


Sur le serveur MariaDB, on peut se connecter et vérifier les utilisateurs :

Code BASH :
 mysql -u root -p


Code SQL :
SELECT USER,host FROM mysql.USER;


Code TEXT :
+------+-----------------------+
| user | host                  |
+------+-----------------------+
| root | 127.0.0.1             |
| root | ::1                   |
| root | localhost             |
| root | localhost.localdomain |
+------+-----------------------+
4 rows in set (0.000 sec)


Je vais créer un utilisateur qui peut se connecter depuis n’importe quel endroit, avec tous les droits (adaptez si vous ne voulez que l'utilisateur n'accède qu'à une seule base, changer le nom d'utilisateur et le mot de passe évidemment) :

Code SQL :
CREATE USER 'adrien'@'%' IDENTIFIED BY 'motdepasse';
GRANT ALL ON *.* TO 'adrien'@'%';
FLUSH privileges;


Du côté client, on peut tester le bon fonctionnement (non sécurisé) :

On installe si besoin les commandes clientes mysql (MariaDB) :

Code BASH :
yum install mariadb


Code BASH :
mysql -u adrien -p -h 192.168.21.11


Configuration du serveur



Vérification du support SSL



Sur le serveur, on se connecte en root dans MariaDB.

On vérifie le support de OpenSSL et de SSL via :

Code SQL :
SHOW VARIABLES LIKE "%ssl%";


On a ceci :

Code TEXT :
+---------------------+----------------------------------+
| Variable_name       | Value                            |
+---------------------+----------------------------------+
| have_openssl        | YES                              |
| have_ssl            | DISABLED                         |
| ssl_ca              |                                  |
| ssl_capath          |                                  |
| ssl_cert            |                                  |
| ssl_cipher          |                                  |
| ssl_crl             |                                  |
| ssl_crlpath         |                                  |
| ssl_key             |                                  |
| version_ssl_library | OpenSSL 1.1.1c FIPS  28 May 2019 |
+---------------------+----------------------------------+
10 rows in set (0.001 sec)


DISABLED = Supporté mais non actif
NO = Pas de support OpenSSL

Génération des certificats



On va générer les certificats.
Je vais les créer dans /etc/ssl/mariadb qui me semble l'endroit le plus aproprié.

Code BASH :
cd /etc/ssl
mkdir mariadb
cd mariadb


On va créer la clé du CA :
Code BASH :
openssl genrsa 2048 > ca-key.pem


On génère ensuite le certificat avec la clé précédemment générée :
Code BASH :
openssl req -new -x509 -nodes -days 365000 -key ca-key.pem -out ca-cert.pem


Exemple de sortie :
Code TEXT :
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:FR
State or Province Name (full name) []:Burgundy
Locality Name (eg, city) [Default City]:Dijon
Organization Name (eg, company) [Default Company Ltd]:Linuxtricks
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:linuxtricks.fr
Email Address []:
 


A ce stade on a 2 fichiers :
ca-cert.pem – Fichier de certificat Certificate Authority (CA).
ca-key.pem – Fichier de clé Certificate Authority (CA).

On utilise ces 2 clés pour générer les certificats serveur et client :
Pour le serveur, on créé la clé et le certificat :
Code BASH :
openssl req -newkey rsa:2048 -days 365000 -nodes -keyout server-key.pem -out server-req.pem
openssl rsa -in server-key.pem -out server-key.pem


Code TEXT :
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:FR
State or Province Name (full name) []:Burgundy
Locality Name (eg, city) [Default City]:Dijon
Organization Name (eg, company) [Default Company Ltd]:Linuxtricks
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:centos-db.linuxtricks.fr
Email Address []:
 
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
 


Et on signe le certificat :
Code BASH :
openssl x509 -req -in server-req.pem -days 365000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem


Code TEXT :
Signature ok
subject=C = FR, ST = Burgundy, L = Dijon, O = Linuxtricks, CN = centos-db.linuxtricks.fr
Getting CA Private Key
 


On a donc 2 fichiers :
server-cert.pem – Fichier certificat du serveur MariaDB
server-key.pem – Fichier de clé pour le serveur MariaDB


On génère le certificat pour le client de la même manière :
Code BASH :
openssl req -newkey rsa:2048 -days 365000 -nodes -keyout client-key.pem -out client-req.pem


Code TEXT :
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:FR
State or Province Name (full name) []:Burgundy
Locality Name (eg, city) [Default City]:Dijon
Organization Name (eg, company) [Default Company Ltd]:Linuxtricks
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:centos-www.linuxtricks.fr
Email Address []:
 
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:


Code BASH :
openssl rsa -in client-key.pem -out client-key.pem


Code BASH :
openssl x509 -req -in client-req.pem -days 365000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem


Code TEXT :
Signature ok
subject=C = FR, ST = Burgundy, L = Dijon, O = Linuxtricks, CN = centos-www.linuxtricks.fr
Getting CA Private Key
 


On vérifie les certificats :

Code BASH :
openssl verify -CAfile ca-cert.pem server-cert.pem client-cert.pem


Code TEXT :
server-cert.pem: OK
client-cert.pem: OK
 


Configuration du serveur MariaDB



On va éditer le fichier de configuration du serveur.
Sous CentOS il s'agit de
Code BASH :
/etc/my.cnf.d/mariadb-server.cnf 


Code BASH :
vi /etc/my.cnf.d/mariadb-server.cnf 


Dans la section [mysqld] on ajoute les renseignements sur nos certificats SSL :

Code TEXT :
ssl
ssl-ca=/etc/ssl/mariadb/ca-cert.pem
ssl-cert=/etc/ssl/mariadb/server-cert.pem
ssl-key=/etc/ssl/mariadb/server-key.pem


On donne les droits de lecture/modification au service mysql de lire/écrire les certificats :

Code BASH :
chown -R mysql:mysql /etc/ssl/mariadb


On redémarre MariaDB :

Code BASH :
systemctl restart mariadb


Vérifications du serveur



On se connecte en root sur le serveur à la base de données :

Code BASH :
mysql -u root -p


On vérifie les variables SSL :

Code SQL :
SHOW VARIABLES LIKE '%ssl%';


Code TEXT :
+---------------------+----------------------------------+
| Variable_name       | Value                            |
+---------------------+----------------------------------+
| have_openssl        | YES                              |
| have_ssl            | YES                              |
| ssl_ca              | /etc/ssl/mariadb/ca-cert.pem     |
| ssl_capath          |                                  |
| ssl_cert            | /etc/ssl/mariadb/server-cert.pem |
| ssl_cipher          |                                  |
| ssl_crl             |                                  |
| ssl_crlpath         |                                  |
| ssl_key             | /etc/ssl/mariadb/server-key.pem  |
| version_ssl_library | OpenSSL 1.1.1c FIPS  28 May 2019 |
+---------------------+----------------------------------+
10 rows in set (0.001 sec)
 


On a les chemins des certificats et have_ssl passe à YES.

On liste les utilisateurs du serveur, et s'il supportent les connexions SSL :

Code SQL :
SELECT USER,host,ssl_type FROM mysql.USER;


Code TEXT :
+--------+-----------+----------+
| user   | host      | ssl_type |
+--------+-----------+----------+
| root   | localhost |          |
| root   | 127.0.0.1 |          |
| root   | ::1       |          |
| adrien | %         |          |
+--------+-----------+----------+
4 rows in set (0.001 sec)
 


Ici, aucun ne supporte SSL.
On va activer SSL pour notre utilisateur adrien :

Code SQL :
ALTER USER 'adrien'@'%' REQUIRE SSL;
FLUSH PRIVILEGES;


On vérifie :

Code SQL :
SELECT USER,host,ssl_type FROM mysql.USER;


Code TEXT :
+--------+-----------+----------+
| user   | host      | ssl_type |
+--------+-----------+----------+
| root   | localhost |          |
| root   | 127.0.0.1 |          |
| root   | ::1       |          |
| adrien | %         | ANY      |
+--------+-----------+----------+
4 rows in set (0.000 sec)
 


La configuration du serveur est terminée.

Configuration du client



Maintenant, attaquons-nous au client.

On récupère les clés générées sur le serveur + le CA.
On va les placer, sur le client, dans le dossier /etc/ssl/mariadb/ :

Code BASH :
mkdir /etc/ssl/mariadb/


Code BASH :
rsync -av 192.168.21.11:/etc/ssl/mariadb/{ca-cert.pem,client-cert.pem,client-key.pem}  /etc/ssl/mariadb/


On va ensuite éditer le fichier de configuration du client mysql :
Sous CentOS, le fichier est /etc/my.cnf.d/mysql-clients.cnf
Sous Debian, le fichier est /etc/mysql/conf.d/mysql.cnf

Dans la section [mysqld], on ajoute les références aux certificats (cela évitera de lancer la commande mysql avec les arguments --ssl-XXX=/etc/ssl/mariadb/XXX.pem) :

Code TEXT :
ssl-ca=/etc/ssl/mariadb/ca-cert.pem
ssl-cert=/etc/ssl/mariadb/client-cert.pem
ssl-key=/etc/ssl/mariadb/client-key.pem


On se connecte ensuite pour vérifier le bon fonctionnement :

Code BASH :
mysql -u adrien -p -h 192.168.21.11


Pour s'assurer qu'on utilise bien SSL, on peut lancer la commande status :

Code SQL :
STATUS


Code TEXT :
MariaDB [(none)]> status
--------------
mysql  Ver 15.1 Distrib 10.3.17-MariaDB, for Linux (x86_64) using readline 5.1
 
Connection id:        9
Current database:    
Current user:        [email protected]
SSL:            Cipher in use is TLS_AES_256_GCM_SHA384
Current pager:        stdout
Using outfile:        ''
Using delimiter:    ;
Server:            MariaDB
Server version:        10.3.17-MariaDB MariaDB Server
Protocol version:    10
Connection:        192.168.21.11 via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8
TCP port:        3306
Uptime:            11 min 25 sec
 
Threads: 7  Questions: 11  Slow queries: 0  Opens: 17  Flush tables: 1  Open tables: 11  Queries per second avg: 0.016
--------------
 
 


On utilise bien SSL : Cipher in use is TLS_AES_256_GCM_SHA384

Voila :magic: