Configurer le SSL pour sécuriser MySQL
Sommaire
- I. Présentation
- II. Permettre les connexions distantes
- III. Test de connexion à distance
- IV. Vérifier le support SSL de MySQL
- V. Configuration serveur et génération des certificats
- VI. Configuration Client
- VII. Test de connexion à distance avec SSL
- VIII. Avoir le choix entre une connexion SSL ou non chiffrée
I. Présentation
Dans ce tutoriel, nous allons apprendre à configurer MySQL pour qu'il utilise le SSL afin de chiffrer les échanges avec ses clients.
Il faut savoir que le chiffrement d'un flux par SSL alourdis en général les échanges par des traitements et des calculs supplémentaires (chiffrement / déchiffrement), c'est pourquoi le SSL n'est pas configuré par défaut dans MySQL. Il peut toutefois être dans certaines situations une solution non négligeable pour sécuriser les échanges.
II. Permettre les connexions distantes
Le besoin de sécuriser les échanges MySQL se fait naitre lorsque des serveurs ont besoins de communiquer fréquemment entre eux. Il faut donc déjà pour cela que notre serveur MySQL soit à l'écoute sur son interface externe.
On va également s'assurer d'avoir au moins un utilisateur qui puisse se connecter à distance sur notre serveur dans notre base de données.
On va pour cela se rendre en ligne de commande (de préférence en "root") sur notre serveur MySQL afin d'effectuer cette vérification. Nous allons lister nos utilisateurs ainsi que les hôtes à partir desquels ils ont le droit de se connecter :
select user,host from mysql.user;
Nous aurons alors ce type de résultat :
Nous voyons ici la liste des utilisateurs dans la colonne de gauche ainsi que les hôtes depuis lesquels ils peuvent se connecter à droite. "localhost", "127.0.0.1" ainsi que le nom FQDN de votre machine (ici "linux1"). Il nous faut donc, pour établir une connexion à distance qu'un utilisateur puisse se connecter depuis une IP (celle de notre serveur client) où depuis n'importe quel poste externe.
Par exemple pour faire en sorte que l'utilisateur "neoflow" puisse se connecter depuis l'IP 192.168.1.58, on exécutera cette commande dans MySQL :
CREATE USER "neoflow"@"192.168.1.58" IDENTIFIED BY "mot_de_passe";
On peut également, pour ouvrir un peu plus de notre serveur aux connexions externes, l'ouvrir pas seulement à l'IP 192.168.1.58 mais à une plage d'IP (comme 192.168.1.0/24) ou à toutes les IP externes avec le signe "%" à la place de l'IP.
On va maintenant donner les droits de lecture et de listage sur toutes nos bases de données SQL à l'utilisateur "neoflow" depuis l'IP "192.168.1.58". Les droits à mettre en place dépendent ici de votre situation.
GRANT SELECT, SHOW DATABASES ON *.* TO "neoflow"@"192.168.1.58";
On finira par faire relire à MySQL sa table de privilège pour qu'il mette à jours les droits et les utilisateurs :
FLUSH PRIVILEGES;
Nous allons maintenant refaire notre commande qui liste nos utilisateurs et nos hôtes pour voir la différence :
select user,host from mysql.user;
Nous voyons donc maintenant que notre utilisateur peut se connecter sur notre serveur MySQL depuis l'IP 192.168.1.58 seulement.
III. Test de connexion à distance
Nous allons maintenant faire un test de connexion à distance. On utilisera pour cela l'utilisateur nouvellement créé "neoflow" depuis un client ayant l'IP 192.168.1.58 ainsi que le logiciel "Wireshark" qui nous permettra d'analyser les échanges réseau entre le serveur et le client.
Note : Si vous faites ce tutoriel, il n'est pas nécessaire d'installer Wireshark, je le fait ici pour vous montrer que le trafic passe en clair sur le réseau mais ce n'est pas utile pour configurer SSL sur MySQL.
Depuis notre client, on exécute donc cette commande pour nous connecter à distance sur notre serveur. Ici, il a l'IP 192.168.1.46/24 :
mysql -u neoflow -p -h 192.168.1.46
On pourra ensuite lister nos base de données à distance avec la commande "show databases;" :
Sur notre analyseur réseau, nous voyons alors notre trafic circuler. Tout d'abord la question ("querry") que nous posons à notre serveur en clair sur le réseau. On voit très clairement la commande "show databases;"
Dans un second temps nous voyons la réponse ("Response") du serveur :
On vois alors très clairement la liste de nos bases de données transiter sur le réseau. Cela peut sembler anodin pour une simple liste de base de données mais on pourra également voir des données plus critiques transiter.
On voit donc que sans SSL, les échanges SQL peuvent être vus sur le réseau. Le SSL va donc ici nous permettre de chiffrer ces échanges afin qu'ils ne soient plus lisibles et compréhensibles en sniffant le réseau.
IV. Vérifier le support SSL de MySQL
Nous allons commencer par voir si notre mysql-server supporte le SSL ou non. On se rend donc en ligne de commande sur notre serveur puis nous exécutons la commande suivante :
show variables LIKE "%ssl%";
Nous verrons normalement ce résultat :
"DISABLED" veut dire que le serveur MySQL supporte le SSL mais qu'il n'est pas activé. Si votre serveur ne support pas le SSL, il sera marqué "NO" au lieu de "DISABLED".
On pourra également le vérifier avec la commande "\s" :
On voit à nouveau que le SSL n'est pas utilisé et pas actif sur notre session actuelle.
V. Configuration serveur et génération des certificats
Pour fonctionner, le SSL sur MySQL a besoin de certificats. On va donc s'occuper de les générer. On commence par créer un répertoire dans lequel nous allons stocker nos certificats :
mkdir /etc/mysql/newcerts/ cd /etc/mysql/newcerts/
On commence par ceux de notre autorité de certification :
openssl genrsa 2048 > ca-key.pem openssl req -new -x509 -nodes -days 1000 -key ca-key.pem > ca-cert.pem
On génère ensuite le certificat de notre serveur :
openssl req -newkey rsa:2048 -days 1000 -nodes -keyout server-key.pem > server-req.pem openssl x509 -req -in server-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem
Et enfin celui de nos clients, c'est celui la que nous transfèrerons sur nos clients pour qu'ils puissent se connecter à notre serveur :
openssl req -newkey rsa:2048 -days 1000 -nodes -keyout client-key.pem > client-req.pem openssl x509 -req -in client-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem
Nous allons maintenant aller modifier la configuration de notre serveur afin de lui indiquer les certificats à utiliser et donc de lui permettre d'utiliser le SSL. On va donc modifier le fichier "/etc/mysql/my.cnf" pour y ajouter dans la section "[mysqld]" les lignes suivantes :
On va ensuite redémarrer notre serveur MySQL pour qu'il prenne en compte nos modifications de paramétrage :
service mysql restart
On va maintenant se reconnecter (en local) en ligne de commande et effectuer à nouveau nos vérifications pour voir si le SSL est bien utilisé et supporté :
show variables LIKE "%ssl%";
On voit donc maintenant que le SSL est bien utilisé et supporté par notre serveur MySQL. On pourra également le vérifier avec la commande "\s" :
On nous indique ici que le SSL n'est toujours pas utilisé. En réalité, il n'est pas utilisé pour la session en cours. En effet je me suis ici connecté en local sur la base de données en tant que root ("root@localhost"). Il est donc inutile d'utiliser le SSL. On activera plutôt le SSL pour les utilisateurs se connectant depuis des clients distants et qui génèrent donc du trafic réseau "écoutable".
VI. Configuration Client
On va maintenant passer à la configuration de notre client et de notre utilisateur. Dans la base MySQL de notre serveur il existe un champ "ssl_type" dans la tableau "mysql.user" qui définie quel type de chiffrement l'utilisateur peut utiliser. On va dans un premier temps lister les utilisateurs avec ce champ :
select user,host,ssl_type from mysql.user;
On voit donc que par défaut, le champ "ssl_type" est vide pour tous les utilisateurs ce qui veux dire qu'aucun d'entre eux n'est obligé ou ne peut utiliser le SSL pour les échanges MySQL avec le serveur. On va donc obliger notre utilisateur "neoflow" à utiliser le SSL en ajoutant "REQUIRE SSL" lors de la création de l'utilisateur :
CREATE USER "neoflow"@"192.168.1.58" IDENTIFIED BY "motdepasse" REQUIRE SSL;
Note : On peut utiliser cette commande même si l'utilisateur existe déjà.
On pourra ensuite revérifier la valeur de "ssl_type" pour notre utilisateur en utilisant la même commande que précédemment :
select user,host,ssl_type from mysql.user;
On voit donc que notre utilisateur peut utiliser toutes les formes de chiffrement SSL à présent. Nous allons aussi transférer les trois fichiers dans le client a besoin pour établir une connexion SSL. Il s'agit des fichier "ca-cert.pem", "client-cert.pem" ainsi que "client-key.pem" que l'on pourra transférer du client au serveur par SCP par exemple: voir ce tutoriel sur le transfert de fichier avec SCP
Nous pourrons par exemple mettre ces fichiers dans le répertoire "/etc/mysql/" du client. Une fois cela fait, on ira modifier la configuration du client dans le fichier "/etc/mysql/my.cnf" pour y ajouter ces trois lignes dans la section "[client]":
Il faudra alors redémarrer le mysql client pour que la nouvelle configuration mysql soit pris en compte :
service mysql restart
VII. Test de connexion à distance avec SSL
Nous allons maintenant faire un test de connexion à distance. On utilisera pour cela l'utilisateur nouvellement créé "neoflow" depuis un client ayant l'IP 192.168.1.58 ainsi que le logiciel "Wireshark" nous permettra d'analyser les échanges réseau entre le serveur et le client.
Note : Si vous faites ce tutoriel, il n'est pas nécessaire d'installer Wireshark, je le fait ici pour vous montrer que le traffic passe en clair sur le réseau mais ce n'est pas utile pour configurer SSL sur MySQL.
Depuis notre client, on exécute donc cette commande pour nous connecter à distance sur notre serveur (ici, il a l'IP 192.168.1.46/24 :
mysql -u neoflow -p -h 192.168.1.46
On pourra ensuite lister nos bases de données à distance avec la commande "show databases;" :
Nous voyons donc à nouveau notre échange client-serveur mais cette fois-ci, il est impossible d'y lire des informations sur les échanges :
On ne peut donc plus obtenir d'informations sur les échanges clients - serveur en sniffant le réseau car les échanges sont chiffrés par le SSL.
On pourra également, toujours dans notre session MySQL distante faire la commande "\s" qui nous donne des informations sur notre session :
On voit donc ici que le SSL est actif sur notre session ce qui confirme le chiffrement des échanges client - serveur.
VIII. Avoir le choix entre une connexion SSL ou non chiffrée
Quand on met dans la configuration les certificats à utiliser pour une connexion, cela peut poser problème si le client est amené à établir des connexions avec plusieurs serveurs (avec ou sans SSL). On va donc vouloir avoir la possibilité de choisir les certificats à utiliser pour l'établissement d'une connexion mais également de pouvoir établir une connexion sans SSL.
On va donc retirer dans ce cas les certificats de notre configuration MySQL client et les spécifier dans la ligne de commande à passer lors de la connexion. En utilisant les mêmes certificats, on utilisera la commande suivante :
mysql -u neoflow -p -h 1492.168.1.46 --ssl-ca=/etc/mysql/ca-cert.pem --ssl-cert/etc/mysql/client-cert.pem --ssl-key/etc/mysql/client-key.pem
Ici, on pourra donc spécifier quel certificat utiliser pour établir une connexion SSL avec tel ou tel serveur mais également ne rien préciser du tout si le serveur auquel on veut avoir accès ne demande ou ne permet pas les connexions SSL.
Merci beaucoup ça marche sur debian7 64 avec MariaDB ou MySql.
Bonjour,
J’ai suivi votre tuto et ça fonctionne chez moi. Je précise même que j’ai utilisé les certificats ssl déjà présents pour http.
Je me pose malgré tout une question : comment renseigner les certificats côté mysql client pour qu’il puisse se connecter à plusieurs serveur (ayant potentiellement des certificats différents…) ?
Merci,
Désolé, je n’avais pas lu l’article jusqu’au bout : « possibilité de choisir les certificats à utiliser pour l’établissement d’une connexion ».
Bonjour,
avez-vous une petite idée pourquoi il me réponds ceci :
« ERROR 2026 (HY000): SSL connection error: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed »
Sachant que j’ai un certificat Gandi SSL Wildcard et que la commande de connexion client est la suivante :
mysql -u phpmyadmin -p -h IP –ssl-cert=*.domaine.crt –ssl-key=*.domain.key –ssl-ca=GandiStandardSSLCA2.pem
Côté serveur :
Mariadb 10
+—————+—————————————-+
| Variable_name | Value |
+—————+—————————————-+
| have_openssl | YES |
| have_ssl | YES |
Utilisateur :
| phpmyadmin | IPSource | ANY |
NB : ce certificat est testé et validé en http.
Re,
j’ai contourné le problème en mettant en interne entre les applications et le serveur de bases de données un certificat ssl autosigné.
Slts
bonjour,
Pour ma part, ça ne marche pas. Je précise que je suis sur un NAS synology avec MariaDB.
après le restart (d’ailleurs je n’ai pas trouvé la ligne de commande qui va bien sur syno) de MariaDB que je fais via l’interface, ça démarre bien mais je suis toujours en DISABLED en ce qui concerne le SSL.
je ne trouve pas non plus les logs de démarrage de mariaDB.
Quelqu’un pourrait m’aider ?
Merci pour le tuto mais sur ma version (OS/OpenSSL) j’ai du lancer ces deux commandes supplémentaires :
openssl rsa -in server-key.pem -out server-key.pem
openssl rsa -in client-key.pem -out client-key.pem
Aussi, question probablement bête mais.. Faut il installer MySQL server côté client ? Non parce que on ne peut pas lancer « sudo service mysql restart » depuis le client si on a installé uniquement « mysql-client ».
C’est pas terrible de devoir installer une version server sur un client pour qu’il contacte un vrai serveur MySQL.
Y a t-il qq chose à faire ? Ai-je mal compris ?
Bonjour,
J’ai suivi ce tuto mais rien n’y fait, j’ai toujours « DISABLED » lorsque je vérifie.
Pourriez-vous m’aider svp ?
Hello,
Idem pour moi.
Essaye de placer tes fichiers .pem dans /etc/mysql et non dans un sous-répertoire, ça a résolu le pb sur mon Ubuntu 14.04 LTS.
P-e du à Apparmor: voir commentaire de Dana Byrd sur http://xmodulo.com/enable-ssl-mysql-server-client.html
Merci pour le tuto