Servir plusieurs noms de domaines en HTTPS en auto-hébergement

Actuellement, mon FAI ne me propose que de l’IP v4.
Donc je n’ai qu’une adresse IP publique, et en plus elle n’est pas fixe.

Malgré cela, il y a des solutions pour s’auto-héberger, y compris avec plusieurs noms de domaines, et avec du cryptage SSL.

La résolution DNS

J’ai acheté mes noms de domaines chez Gandi. Comme chez n’importe quel registrar, il est facile de configurer son DNS pour qu’il pointe vers la bonne adresse IP.

Oui mais comment faire si l’IP n’est pas fixe ?

Il y a des solutions type dyndns.org (dont le service est hélas devenu payant), mais on ne peut pas utiliser son propre nom de domaine : ce n’est forcément qu’un sous-domaine.

Heureusement, ils ont la bonne idée chez Gandi de proposer une API, qui permet (entre autres) de modifier les DNS à distance.

Gandi_logo_black

Et il existe un petit script Python qui permet d’automatiser la mise à jour du DNS quand l’adresse IP change : https://github.com/Chralu/gandyn/ (j’y ai très modestement contribué)

Ca marche plutôt très bien. Je le lance alternativement sur mes 2 noms de domaines via crontab : l’un à 0 minutes, l’autre à 30 minutes de chaque heure :

Ce délai est suffisant dans mon cas : mon IP n’est pas fixe mais elle change très peu souvent (autour d’une fois par an). Il faut aussi penser à choisir un TTL (Time To Live) suffisamment court pour vos entrées DNS : j’ai mis 15 minutes mais ces valeurs peuvent se discuter…

Le seul point faible est que la recherche de l’adresse IP s’appuie sur un service externe : http://ifconfig.me/ip . Et il n’est pas extrêmement fiable : j’ai souvent des timeouts.

Configuration SSL/TLS

Sur les 2 noms de domaine, j’utilise du cryptage SSL (ou plutôt TLS) pour certaines communications en HTTPS.

Il y a quelques années, il n’était pas possible d’héberger sur une même adresse IP plusieurs noms de domaines en HTTPS. Logique puisque la négociation du certificat SSL/TLS se fait avant l’envoi effectif de la requête HTTP (pour qu’elle soit elle-même cryptée). Le serveur HTTP, ne connaissant pas l’URL, ne peut donc pas choisir entre les différents certificats.

Mais ouf, il y a maintenant le SNI : https://fr.wikipedia.org/wiki/Server_Name_Indication

Ça permet justement d’indiquer au serveur quel est le nom de domaine auquel on veut accéder AVANT la négociation TLS. Et le serveur est donc capable de choisir le bon certificat.

Il faut bien sûr un serveur compatible ET un client compatible : https://en.wikipedia.org/wiki/Server_Name_Indication#Support . En résumé :

  • Côté serveur, il faut un Apache >=2.2.12 ou Tomcat sur un Java>=1.7
  • Côté client, n’importe quel Firefox >=2.0 ou Chrome>=6 ou IE>=7 (mais uniquement à partir de Vista), et côté mobiles iOS>=4.0 ou Android>=3.0 ou Windows Phone>=7.0 ou Firefox OS>=1.0

Cela parait des critères raisonnables en 2014, mais comment ça se passe si un utilisateur se connecte quand même avec un client non compatible ? Par exemple IE8 sur Windows XP (Oui il en reste encore…) Avec la configuration d’Apache par défaut, le serveur prend le premier des deux certificats, et a donc une chance sur 2 de se tromper. Dans ce cas, le navigateur va râler sur le fait que le certificat ne correspond pas au nom de domaine.

Une solution radicale consiste à activer l’option ci-dessous dans Apache :

Cette option se situe (sous Debian ou Ubuntu) dans /etc/apache2/mods-enabled/ssl.conf , et elle est commentée par défaut (c’est-à-dire à Off).

Si cette option est activée, un browser non compatible se verra carrément refuser l’accès. C’est ce que j’ai fait.

Comment générer les certificats SSL ?

Dans mon cas, l’objectif est uniquement de crypter la communication, notamment pour que les mots de passe d’administration ne passent pas en clair.

Première possibilité : un certificat auto-signé

https://wiki.debian.org/Self-Signed_Certificate

Avantage : simple, rapide et gratuit. On peut choisir librement toutes les caractéristiques du certificat, y compris sa date d’expiration ou le fait qu’il soit wildcard

Inconvénient : Il y aura un avertissement affiché par les navigateurs puisque vous n’êtes pas une autorité de certification qu’ils connaissent.

Deuxième possibilité : un certificat gratuit ou pas cher

Il en existe pas mal qui ne sont pas très chers, voire même gratuits.  Mais attention à ce qu’ils soient sérieux.

Gandi offre un certificat SSL la première année, puis ça coûte 12€ HT par an : https://www.gandi.net/ssl

Mais un certificat wildcard coûte beaucoup plus cher : 120€ HT par an, chez Gandi.

Avantage : pas d’avertissement du navigateur

Inconvénient : un wildcard coûte vraiment cher

Troisième possibilité : un certificat (gratuit) généré par CACert

cacert4

CACert est une initiative communautaire pour délivrer gratuitement des certificats SSL. Le principe est de faire une « toile de confiance » : au lieu de payer un organisme qui vérifie notre identité, la vérification est faite par vous et moi, à travers un système d’accréditeurs et de points.

Avantage  : gratuit, participation à la toile de confiance, permet les certificats wildcard

Inconvénient : long à mettre en œuvre si on veut un certificat qui dure + de 6 mois, puisqu’il faut rencontrer physiquement plusieurs accréditeurs. Mais le principal inconvénient reste que le certificat racine de CACert n’est accepté par défaut par aucun des principaux navigateurs du marché. Donc il y aura quand même un avertissement du navigateur chez quasiment tout le monde.

Dans mon cas, le cryptage ne sert pour l’instant qu’à l’administration et à des services non publics. D’autre part, je voulais un certificat wildcard : j’ai finalement opté pour CACert, dont la philosophie me plaît.

Certificats wildcard

Au fait, je parle de wildcard depuis plusieurs paragraphes : c’est quoi un certificat wildcard ?

C’est tout simplement un certificat qu’on peut utiliser pour n’importe quel sous-domaine. Exemple : le certificat *.domaine.fr peut être utilisé pour sousdomaine1.domaine.fr et sousdomaine2.domaine.fr. Il n’y a pas besoin de générer un nouveau certificat quand on rajoute un sous-domaine.

Dans mon cas, j’utilise beaucoup de NameVirtualHost dans Apache, qui se basent justement sur le sous-domaine pour diriger vers un service ou un autre. Donc un wildcard est très adapté.

Seul hic sur lequel je suis tombé : un *.domaine.fr ne couvre par défaut pas le nom « domaine.fr » tout court : il ne couvre que les sous-domaines. C’est d’ailleurs précisé dans la doc de Gandi.

Pour créer un certificat qui couvre aussi domaine.fr, la demande de certificat est un poil plus compliquée, car il faut y ajouter un SubjectAltName qui correspond à « domaine.fr » tout court.

J’ai essayé de m’appuyer sur http://techbrahmana.blogspot.fr/2013/10/creating-wildcard-self-signed.html mais ça n’a pas fonctionné : il semble que CACert ignore le SubjectAltName mis de cette manière.

La solution est venue de chez CACert même, en utilisant un petit script qui génère le fichier CSR nécessaire : http://wiki.cacert.org/VhostTaskForce#Shell_Script

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *