MySQL : Chiffrer les échanges SQL de MariaDB avec une couche SSL
Table des matières
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.
On installe le serveur MariaDB :
Sur le serveur MariaDB, j'autorise MariaDB à écouter sur toutes les IP :
Sur le serveur MariaDB, j'autorise dans le pare-feu uniquement l'IP du serveur Web à accéder à MariaDB :
Sur le serveur MariaDB, on peut se connecter et vérifier les utilisateurs :
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) :
Du côté client, on peut tester le bon fonctionnement (non sécurisé) :
On installe si besoin les commandes clientes mysql (MariaDB) :
Sur le serveur, on se connecte en root dans MariaDB.
On vérifie le support de OpenSSL et de SSL via :
On a ceci :
DISABLED = Supporté mais non actif
NO = Pas de support OpenSSL
On va générer les certificats.
Je vais les créer dans /etc/ssl/mariadb qui me semble l'endroit le plus aproprié.
On va créer la clé du CA :
On génère ensuite le certificat avec la clé précédemment générée :
Exemple de sortie :
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 :
Et on signe le certificat :
On a donc 2 fichiers :
server-cert.pem – Fichier certificat SSL du serveur MariaDB
server-key.pem – Fichier de clé SSL pour le serveur MariaDB
On génère le certificat pour le client de la même manière :
On vérifie les certificats :
On va éditer le fichier de configuration du serveur.
Sous CentOS il s'agit de
Dans la section [mysqld] on ajoute les renseignements sur nos certificats SSL :
On donne les droits de lecture/modification au service mysql de lire/écrire les certificats :
On redémarre MariaDB :
On se connecte en root sur le serveur à la base de données :
On vérifie les variables SSL :
On a les chemins des certificats et have_ssl passe à YES.
On liste les utilisateurs du serveur, et s'il supportent les connexions SSL :
Ici, aucun ne supporte SSL.
On va activer SSL pour notre utilisateur adrien :
On vérifie :
La configuration du serveur est terminée.
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/ :
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 [mysql], 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) :
On se connecte ensuite pour vérifier le bon fonctionnement :
Pour s'assurer qu'on utilise bien SSL, on peut lancer la commande status :
On utilise bien SSL : Cipher in use is TLS_AES_256_GCM_SHA384
Pour se connecter à la base avec une application PHP, grâce à PDO, voir la doc : https://www.php.net/manual/fr/ref.pdo-mysql.php
Voila
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 SSL du serveur MariaDB
server-key.pem – Fichier de clé SSL 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 [mysql], 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
Se connectr avec PHP et PDO
Pour se connecter à la base avec une application PHP, grâce à PDO, voir la doc : https://www.php.net/manual/fr/ref.pdo-mysql.php
Code PHP :
<?php $pdo = new PDO('mysql:host=192.168.21.100;dbname=bdd', 'user', 'pass', array( PDO::MYSQL_ATTR_SSL_KEY =>'/etc/ssl/mariadb/client-key.pem', PDO::MYSQL_ATTR_SSL_CERT=>'/etc/ssl/mariadb/client-cert.pem', PDO::MYSQL_ATTR_SSL_CA =>'/etc/ssl/mariadb/ca-cert.pem' ) ); ?>
Voila