Dans un environnement web critique/à fort trafic, il est courant d'avoir de
multiples serveurs web, et un ou deux load-balancer devant permettant
de répartir la charge et d'avoir une tolérance de panne sur les serveurs web.
Dans le cas d'un site en HTTPS, le flux est en général déchiffré par les
load-balancer, puis transite en clair vers les frontaux. Cela permet de
décharger les frontaux du traitement cryptographique et au load-balancer
d'interpréter le HTTP, donc d'avoir certaines fonctionnalités intéressantes
(répartition du trafic en fonction du virtualhost ou de l'URL, gestion des
cookies de session, interprétation des codes d'erreurs HTTP renvoyés par les
frontaux pour anticiper un problème, etc…).
Cependant le fait que le flux HTTP transite en clair entre les load-balancers et les frontaux peut poser problème dans certains cas :
- les données qui y transitent nécessitent un haut degré de confidentialité (numéros de cartes bancaires par exemple) ;
- le réseau entre le load-balancer et les frontaux n'est pas sûr (le flux repasse sur Internet par exemple).
Dans ces cas, la solution est de re-chiffrer le trafic après traitement par le load-balancer, puis chaque frontal le déchiffre à nouveau. Il faut bien noter que cette charge supplémentaire en traitement cryptographique (déchiffrement, re-chiffrement, re-déchiffrement), n'est pas anodine et la quantité de requêtes par seconde que peut encaisser la plateforme sera bien moindre que dans le cas d'un simple déchiffrement du flux par le load-balancer.
Pour en venir au cœur de l'article, j'ai dû mettre en place récemment une architecture de ce type, et j'ai été confronté à un problème dont je ne m'attendais pas vraiment : peu de reverse proxies HTTP savent re-chiffrer le flux HTTP vers les backends !
Parmi les logiciels existants :
- HAProxy : dans sa version stable actuelle (1.4), il ne sait pas déchiffrer le trafic entrant, et donc encore moins re-chiffer derrière. Sa version encore en dév (1.5) supporte le déchiffrement du HTTPS néanmoins ;
- Nginx : il sait bien sûr déchiffrer le HTTPS mais pas le re-chiffrer vers les backends ensuite ;
- Pound : pareil que Nginx, ne sais que déchiffrer ;
- Apache : le seul après recherche à savoir faire les 2 !
Voici la conf (en somme très simple) d'Apache pour lui dire de re-chiffrer le flux vers les backends. Elle nécessite bien évidemment d'avoir mod_proxy_http et mod_ssl :
<VirtualHost *:443>
# Activation de SSL pour le trafic entrant, cas dans le cas d'un
# serveur web classique.
SSLEngine On
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCACertificateFile /etc/ssl/certs/example.com-intermediate.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
# Activation de SSL pour la communication avec les backends.
# On vérifie au passage que le certificat fourni par le backend est
# bien valide.
SSLProxyEngine On
SSLProxyCheckPeerExpire On
SSLProxyVerifyDepth 10
# Configuration classique du mod_proxy, mis à part qu'on spécifie bien
# https dans l'URL du backend.
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / https://192.0.2.42:443/ keepalive=On retry=5
ProxyPassReverse / https://192.0.2.42:443/
ErrorLog /var/log/apache2/example.com_error.log
CustomLog /var/log/apache2/example.com_access.log combined
</VirtualHost>