Haproxy + Stunnel + Keep-Alive?

10

Ich möchte stunnel vor haproxy 1.4 stellen, um den HTTPS-Verkehr zu verarbeiten. Ich brauche auch Stunnel, um den X-Forwarded-For- Header hinzuzufügen . Dies kann durch die "stunnel-4.xx-xforwarded-for.diff" erreicht werden Patches von der haproxy Website.

In der Beschreibung wird jedoch Folgendes erwähnt:

Beachten Sie, dass dieser Patch nicht mit Keep-Alive funktioniert, ...

Meine Frage ist: Was bedeutet das in der Praxis für mich? Ich bin mir nicht sicher,

  1. wenn es um das Keep-Alive zwischen geht
    • Client und Stunnel
    • Stunnel und Haproxy
    • oder Haproxy und Backend Server?
  2. Was dies für die Leistung bedeutet: Wenn ich 100 Symbole auf einer Webseite habe, muss der Browser dann 100 vollständige SSL-Verbindungen aushandeln oder kann er die SSL-Verbindung wiederverwenden und nur neue TCP-Verbindungen erstellen?
Chris Lercher
quelle

Antworten:

12

Hierbei handelt es sich um HTTP-Keep-Alive, bei dem mehrere Ressourcenanforderungen über eine einzelne TCP-Sitzung (und mit SSL über eine einzelne SSL-Sitzung) eingehen können. Dies ist für die Leistung einer SSL-Site von großer Bedeutung, da ohne Keep-Alive ein SSL-Handshake für jede angeforderte Ressource erforderlich wäre.

Hier geht es also um eine große Keep-Alive-Sitzung vom Client bis zum Backend-Server. Es ist eine wichtige Sache für die Leistung und für moderne HTTP-Server selbstverständlich, aber dieser Patch sagt, dass er es nicht unterstützt. Schauen wir uns an, warum ..


Eine Keep-Alive-Sitzung besteht nur aus mehreren Anfragen nacheinander. Sobald der Server seine Antwort auf eine Anfrage beendet hat, sendet der Server kein FINPaket, um die TCP-Sitzung zu beenden. Der Client kann einfach einen weiteren Stapel von Headern senden.

Um zu verstehen, was dieser Patch tut, ist hier ein Beispiel für ein Keep-Alive-Gespräch:

Klient:

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

Server:

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

Hier würde eine Nicht-Keep-Alive-Verbindung aufhören. Mit Keep-Alive kann der Client jedoch einfach einen anderen abfeuern:

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

Für die Client-ID beim Proxying können einige Reverse-Proxys im X-Forwarded-ForHeader jeder Client-Anforderung hinzugefügt werden . Dadurch wird dem Upstream-Server mitgeteilt, woher die Anforderung stammt (anstelle jeder Anforderung, die von der IP des Reverse-Proxys initiiert wird), um die Protokollierung und andere Anwendungsanforderungen zu gewährleisten.

Der X-Forwarded-ForHeader muss in jede Client-Ressourcenanforderung eingefügt werden, die über die Keep-Alive-Verbindung gesendet wird, da jedes Mal die vollständigen Header gesendet werden. Die Behandlung des X-Forwarded-ForHeaders und die Übersetzung in die "echte" Anforderungs-IP erfolgt pro Anforderung und nicht pro TCP-Keep-Alive-Sitzung. Und hey, vielleicht gibt es da draußen eine großartige Reverse-Proxy-Software, die eine einzige Keep-Alive-Sitzung verwendet, um Anfragen von mehreren Clients zu bearbeiten.

Hier schlägt dieser Patch fehl.


Der Patch an dieser Site überwacht den Puffer der TCP-Sitzung auf das Ende des ersten Satzes von HTTP-Headern im Stream und fügt den neuen Header nach dem Ende dieses ersten Satzes von Headern in den Stream ein. Danach wird der X-Forwarded-ForJob als erledigt betrachtet und das Scannen nach dem Ende neuer Headersätze beendet. Diese Methode kennt nicht alle zukünftigen Header, die über nachfolgende Anforderungen eingehen.

Kann ihnen nicht wirklich die Schuld geben; stunnel war nicht wirklich dafür gebaut, den Inhalt seiner Streams zu verarbeiten und zu übersetzen.

Dies hätte Auswirkungen auf Ihr System, dass bei der ersten Anforderung eines Keep-Alive-Streams der X-Forwarded-ForHeader ordnungsgemäß injiziert wird und alle nachfolgenden Anforderungen einwandfrei funktionieren - der Header jedoch nicht.

Sofern es keinen anderen Header-Injection-Patch gibt, der mehrere Client-Anforderungen pro Verbindung verarbeiten kann (oder diesen mithilfe unserer Freunde bei Stack Overflow optimieren kann), müssen Sie möglicherweise andere Optionen für Ihre SSL-Beendigung prüfen.

Shane Madden
quelle
1
Hervorragende Antwort, danke. Erinnert mich daran, warum es eine gute Idee ist, hier Fragen zu stellen.
Chris Lercher
1
Um eine Keep-Alive-Header-Injektion in den Stunnel zu ermöglichen, müsste es möglich sein, fast das gesamte HTTP zu sprechen, was eine enorme Menge an Arbeit wäre. Das heißt, Sie auch HAProxy des PROXY - Protokoll (das erfordert einen Patch für stunnel oder alternativ können Stud ) ein inject Header in HAProxy. Weitere Informationen finden Sie in den Dokumenten (aus dem Google-Cache, da die HAproxy-Site teilweise nicht am Geldautomaten verfügbar zu sein scheint)
Holger Nur
3

Ähnlich wie in einem anderen Thread unterstützt HAProxy seit 1.5-dev12 auf beiden Seiten natives SSL. X-Forwarded-For, HTTP Keep-Alive sowie ein Header, der dem Server mitteilt, dass die Verbindung über SSL hergestellt wurde, sind also so einfach wie folgt:

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 ...
    ...

Es ist viel einfacher als das Ausbessern des Stunnels und viel besser, als Keep-Alive fallen zu lassen.

Willy Tarreau
quelle
Vielleicht möchten Sie ssl_fc anstelle von is_ssl
josch
2

Wenn Sie die hervorragende Antwort von Shane erweitern, können Sie Nginx als SSL-Terminator vor HAproxy verwenden. Es behandelt das Keep-Alive zwischen Client und Nginx korrekt. Dies ist die latenzempfindlichste Seite und stellt für jede Clientanforderung eine neue Verbindung zum Backend her, wobei das X-FORWARDED-FOR in jeder gesendet wird.

Ochoto
quelle
1
Wenn Sie jedoch Websockets benötigen, funktioniert nginx nicht.
w00t
Außerdem unterstützt es den SSL-Sitzungscache.
3molo