TL;DR : le système GNU/Linux Fedora a désactivé la prise en charge des suites cryptographiques reposant sur l'algorithme de chiffrement symétrique 3DES de la bibliothèque cryptographique (mais pas que) NSS qu'il fournit dans ses paquets. Conséquence : le logiciel Firefox packagé dans Fedora n'est plus en mesure d'accéder, en HTTPS, à des sites web qui proposent uniquement des suites cryptographiques qui incluent 3DES.
Ce shaarli est surtout l'occasion de réviser les différentes commandes système qui permettent de diagnostiquer ce genre de cas ainsi que d'apprendre à installer un reverse proxy Apache httpd compatible avec un site web de destination qui accepte uniquement 3DES, ce qui est loin d'être aussi trivial qu'on le pense au premier abord.
Il y a quelques mois, un collègue met à jour sa station de travail Fedora 25/26 (probablement) en Fedora 29. Un des sites web dont nous avons la responsabilité cesse alors de fonctionner avec son Firefox 62 : « An error occurred during a connection to siteweb.example. Cannot communicate securely with peer: no common encryption algorithm(s). Error code: SSL_ERROR_NO_CYPHER_OVERLAP ».
En revanche, cela continue de fonctionner avec son Chrome 72 installé via le paquet rpm récupéré directement sur le site web officiel de Google.
Aucun problème avec Firefox 62 et 66 sur Ubuntu 18.04 et 18.10 ainsi que sur Debian Stretch.
L'erreur est plutôt explicite : le client et le serveur n'ont pas d'algorithmes de chiffrement en commun.
J'utilise les testeurs TLS habituels : le serveur prend en charge uniquement les algorithmes de chiffrement symétrique RC4 et 3DES (la suite cryptographique TLS-RSA-WITH-3DES-EDE-CBC-SHA, pour être précis). Oui, ce site web est un vieux bouzin hébergé sur un système GNU/Linux Debian 4, oui c'est scandaleux, mais si t'es OK pour venir démanteler ce serveur (et surtout tout le bout de SI qu'il contient) gratuitement (si l'on était en capacité d'embaucher, on le ferait ;) ), on prend (attention : il y a des mois de taff, une conduite du changement à mener, etc.). :)
Mon hypothèse est la suivante : dans la pratique, RC4 a été abandonné il y a quelques années, 3DES vient de l'être dans la bibliothèque cryptographique utilisée par Firefox sur Fedora.
Pour le savoir, utilisons leur utilitaire en ligne de commande.
$ openssl s_client -connect siteweb.example:443
140134895833152:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1407:SSL alert number 40
$ gnutls-cli siteweb.example:443
- Handshake was completed
Je n'ai pas trouvé d'outil en ligne de commande pour manipuler la bibliothèque NSS.
Notons que ni 3DES ni RC4 apparaissent dans openssl ciphers
. En revanche, ils apparaissent dans gnutls-cli -l
.
Notons que curl, qui utilise OpenSSL, ne parvient pas à se connecter à notre site web, alors que wget, qui utilise GnuTLS, y parvient.
Note : j'ai rencontré un comportement bizarre. Lors de mon diagnostic avec mon ordinateur professionnel il y a quelques mois, GnuTLS (gnutls-cli
, wget
, etc.) ne parvenait pas à se connecter au site web. Pour y parvenir, il fallait activer les algorithmes de chiffrement dépréciés parmi lesquels se trouvent 3DES avec la commande gnutls-cli --priority LEGACY siteweb.example:443
(gnutls-cli --priority LEGACY -l
affichait 3DES alors que gnutls-cli -l
ne l'affichait pas). Lors de la rédaction de ce shaarli, cela fonctionne avec mon ordinateur personnel et professionnel… Le seul changement que je vois, c'est la mise à jour de mon ordinateur professionnel vers Debian 9.8 ou 9.9. Pourtant, on constate, dans les snapshots Debian, que le paquet libgnutls30 n'a pas été mis à jour ces derniers mois. De même, la date de dernière modification du fichier /usr/lib/x86_64-linux-gnu/libgnutls.so.30.13.1 est le 6 octobre 2018, ce qui correspond à ce qui est consigné dans /usr/share/doc/libgnutls30/changelog.Debian.gz. Bref, le mystère reste entier…
Avec openssl s_client
, le comportement est identique à celui observé précédemment : impossible de négocier une session TLS.
$ gnutls-cli siteweb.example:443
*** Fatal error: A TLS fatal alert has been received.
*** Received alert [40]: Handshake failed
*** handshake has failed: A TLS fatal alert has been received.
Il n'est pas possible d'activer 3DES avec gnutls-cli --priority LEGACY
, car 3DES ne figure pas dans la liste des algorithmes membres de ce groupe.
On se souvient que les chaînes de priorité de GnuTLS, c'est comme les profils d'OpenSSL : la liste des suites cryptographiques membres d'un de ces groupes peut changer sans prévenir entre deux versions. Il est possible d'utiliser explicitement la suite cryptographique TLS-RSA-WITH-3DES-EDE-CBC-SHA qui nous intéresse avec la commande suivante : gnutls-cli --priority "NORMAL:+3DES-CBC" siteweb.example:443
. Notre site web est alors accessible.
On constate une différence de comportement entre deux bibliothèques cryptographiques très utilisées : les suites cryptographiques utilisant 3DES pour le chiffrement symétrique ne sont plus disponibles dans OpenSSL mais continuent de l'être dans GnuTLS.
On constate également une différence entre deux systèmes GNU/Linux pour une même bibliothèque : les suites cryptographiques embarquant 3DES ne peuvent pas être utilisées avec Fedora 30 et GnuTLS, alors qu'elles le peuvent avec Debian et GnuTLS. Il est également crédible de penser que le retrait de 3DES la priorité LEGACY a eu un impact sur les logiciels qui utilisent GnuTLS en spécifiant ce groupe de suites cryptographiques. Dit autrement : sauf si un logiciel qui repose sur la libgnutls spécifie explicitement l'utilisation de 3DES, 3DES n'est plus disponible.
J'utilise la version 60.6 ESR de Firefox, celle packagée dans le dépôt officiel de Debian. L'accès au site web fonctionne. En revanche, si je désactive 3DES en changeant, dans about:config
, la valeur de security.ssl3.rsa_des_ede3_sha
à false
, alors le site web ne fonctionne plus. Cela confirme la piste de la prise en charge ou non de 3DES comme source de notre problème.
Je pensais qu'un ldd /usr/lib/firefox-esr/firefox-esr
suffirait pour démasquer la bibliothèque cryptographique utilisée par Firefox… mais ce n'est pas le cas. Et pour cause : le vrai exécutable de Firefox est libxul.so
. Il s'agit d'un objet partagé, comme la plupart des binaires de base. ldd /usr/lib/firefox-esr/libxul.so
nous montre que la lib TLS utilisée est /usr/lib/firefox-esr/libssl3.so
.
$ apt-file search /usr/lib/firefox-esr/libssl3.so
firefox-esr: /usr/lib/firefox-esr/libssl3.so
La libssl3 est fourni avec le paquet Firefox lui-même.
Si nous nous amusons à récupérer toutes les chaînes de caractères contenues dans le binaire avec la commande strings /usr/lib/firefox-esr/libssl3.so
, nous nous rendons compte que nous sommes en présence d'un bout de la fameuse bibliothèque NSS (« Version: NSS 3.36.7 »). Si nous nous amusons avec objdump -T /usr/lib/firefox-esr/libssl3.so
nous nous rendons compte que cette bibliothèque contient bien les fonctions qui permettent d'établir une session TLS avec NSS (« SSL_ResetHandshake », « PR_Read », etc.).
J'aurais voulu m'assurer que c'est bien cette bibliothèque qui est utilisée pour établir des connexions TLS, mais je ne suis pas parvenu à mes fins avec ltrace
qui permet de tracer les appels aux bibliothèques. ltrace -f firefox-esr
est bien trop lent, Firefox est inutilisable (on parle de plusieurs dizaines de minutes pour ouvrir un Firefox vierge, et impossible de manipuler les onglets). ltrace -p <PID_Firefox> -l /usr/lib/firefox-esr/libssl3.so
et ltrace -p <PID_Firefox -e SSL_ResetHandshake
avec un ltrace
par processus Firefox, retournent rien, aucun appel. C'est le cas de plein de binaires (wget, curl, gnutls-cli, etc.) alors que ça fonctionne avec d'autres (openssl s_client, ls, etc.)… Je n'ai pas l'explication.
Un autre moyen de débusquer la lib NSS (libssl3.so) est d'utiliser strace -f -e open,openat firefox-esr
. C'est d'ailleurs la piste que j'ai choisie initialement. En passant, rappelons-nous que la différence entre ldd
et strace
, c'est que la première commande montre la théorie, c'est-à-dire ce qui se passerait si on appelait le linker en exécutant ce binaire. C'est une simulation. La deuxième commande montre ce qui s'est réellement passé. La théorie peut être contournée par le programme lui-même. En surchargeant « LD_LIBRARY_PATH », par exemple. C'est d'ailleurs ce que fait Firefox. Pour observer cela, il suffit d'utiliser la commande suivante : tr '\0' '\n' < /proc/<PID_Firefox>/environ | grep LD_LIBRARY_PATH
. Sur le processus Firefox parent, la variable d'environnement n'existe pas. En revanche, elle est bien positionnée sur les processus enfant. On comprend maintenant un peu mieux ce que fait le mini-binaire /usr/lib/firefox-esr/firefox-esr . ;)
Pour identifier libxul.so, j'ai utilisé ncdu /usr/lib/firefox-esr/
pour chercher l'objet ayant une occupation sur le disque crédible pour un navigateur moderne alors que le binaire firefox-esr
occupe seulement quelques kilooctets.
Mon collègue utilise la version 66 de Firefox, celle packagée dans le dépôt officiel de Fedora. L'accès à notre site web ne fonctionne pas. La valeur de security.ssl3.rsa_des_ede3_sha
est bien « true ».
Identifions la bibliothèque TLS utilisée par Firefox :
$ whereis -b firefox
firefox: /usr/bin/firefox /usr/lib64/firefox /etc/firefox
[ comprendre le script /usr/bin/firefox ]
$ strace -f -e open,openat /usr/lib64/firefox/firefox 2>&1 | grep -E '(ssl|tls|nss)'
openat(AT_FDCWD, "/usr/lib64/firefox/libssl3.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libssl3.so", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/usr/lib64/firefox/libnss3.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libnss3.so", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/usr/lib64/firefox/libnssutil3.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libnssutil3.so", O_RDONLY|O_CLOEXEC) = 4
[…]
$ rpm -qf /lib64/libssl3.so
nss-3.43.0-1.fc30.x86_64
On constate que, là aussi, le binaire firefox
surcharge LD_LIBRARY_PATH. Mais, contrairement à Debian, la bibliothèque NSS n'est pas livrée avec le paquet firefox
donc elle est introuvable à l'emplacement indiqué, donc le linker se rabat sur la bibliothèque NSS livrée par le paquet nss
et installé dans le dossier système.
Je me suis heurté à la même limite concernant l'utilisation de ltrace
.
J'ai obtenu la certitude que c'est la libssl3 est bien la lib utilisée pour effectuer des échanges TLS en virant le paquet nss
sans virer les paquets qui dépendent de lui avec rpm -e --nodeps nss
et en utilisant la lib NSS de mon Debian. Notre site web fonctionnait alors très bien.
Notre site web fonctionne sur un système Ubuntu 16.04 avec un Firefox 62 ainsi que sur un Ubuntu 18.04 avec un Firefox 65.
Sur le Firefox 65, la bibliothèque TLS utilisée est /usr/lib/firefox/libssl3.so
, fournie par le paquet firefox
.
ldd
/ ltrace
/ strace
: ldd c'est la théorie, une simulation, strace, c'est la pratique, une description factuel de ce qui s'est passé ;nss
avec rpm -q --changelog nss
, mais il y a rien d'intéressant (« Update to » telle version, « Rebuild for » tel événement majeur, etc.). J'ai aussi lu les notes de versions du projet NSS jusqu'à la version 3.20, sans succès. Vu la différence de version, je penche pour un changement côté Fedora.strace
, la bibliothèque utilisée est celle fournie dans l'archive. strings
ne permet pas de récupérer la version ni beaucoup d'info, un nettoyage ayant été fait, il faut croire. En tout cas, tout laisse à penser que c'est Fedora qui a changé les drapeaux de compilation de la lib NSS qu'elle fournit dans son dépôt, pas Firefox.Ben oui, mon collègue rapporte que notre site web est toujours accessible avec Chrome 72 sous Fedora 29. Comment est-ce possible ? La première idée qui vient à l'esprit est que Chrome utilise une autre bibliothèque cryptographique. Laquelle ?
$ whereis google-chrome
google-chrome: /usr/bin/google-chrome /usr/share/google-chrome /usr/share/man/man1/google-chrome.1.gz
$ file /usr/bin/google-chrome
/usr/bin/google-chrome: symbolic link to /etc/alternatives/google-chrome
$ file /etc/alternatives/google-chrome
/etc/alternatives/google-chrome: symbolic link to /usr/bin/google-chrome-stable
$ file /usr/bin/google-chrome-stable
/usr/bin/google-chrome-stable: symbolic link to /opt/google/chrome/google-chrome
$ file /opt/google/chrome/google-chrome
/opt/google/chrome/google-chrome: Bourne-Again shell script, ASCII text executable
[ comprendre ce script … ]
$ file /opt/google/chrome/chrome
/opt/google/chrome/chrome: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=0da5431fb81fa27f574e46f3bb0d66397b34ed74, stripped
$ ldd /opt/google/chrome/chrome | grep -E '(nss|ssl|tls)'
libnss3.so => /lib64/libnss3.so (0x00007fe1ff5f2000)
libnssutil3.so => /lib64/libnssutil3.so (0x00007fe1ff5bf000)
libgnutls.so.30 => /lib64/libgnutls.so.30 (0x00007fe1fe11b000)
Ainsi Google Chrome utiliserait la lib GnuTLS ? Pourtant, nous avons vu qu'il faut spécifier explicitement 3DES (seul ou parmi une liste) pour que cet algorithme de chiffrement symétrique soit utilisable. Google ferait-il ça ?
Je trouve curieux que GnuTLS ne soit pas indiquée comme dépendance de Chrome dans le .deb et le .rpm fournis par Google… Pour savoir cela, il faut consulter le fichier nommé « control » dans le dossier « DEBIAN » en utilisant un gestionnaire d'archives pour ouvrir le .deb. Pour le rpm, il faut utiliser la commande rpm -qp --requires <fichier_rpm>
. Ceci dit, ce n'est pas une référence fiable : le rpm mentionne une dépendance à libssl3 >= NSS 3.28, alors que cette librairie n'est pas du tout utilisée…
En cherchant sur le web, je constate que, si GnuTLS fut utilisé, il semblerait qu'aujourd'hui, ce soit BoringSSL, un fork maison d'OpenSSL suite à l'affaire Heartbleed, qui l'est.
Pourquoi ldd
et strace
ne voient aucun appel à cette bibliothèque ? Peut-être parce qu'elle est compilée statiquement alors que ldd
et strace
permettent uniquement d'identifier les chargements dynamiques ? Vérifions :
$ strings /opt/google/chrome/chrome
[…]
../../third_party/boringssl/src/ssl/tls13_client.cc
../../third_party/boringssl/src/ssl/tls13_server.cc
../../third_party/boringssl/src/ssl/tls13_both.cc
../../third_party/boringssl/src/ssl/dtls_record.cc
../../third_party/boringssl/src/ssl/tls_record.cc
../../third_party/boringssl/src/ssl/dtls_method.cc
../../third_party/boringssl/src/ssl/tls_method.cc
../../third_party/boringssl/src/ssl/tls13_enc.cc
../../third_party/boringssl/src/crypto/cipher_extra/e_tls.c
[…]
TLS_RSA_WITH_NULL_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_PSK_WITH_AES_128_CBC_SHA
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_PSK_WITH_AES_256_CBC_SHA
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
[…]
LS_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256
TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
[…]
TLS_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
[…]
TLSV1_ALERT_ACCESS_DENIED
TLSV1_ALERT_DECODE_ERROR
TLSV1_ALERT_DECRYPTION_FAILED
TLSV1_ALERT_DECRYPT_ERROR
TLSV1_ALERT_EXPORT_RESTRICTION
TLSV1_ALERT_INAPPROPRIATE_FALLBACK
TLSV1_ALERT_INSUFFICIENT_SECURITY
TLSV1_ALERT_INTERNAL_ERROR
TLSV1_ALERT_NO_RENEGOTIATION
TLSV1_ALERT_PROTOCOL_VERSION
TLSV1_ALERT_RECORD_OVERFLOW
TLSV1_ALERT_UNKNOWN_CA
TLSV1_ALERT_USER_CANCELLED
TLSV1_BAD_CERTIFICATE_HASH_VALUE
TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE
TLSV1_CERTIFICATE_REQUIRED
TLSV1_CERTIFICATE_UNOBTAINABLE
TLSV1_UNKNOWN_PSK_IDENTITY
TLSV1_UNRECOGNIZED_NAME
TLSV1_UNSUPPORTED_EXTENSION
En effet, ça ressemble quand même bien à ce que l'on trouve dans une bibliothèque cryptographique.
Google Chrome 72 sous Fedora 29 continue d'afficher notre site web car il utilise une bibliothèque interne et que Google n'a pas désactivé 3DES dans celle-ci.
Même si la bibliothèque NSS ne prend plus en charge 3DES uniquement sur Fedora, même si la majorité des navigateurs peuvent toujours accéder à notre site web "3DES-only", nous avons décidé d'installer un reverse proxy HTTP en frontal de notre site web "3DES-only". De toutes façons, c'était un point dans notre liste des choses à faire, cette histoire n'a fait que nous le remettre à l'esprit.
Pour ce faire, nous utiliserons Apache httpd sur un système GNU/Linux Debian. Parce que c'est ce qu'on connaît, parce que c'est ce qu'on a en prod'.
La question qui se pose est : quelle configuration pour notre reverse proxy ?
On pourrait se passer de TLS entre le reverse proxy et le site web. Ce n'est pas très cool, mais les deux serveurs sont sur le même réseau, branchés au même commutateur, donc bon… Si l'on se fait pirater à ce niveau-là, il y a des choses bien plus lucratives à faire qu'espionner les conversations entre ce futur reverse proxy et ce site web.
Mais cela ne fonctionnera pas, car notre site web propose des redirections HTTP aux navigateurs web, soit en utilisant la balise HTML meta refresh, soit en utilisant la fonction header
de PHP. Dans les deux cas, le protocole indiqué dans l'URL à laquelle le navigateur doit se rendre est parfois « https ». On obtiendrait donc une boucle infinie : notre proxy discute en http avec notre site web, celui-ci le redirige vers une URL HTTPS, on transmet au client, celui-ci revient discuter avec le proxy en https, le proxy discute en http avec le site web, qui lui dit de revenir en https, etc.
Comme une majorité de personnes, nous utilisons le module mod_ssl d'Apache httpd. Celui-ci repose sur OpenSSL… qui, comme nous l'avons vu au début de ce shaarli, ne prend plus en charge 3DES quand elle est fournie par le système de paquets d'un système Debian 9.
Tentons quand même avec cette configuration Apache httpd minimale :
SSLProxyEngine on
ProxyPass "/" "https://backend-siteweb.example/"
ProxyPassReverse "/" "https://backend-siteweb.example/"
Notre navigateur affiche une page d'erreur « 502 - proxy error ». Le journal d'erreur du virtualhost Apache httpd consigne :
[proxy_http:error] [pid 30044] (103)Software caused connection abort: [client 127.0.0.1:34358] AH01102: error reading status line from remote server backend-siteweb.example:443
[proxy:error] [pid 30044] [client 127.0.0.1:34358] AH00898: Error reading from remote server returned by /
Le module mod_gnutls permet à Apache httpd d'utiliser la bibliothèque GnuTLS pour établir les connexions chiffrées. Au début de ce shaarli, nous avons vu que 3DES n'est pas (encore) désactivé dans cette bibliothèque quand elle est fournie par le système de paquets d'un système Debian 9. La documentation de mod_gnutls est disponible ici.
Pour installer ce module :
apt-get install libapache2-mod-gnutls
;a2dismod ssl && a2enmod gnutls && systemctl restart apache2
.
Sa configuration est un peu plus complexe.
Pour activer TLS entre le proxy et le site web (« GnuTLSProxyEngine »), il faut également activer TLS entre le client et le proxy (« GnuTLSEnable »). Dit autrement, il n'est pas possible de communiquer de manière non chiffrée (HTTP) avec le client tout en communiquant de manière chiffrée (HTTPS) avec le site web. Ce comportement est plutôt inattendu et diffère de celui de mod_ssl. Notons qu'il est parfois difficile de se rendre compte de ce point : si la destination du proxy est un vieux site web, une communication HTTP non chiffrée est tentée par mod_proxy_http après l'échec de l'établissement de la connexion TLS et aucune erreur TLS est consignée dans le journal d'Apache httpd.
« GnuTLSEnable » impose de préciser la valeur des directives « GnuTLSCertificateFile », « GnuTLSKeyFile » et « GnuTLSPriorities ». Si les deux premières sont habituelles, la dernière est plus suprenante… Sans elle, un systemctl restart apache2
échoue sans rien consigner côté systemd/journald. Mais le journal d'erreur du virtualhost indique clairement « GnuTLS: Host 'siteweb.example:0' is missing the GnuTLSPriorities directive! ».
De la même façon, « GnuTLSProxyEngine » impose de préciser la valeur de la directive « GnuTLSProxyPriorities ». Sans elle, le journal d'erreur du virtualhost consigne « Host 'siteweb.example:0' is missing the GnuTLSProxyPriorities directive! mgs_hook_post_config: loading proxy credentials for host 'siteweb.example:0' failed, exiting! ».
Même si le certificat x509 du site web est signé par une autorité de certification publique reconnue, « GnuTLSProxyEngine » impose de préciser un catalogue contenant les certificats des autorités de certificats publiques reconnues. Je vais utiliser /etc/ssl/certs/ca-certificates.crt
qui est généré et maintenu à jour par le paquet Debian ca-certificates
. Bout de conf' à utiliser dans le virtualhost : « GnuTLSProxyCAFile /etc/ssl/certs/ca-certificates.crt ». Sans cela, le journal d'erreur du virtualhost indique :
[gnutls:warn] [pid 7562] load_proxy_x509_credentials: no CA trust list for proxy connections, TLS connections will fail!
[gnutls:warn] [pid 7565] [remote 192.0.2.1:443] gtls_check_server_cert: The certificate is NOT trusted. The certificate issuer is unknown.
[proxy_http:error] [pid 7565] (104)Connection reset by peer: [client 127.0.0.1:38258] AH01102: error reading status line from remote server backend-siteweb.example:443
[proxy:error] [pid 7565] [client 127.0.0.1:38258] AH00898: Error reading from remote server returned by /
Les deux dernières lignes indiquent que l'échec de l'initialisation de la connexion TLS n'a pas empêché mod_proxy_http de tenter une connexion HTTP. Un tcpdump
confirme cela : une requête non chiffrée est envoyée au port 443 du site web de destination. Ce comportement est totalement différent de celui de mod_ssl.
Au final, la configuration minimale pour ce reverse proxy est :
<VirtualHost *:443>
ServerName siteweb.example
ServerAdmin www@exemple
GnuTLSEnable on
GnuTLSCertificateFile /chemin/vers/certification/x509.crt
GnuTLSKeyFile /chemin/vers/cle/privee.key
GnuTLSPriorities NORMAL
GnuTLSProxyEngine on
GnuTLSProxyPriorities NORMAL
GnuTLSProxyCAFile /etc/ssl/certs/ca-certificates.crt
ProxyPass "/" "https://backend-siteweb.example/"
ProxyPassReverse "/" "https://backend-siteweb.example/"
ErrorLog /var/log/apache2/siteweb.example/error.log
CustomLog /var/log/apache2/siteweb.example/access.log combined
</VirtualHost>
Sur un système GNU/Linux Debian 8, la prise en charge des suites cryptographiques qui utilisent 3DES comme algorithme de chiffrement symétrique n'est pas désactivée dans OpenSSL. On peut donc utiliser mod_ssl de la manière la plus basique qui soit :
<VirtualHost *:443>
ServerName siteweb.example
ServerAdmin www@exemple
SSLEngine on
SSLCertificateFile /chemin/vers/certification/x509.crt
SSLCertificateKeyFile /chemin/vers/cle/privee.key
SSLProxyEngine on
ProxyPass "/" "https://backend-siteweb.example/"
ProxyPassReverse "/" "https://backend-siteweb.example/"
ErrorLog /var/log/apache2/siteweb.example/error.log
CustomLog /var/log/apache2/siteweb.example/access.log combined
</VirtualHost>
Au final, nous avons retenu cette solution. Raisons : mod_gnutls est plus capricieux que mod_ssl, il a des comportements inattendus (ne pas interrompre mod_proxy_http quand la connexion TLS n'a pas pu être établie), il est moins documenté et nous avons l'habitude de mod_ssl.