Faire un proxy SSL

Faire un proxy SSL

Pour ceux qui me lisent régulièrement, je fais du multisite WordPress à ma sauce. Or, une des instances que j’héberge ainsi, a une vocation privée : une sorte d’extranet. Pour y parvenir, j’utilise un dispositif simple et efficace qui repose sur des outils particulièrement éprouvés : SSL et l’authentification HTTP Basic. Seulement voilà, les navigateurs de nos jours, pour des raisons bassement mercantiles font tout pour contraindre les propriétaires de site à acquérir des certificats souvent onéreux sans quoi ils effraieront vos usagers en leur disant que votre site n’est pas protégé. Ils vous préviennent aussi que si vous voulez vraiment y accéder, il va falloir lire plein de messages incompréhensibles et cliquer à droite à gauche.

OVH en son temps, proposait des certificats SSL bon marché opérationnels sur leur serveur mutualisé, mais il semble là aussi que le côté bon marché n’ait pas vraiment séduit. J’y vois 2 raisons selon qu’on se place du côté du développeur ou du décideur (les 2 principaux intéressés) :

  • pour les développeurs, un truc bon marché, c’est déjà plus cher qu’un truc gratuit alors pourquoi payer ?
  • pour les décideurs, un truc bon marché ça ne peut pas être sûr. En effet, dans les schémas mentaux qu’on leur a inculqués en grandes écoles, il y a cette idée que quand on veut de la sécurité en informatique, il faut payer cher !

Bilan, pour pallier à l’impossibilité d’installer un certificat personnel sur un serveur mutualisé, j’ai été contraint d’utiliser mon serveur VPS comme un simple proxy mais avec un certificat valide. Voici le schéma de fonctionnement :

Internet --- HTTPS ---> family.e-gaulue.com --- HTTPS ---> family-direct.e-gaulue.com
                   (certificat conforme sur VPS)      (certificat non conforme du mutu OVH)

La suite de cet article décrit cette installation.

La configuration côté Apache

On trouve pas mal de guides pour mettre en place un reverse proxy sous Apache. Globalement, il s’agit de mettre en oeuvre mod_proxy, mod_proxy_http (fournis par apache) et mod_proxy_html (module tiers mais généralement packagé par les principales distributions).

En gros, Apache permet de gérer ça sur la base de 3 briques :

  1. Il va falloir transformer les demandes vers un espace de nom A par des demandes vers le site B : c’est le rôle de la directive ProxyPass. Ainsi, quand le proxy recevra une requête A, il demandera le contenu correspondant à B.
  2. Ensuite, il faut réécrire les adresses éventuellement présentes dans les entêtes renvoyés par B (cas d’une réponse de type HTTP Redirect par exemple). Cela arrive peut-être rarement, mais si vous ne le faites pas votre navigateur essaiera alors de contacter directement B. C’est le rôle de la directive ProxyReversePass
  3. Enfin, le proxy renvoie le contenu HTML de B vers l’émetteur de la demande. Seulement, ce contenu est souvent plein de liens qui pointent vers B. Aussi, il est vivement préférable que le proxy en profite pour modifier ces liens : c’est le rôle du module mod_proxy_html.

Ça nous donne une configuration de ce type :

ProxyPass / https://family-direct.e-gaulue.com/
ProxyPassReverse / https://family-direct.e-gaulue.com
ProxyHTMLURLMap https://family-direct.e-gaulue.com https://family.e-gaulue.com

Pour en savoir plus, cette documentation est intéressante.

mod_proxy_html ou modproxyperlhtml

Comme indiqué mod_proxy_html a cette qualité qu’il est déjà packagé pour un ensemble de distributions. Cependant en y regardant d’un peu plus près le package Debian fourni avec squeeze (qui date de février 2011) n’est qu’en version 3 alors qu’une version 3.1 existe depuis fin 2009. Étrange : instabilité de la version ? Perte de vitalité du projet ? En tout cas, il n’est pas si simple à faire fonctionner et manque de documentation récente. Enfin, il est très/trop intrusif : il essaie de générer un code HTML propre (mais ne connaît pas HTML 5), il peut faire du transcodage… Pour l’ensemble de ces raisons, je me suis tourné vers un autre module : modproxyperlhtml.

Le principal défaut de ce dernier c’est son installation puisqu’il n’existe pas de module prepackagé (à vrai dire ce n’est qu’une pustule de mod_perl, donc surement ne le sera-t-il jamais). Aussi, je vais décrire ici, ce que j’ai fait sous Debian Squeeze.

D’abord, il faut mod_perl, s’il n’est pas déjà installé. Et comme nous allons « compilé » modproxyperlhtml, il nous faudra aussi la version de développement (ce dernier point est peu documenté) :

> apt-get install libapache2-mod-perl2 libapache2-mod-perl2-dev

Ceci étant fait, il faut récupérer les sources du module, sur le CPAN par exemple.

> locate Zlib
...
/usr/lib/perl/5.10.1/IO/Compress/Zlib
/usr/lib/perl/5.10.1/IO/Compress/Zlib/Constants.pm
/usr/lib/perl/5.10.1/IO/Compress/Zlib/Extra.pm
...

Je me suis dit que ça devait être ce qu’il fallait (désolé de ne pas aider plus ceux qui n’auraient pas ces dépendances déjà installées).

Ensuite, il suffit de lire la documentation de modproxyperlhtml :

> make
> make install
> ls /usr/local/share/perl/5.10.1/Apache2
/usr/local/share/perl/5.10.1/Apache2/ModProxyPerlHtml.pm

Les 2 dernières lignes confirment la présence du nouveau module. Ensuite, il reste à configurer Apache.

ProxyPass / https://family-direct.e-gaulue.com/
ProxyPassReverse / https://family-direct.e-gaulue.com/
 
PerlInputFilterHandler Apache2::ModProxyPerlHtml
PerlOutputFilterHandler Apache2::ModProxyPerlHtml
 
SetHandler perl-script
 
#If you need debugging features
PerlSetVar ProxyHTMLVerbose "On"
LogLevel Info
 
<Location />
    PerlAddVar ProxyHTMLURLMap "https://family-direct.e-gaulue.com https://family.e-gaulue.com"
</Location>

À dire vrai, le PerlInputFilterHandler n’a pas d’intérêt pour moi puisque mes utilisateurs n’ont pas de raison de m’envoyer du code HTML, ni des en-têtes à traduire. Au passage, je recommande la lecture de la documentation de mod_perl2.

Mettre en place le certificat SSL

Tout ceci est bien beau, mais pour le moment je n’ai pas encore parlé de certificat. Après une courte recherche google, il semble, à l’heure où j’ai écrit ce billet, que seul startssl.com fourni des certificats gratuits pour un usage particulier.

Je ne donnerai ici que les grandes lignes suivies. Quand on se connecte sur le site startssl.com on se dirige vers StartSSL Free puis de là il est conseillé d’aller dans le Certificate Control Panel. Là, divers choix s’offrent à vous suivant que vous disposez déjà d’un compte ou non. Personnellement, j’ai suivi l’Express Line qui par une suite d’écrans crée votre compte et vous fournit le certificat de façon relativement simple. Les formulaires permettront dans un premier temps de vous enregistrer chez StartSSL. À l’issue, une clef privée vous est fournie et un certificat devrait s’installer dans votre navigateur. Il vous permettra de vous authentifier sur le site startssl.com lors de vos prochaines visites, aussi il peut être bon de le conserver en lieux sûrs. Ensuite, on passe à l’étape de la création du certificat pour votre serveur. Là, il vous sera demandé un mot de passe qui sera utilisé pour chiffrer la clé privée associée au certificat de votre serveur (et qu’il faudra bien entendu déchiffrer au moment de son installation). Enfin, on vous demandera les informations classiques nécessaires à la création d’un certificat dont fondamentalement le nom de votre serveur (dans mon cas family.e-gaulue.com).

Il n’y a plus qu’à installer tout cela. StartSSL vous fournit un guide, en particulier il faut télécharger des certificats intermédiaires nécessaires au chaînage (ben oui c’est gratuit, alors on ne peut pas tout avoir). À supposer que vous avez tous les fichiers et qu’ils sont sécurisés sur votre serveur dans les répertoires fournis par Debian ainsi :

> ls -lR /etc/ssl
./certs/startssl:
-rw-r--r-- 1 root root 2760 2008-05-07 02:49 ca.pem
-rw-r--r-- 1 root root 2548 2012-01-13 22:52 ssl-cert-family.crt
-rw-r--r-- 1 root root 2212 2010-04-18 00:20 sub.class1.server.ca.pem
 
./private:
-rw-r----- 1 root ssl-cert 1706 2012-01-13 22:51 ssl-cert-family.key

Il reste alors à ajouter ces directives pour notre site pour qu’il communique en HTTPS avec le certificat qui convient.

SSLEngine on
 
SSLCertificateFile    /etc/ssl/certs/startssl/ssl-cert-family.crt	
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-family.key
 
SSLCertificateChainFile /etc/ssl/certs/startssl/sub.class1.server.ca.pem
SSLCACertificateFile /etc/ssl/certs/startssl/ca.pem

Finir le paramétrage du proxy

Que reste-t-il à faire ? Pas grand-chose.

Dans notre cas, on n’a pas besoin de tuneliser les requêtes HTTPS vers le serveur final, on se comporte en fait comme un man in the middle. Il suffit donc d’ajouter la directive SSLProxyEngine On.

Il faut également vérifier que l’on autorise bien les requêtes vers des serveurs HTTPS qui présentent des certificats non conformes. C’est le rôle de la directive SSLProxyVerify mais qui normalement par défaut est à none, autrement dit, aucune vérification.

Enfin, pourquoi ne pas profiter de la situation pour retirer 2 variables ajoutées dans les en-têtes, l’une par WordPress pour le ping-back qui est inutile pour ce type de site « privé » et l’autre par OVH pour garantir le suivi des sessions sur leur ferme de serveurs, là encore inutile puisqu’en théorie, il n’y aura pas de session sur le serveur distant pour des usagers en simple lecture. Et puis s’il le faut on peut raffiner : on retire tous les cookies sauf si l’URL demandée pointe vers l’interface d’administration.

Header unset X-Pingback
<LocationMatch "^/(?!family/)">
        Header unset Set-Cookie
</LocationMatch>

Comme un blog, ça ne bouge pas beaucoup, j’avais également pensé à mettre en place un cache. Si Apache est globalement ton ami, là les choses se compliquent un peu : HTTPS, proxy, authentification HTTP… c’est un peu trop pour lui. Du moins pour le moment, car des directives à venir semblent prometteuses.

Une réaction au sujet de « Faire un proxy SSL »

  1. excellent article .
    j’aime beaucoup tous ces informations pour le proxy ssl.
    merci pour le partage .

Répondre à Cahier des charges site Internet Annuler la réponse

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