HAProxy mit SNI und verschiedenen SSL-Einstellungen


9

Ich habe HAProxy für meine beiden Websites, eine davon öffentlich und eine privat.

www.mysite.com private.mysite.com

Atm, ich benutze Haproxy wie folgt:

frontend mysite_https
  bind *.443 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3
  mode http
  acl domain_www     hdr_beg(host) -i www.
  acl domain_private hdr_beg(host) -i private.
  acl path_ghost     path_beg         /ghost/
  acl clientcert     ssl_c_used

  redirect location https://www.example.com if path_ghost !clientcert
  redirect location https://www.example.com if !domain_www !clientcert

  use_backend bknd_private if domain_private
  use_backend bknd_www     if domain_www

  default_backend bknd_www

Fordern Sie dazu (optional) ein Client-Zertifikat an und fahren Sie fort. Wenn die Domain nicht www.example.com ist und der Besucher nicht das richtige Zertifikat bereitstellen kann oder der Pfad / ghost / ist und der Besucher nicht das richtige Zertifikat bereitstellen kann, sollte er zu https://www.example.com umgeleitet werden

Bisher funktioniert das gut. Ich habe jedoch Beschwerden von Mac-Benutzern erhalten, die meine Website mit Safari durchsuchen, dass sie beim Surfen auf https://www.example.com/ immer wieder nach dem Zertifikat gefragt werden, während Firefox beispielsweise nur beim Durchsuchen von https: //private.example fragt .com / oder https://www.example.com/ghost/ .

Anscheinend funktioniert Safari so, also kann ich das nicht beheben. Meine Idee war, SNI zu verwenden, um zwischen verschiedenen Frontends zu teilen

frontend mysite_https
  bind *.443 ssl crt /etc/mycert.pem no-sslv3

frontend private_https
  bind *.443 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3

Das funktioniert natürlich nicht, weil

ein. Ich kann nicht zwei Frontends haben, die Port 443 mit nur einer öffentlichen IP abhören. B. Ich habe noch keine Möglichkeit gefunden, "use_frontend if domain_www" oder ähnliches zu sagen. (Nur use_backend oder use-server)

Ich habe es auch mit drei Haproxy-Servern versucht

frontend haproxy-sni
bind *:443 ssl crt /etc/mycert.pem no-sslv3
mode tcp

tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }

acl domain_www ssl_fc_sni_end -i www.example.com

use-server server1 haproxy-private.lan  if !domain_www
use-server server2 haproxy-public.lan   if domain_www

Dies funktioniert, das Problem hierbei ist jedoch, dass haproxy-private nach dem Client-Zertifikat fragt, die Anforderung jedoch den Browser nicht erreicht. Irgendwie lässt Haproxy-Sni die Anfrage fallen.

Außerdem habe ich jetzt drei Haproxy-Server, was nicht wünschenswert ist (obwohl eine mögliche Option, wenn ich keine bessere Lösung finde).

Am liebsten hätte ich so etwas (erfunden .. kenne die wirklichen Möglichkeiten nicht)

frontend mysite_https
  bind *.443 ssl crt /etc/mycert.pem no-sslv3
  mode http

  acl domain_www     hdr_beg(host) -i www.
  acl domain_private hdr_beg(host) -i private.
  acl path_ghost     path_beg         /ghost/

  ssl_options ca-file /etc/myca.pem verify optional if !www_domain          # made up!
  ssl_options ca-file /etc/myca.pem verify optional if !path_ghost          # made up!

  acl clientcert     ssl_c_used

  redirect location https://www.example.com if path_ghost !clientcert
  redirect location https://www.example.com if !domain_www !clientcert
  ...

Ich hoffe jemand kann mir dabei helfen ...

Antworten:


13

Ich habe eine Lösung für dieses Problem gefunden, für die keine zusätzlichen Server oder Dienste erforderlich sind. Ich bin mir nicht ganz sicher, ob dies nicht zu neuen Problemen führt. Für mich scheint es gerade zu funktionieren.

So habe ich es gemacht, ein Frontend für jede Domain zu erstellen, für die unterschiedliche SSL-Einstellungen erforderlich waren. Ich habe dann die Bindungsoption dieser Frontends auf hohe Ports gesetzt (diese sind von der Öffentlichkeit nicht erreichbar!).

Ich habe ein weiteres Frontend erstellt, das den Port überwacht: 443, um den Datenverkehr basierend auf SNI zu teilen, und die Backend-Server auf 127.0.0.1:high-port gesetzt.

Auf diese Weise habe ich eine Art Schleife in Haproxy erstellt

[incoming]->[haproxy:443]->[haproxy:7000]->[www.intern.lan]
[incoming]->[haproxy:443]->[haproxy:8000]->[private.intern.lan]

Hier ist der Konfigurationsteil.

frontend frnd_snipt                                             # Frontend_SNI-PassThrough (snipt)
  bind *:443                                                    # Do not use bind *:8443 ssl crt etc....!
  option tcplog
  mode tcp 

  tcp-request inspect-delay 5s
  tcp-request content accept if { req_ssl_hello_type 1 } 

  acl subdomain_is_www   req_ssl_sni -i www.example.com
  acl subdomain_is_www   req_ssl_sni -i example.com
  acl subdomain_is_private req_ssl_sni -i private.example.com

  use_backend bknd_snipt_private if subdomain_is_private
  use_backend bknd_snipt_www  if subdomain_is_www

backend bknd_snipt_www
  mode tcp                                              # tcp mode must match the frontend mode - already set as default in [global]
  server snipt-www 127.0.0.1:7000                       # run without "check", otherwise haproxy checks itself all the time!

backend bknd_snipt_private
  mode tcp     
  server snipt-private 127.0.0.1:8000                   # also, don't add "ssl" when in tcp mode. "ssl" is an http mode option (result in "NO-SRV" when set in tcp)

##### NORMAL HAPROXY PART #####
frontend www_example_com                                # this frontend can be in tcp or http mode...
  bind *:7000 ssl crt /etc/mycert.pem no-sslv3          # www. frontend with normal https
  mode http
  option httplog


frontend private_example_com
  bind *:8000 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3        # private. frontend with client certificate request.
  mode http
  option httplog
  ... # whatever you have in your frontend

Wenn jemand Gedanken dazu hat oder eine Idee hat, warum dies eine schlechte Idee sein könnte, lass es mich wissen. Es funktioniert, aber ich frage mich, warum use_frontend keine Option ist. Vielleicht, weil es etwas ist, das aus irgendeinem Grund nicht getan werden sollte.


Gute Idee. Ich konnte auch keine Dokumentation zu diesem Setup finden. Ist die Leistung dieser HAProxy-Schleife ähnlich?
JB. Mit Monica.

Sry, ich weiß nicht, wie performant es ist, weil A: es nicht lange verwendet hat (wegen der Quell-IP-Filter), B: keine Site mit hohem Datenverkehr hat, auf der Leistungsoptimierung interessanter wäre ...
Mohrphium

Ich habe nur Apache2 vor Haproxy gestellt, was funktioniert, aber irgendwie dumm ist, weil Single-Point-of-Failure vor Hapoxy-Cluster und (ich denke) Leistungsengpass (ich denke, Hap ist schneller als Ap2, keine wirklichen Daten haben das aber.)
Mohrphium

3

Neuere Versionen von Haproxy unterstützen eine Einstellung namens crt-list, mit der Sie verschiedene TLS-Einstellungen basierend auf dem übereinstimmenden Zertifikat angeben können

Sie können es so verwenden:

haproxy.conf:

frontend https
    mode http
    bind *:443 ssl crt-list /etc/haproxy/crt-list.conf ca-file ca.pem

    use_backend test if { ssl_fc_sni -i test.area.example.org }
    use_backend private if { ssl_fc_sni -i private.example.org }
    default_backend www

crt-list.conf:

www.pem [verify none]
www.pem [verify required] *.area.example.org
private.pem [verify required]

Weitere Informationen: https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#5.1-crt-list

Hinweis zur Sicherheit: Vergleichen Sie Ihre (sensiblen) Hostnamen immer mit SNI ssl_fc_sni, nicht mit dem HTTP-Hostnamen. Andernfalls könnte ein Angreifer möglicherweise Ihre Client-Zertifizierungsauthentifizierung umgehen, indem er die TLS-SNI von sendet, www.example.orgaber den HTTP-Hostnamen auf setzt private.example.org!


OP verwendet für beide das gleiche Zertifikat. Die Frage betraf eher unterschiedliche ca-fileEinstellungen.
gre_gor
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.