haproxy + stunnel + keep-alive?

10

Je voudrais mettre Stunnel devant haproxy 1.4 pour gérer le trafic HTTPS. J'ai également besoin de Stunnel pour ajouter l'en - tête X-Forwarded-For . Ceci peut être réalisé par les "stunnel-4.xx-xforwarded-for.diff" patches à partir du site haproxy.

Cependant, la description mentionne:

Notez que ce patch ne fonctionne pas avec keep-alive, ...

Ma question est: qu'est-ce que cela signifie concrètement pour moi? Je ne suis pas sûr,

  1. s'il s'agit de la survie entre
    • client et stunnel
    • stunnel et haproxy
    • ou serveur haproxy et backend?
  2. ce que cela signifie pour les performances: si j'ai 100 icônes sur une page Web, le navigateur devra-t-il négocier 100 connexions SSL complètes, ou peut-il réutiliser la connexion SSL, en créant simplement de nouvelles connexions TCP?
Chris Lercher
la source

Réponses:

12

Il s'agit de HTTP keep-alive, qui permet à plusieurs demandes de ressources de passer par une seule session TCP (et, avec SSL, une seule session SSL). Ceci est d'une grande importance pour les performances d'un site SSL, car sans maintien en vie, une poignée de main SSL serait nécessaire pour chaque ressource demandée.

Donc, le problème ici est une grande session de maintien en vie du client jusqu'au serveur principal. C'est une chose importante pour les performances, et considérée comme une évidence pour les serveurs HTTP modernes, mais ce correctif indique qu'il ne le prend pas en charge. Voyons pourquoi ..


Une session persistante est simplement plus de demandes l'une après l'autre - une fois que le serveur a terminé sa réponse à une demande, le serveur n'envoie pas de FINpaquet pour mettre fin à la session TCP; le client peut simplement envoyer un autre lot d'en-têtes.

Pour comprendre ce que fait ce patch, voici un exemple de conversation continue:

Client:

GET / HTTP/1.1
Connection: keep-alive
Host: domain.com
...

Serveur:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Server: Apache
Content-Length: 34
.... (other headers)
<html><head>content!</head></html>

Voici où s'arrêterait une connexion non maintenue. Mais, keep-alive permet au client d'en déclencher un autre:

GET /images/some/image.on.the.page.jpg HTTP/1.1
Connection: keep-alive
Host: domain.com
...

Pour l'ID client dans le proxy, certains proxy inverses peuvent ajouter l'en- X-Forwarded-Fortête dans chaque demande client. Cela indique au serveur en amont d'où provient la demande (au lieu de chaque demande initiée à partir de l'IP du proxy inverse), pour des raisons de cohérence dans la journalisation et d'autres besoins d'application.

L'en- X-Forwarded-Fortête doit être injecté dans chaque demande de ressource client envoyée via la connexion permanente, car les en-têtes complets sont envoyés à chaque fois; le traitement de l'en- X-Forwarded-Fortête et sa traduction en tant qu'IP de demande "réelle" est effectué sur une base par demande et non par session TCP-keep-alive. Et bon, il existe peut-être un logiciel de proxy inverse génial qui utilise une seule session permanente pour répondre aux demandes de plusieurs clients.

C'est là que ce patch échoue.


Le correctif de ce site surveille le tampon de la session TCP pour la fin du premier ensemble d'en-têtes HTTP dans le flux et injecte le nouvel en-tête dans le flux après la fin de ce premier ensemble d'en-têtes. Une fois cette opération effectuée, il considère que le X-Forwarded-Fortravail est terminé et arrête de rechercher la fin de nouveaux ensembles d'en-têtes. Cette méthode n'a pas connaissance de tous les futurs en-têtes entrant via des demandes ultérieures.

Je ne peux pas vraiment leur en vouloir; stunnel n'était pas vraiment conçu pour gérer et traduire le contenu de ses flux.

L'effet que cela aurait sur votre système est que la première demande d'un flux de maintien en vie X-Forwarded-Forinjectera correctement l'en- tête, et toutes les demandes suivantes fonctionneront très bien - mais elles n'auront pas l'en-tête.

À moins qu'il n'y ait un autre patch d'injection d'en-tête qui puisse gérer plusieurs demandes client par connexion (ou que celui-ci soit modifié avec l'aide de nos amis sur Stack Overflow), vous devrez peut-être examiner d'autres options pour votre terminaison SSL.

Shane Madden
la source
1
Excellente réponse, merci. Cela me rappelle pourquoi c'est une bonne idée de poser des questions ici.
Chris Lercher
1
Pour permettre une injection d'en-tête persistante dans Stunnel, il devrait être capable de parler presque tout HTTP, ce qui représenterait une énorme quantité de travail. Cela dit, vous pouvez également utiliser le protocole PROXY de HAproxy (qui nécessite un patch pour stunnel ou alternativement stud ) et injecter l'en-tête dans HAproxy. Voir les documents pour plus d'informations (à partir du cache Google, car le site HAproxy semble être partiellement en panne ATM)
Holger Just
3

Semblable à ce que j'ai publié dans un autre fil, HAProxy prend en charge le SSL natif des deux côtés depuis 1.5-dev12. Ainsi, avoir X-Forwarded-For, HTTP keep-alive ainsi qu'un en-tête indiquant au serveur que la connexion a été établie via SSL est aussi simple que ce qui suit:

listen front
    bind :80
    bind :443 ssl crt /etc/haproxy/haproxy.pem
    mode http
    option http-server-close
    option forwardfor
    reqadd X-Forwarded-Proto:\ https if { is_ssl }
    server srv1 1.1.1.1:80 check ...
    ...

C'est beaucoup plus facile que de rapatrier Stunnel et bien mieux que de devoir laisser tomber Keep-Alive.

Willy Tarreau
la source
Vous voudrez peut-être utiliser ssl_fc au lieu de is_ssl
josch
2

En étendant l'excellente réponse de Shane, vous pouvez utiliser Nginx comme terminateur SSL devant HAproxy. Il gère correctement la conservation entre le client et nginx qui est le côté le plus sensible à la latence et établit une nouvelle connexion au backend pour chaque demande client, en envoyant le X-FORWARDED-FOR dans chacun d'eux.

Ochoto
la source
1
Cependant, si vous avez besoin de websockets, nginx ne fonctionnera pas.
w00t
De plus, il prend en charge le cache de session SSL.
3molo