[Solved] SSL Passthough mit HAProxy Plugin

Started by getle87, February 25, 2019, 01:35:45 PM

Previous topic - Next topic
February 25, 2019, 01:35:45 PM Last Edit: March 11, 2019, 09:36:41 AM by getle87
Hallo,

ich versuche seit einiger Zeit ein HAProxy mit SSL Passthrough auf meiner OPNsense einzurichten, da ich von IPFire gewechselt bin und die WebGUI bzw. meinen Web Server hinter der FW weiterhin von außen erreichen möchte. Bei IPFire funktionierte dies ohne Probleme. Mit dem HAProxy Plugin unter OPNsense bekomme ich es allerdings nicht zum Laufen. Es soll wie folgt aussehen:



Wenn ich ein NAT Forwarding zu dem Web Server einrichte und den HAProxy auf diesem betreibe funktioniert es.



Configs würde ich noch posten falls gewünscht. Mir gehts hier erst einmal um die Frage ob der HAProxy unter FreeBSD dies überhaupt beherrscht. Leider hab ich bis jetzt keine richtigen Antworten im Netz gefunden, die meisten Anfragen sind entweder mit SSL Offloading oder nicht beantwortet.

Die DNS Namen hier verwende ich im Testsetup, diese sind natürlich nur Platzhalter

Sollte gehen, hab das aber noch nie gemacht. Du musst den HAProxy in den TCP mode schalten - dann solltest du das gleiche Ergebnis bekommen wie mit nginx streams. Ohne PROXY-Protokoll ist das imho aber suboptimal, weil du wichtige logging infos verlierst.

Hallo fabian,

das mit dem TCP Mode hatte ich auch so eingestellt. Der Proxy leitet ja in diesem Modus alles verschlüsselt weiter ohne die Verbindung "aufzubrechen", lediglich der SNI Wert im Klartext wird für das "Routing" ausgewertet, soweit ich das verstanden habe. Ich selber bin leider kein Proxy oder nginx Experte.

Ich habe hier die Configs von meinen beiden Modellen mal angehangen. Zum Verständnis des Testaufbaus (Netze und Addressen) folgende Abbildung:





Linux als HA Proxy mit Portforwarding über die 192.168.22.2 auf Port 443, siehe Abb. 2 erster Post (funktionsfähig):


global
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
timeout client 30s
timeout server 30s
timeout connect 5s
maxconn 3000

frontend https
bind *:444
mode tcp
tcp-request inspect-delay 5s
acl exchange req.ssl_sni -i ha-test.local
acl config req.ssl_sni -i cnf-test.local
tcp-request content accept if exchange
tcp-request content accept if config
tcp-request content reject
use_backend exc if exchange
use_backend cnf if config

backend exc
    mode tcp
    no option checkcache
    no option httpclose
    server server1 localhost:443

backend cnf
    mode tcp
    no option checkcache
    no option httpclose
    server server1 192.168.82.250:8443 check


OPNsense als HA Proxy auf 192.168.22.2 Port 443, siehe Abb. 1 erster Post (nicht funktionsfähig bis jetzt):

#
# Automatically generated configuration.
# Do not edit this file manually.
#

global
    # NOTE: Could be a security issue, but required for some feature.
    uid                         80
    gid                         80
    chroot                      /var/haproxy
    daemon
    stats                       socket /var/run/haproxy.socket level admin
    nbproc                      1
    nbthread                    1
    tune.ssl.default-dh-param   1024
    spread-checks               0
    tune.chksize                16384
    tune.bufsize                16384
    tune.lua.maxmem             0
    log /var/run/log len 65535 local0

defaults
    log     global
    option redispatch -1
    timeout client 30s
    timeout connect 30s
    timeout server 30s
    retries 3

# autogenerated entries for ACLs

# autogenerated entries for config in backends/frontends

# autogenerated entries for stats


# Frontend: WebGUIClientCertCheckProxy ()
frontend WebGUIClientCertCheckProxy
    bind 192.168.82.250:8443 name 192.168.82.250:8443 ssl ca-file /tmp/haproxy/ssl/5c6e94492253d2.87190125.calist verify required crt-list /tmp/haproxy/ssl/5c6e94492253d2.87190125.certlist
    mode http
    option http-keep-alive
    default_backend WebGUIBackend
    # tuning options
    timeout client 30s

    # logging options
    option log-separate-errors
    option httplog
    # WARNING: pass through options below this line
    option tcplog

# Frontend: HTTPSProxy ()
frontend HTTPSProxy
    bind 192.168.22.2:443 name 192.168.22.2:443
    mode tcp
    # tuning options
    timeout client 30s

    # logging options
    option tcplog
    # ACL: WebGUI-SNI-Rule
    acl acl_5c75143c261ba1.96471201 req.ssl_sni -i cnf-test.local
    # ACL: Webserver-SNI-Rule
    acl acl_5c6e9491ad86b4.89663855 req.ssl_sni -i web-test.local

    # ACTION: WebGUI-ACL
    use_backend WebGUIClientCertCheckBackend if acl_5c75143c261ba1.96471201
    # ACTION: Webserver-ACL
    use_backend WebserverBackend if acl_5c6e9491ad86b4.89663855

# Backend: WebGUIBackend ()
backend WebGUIBackend
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    http-reuse never
    server WebGUI 127.0.0.1:443 ssl verify none

# Backend: WebGUIClientCertCheckBackend ()
backend WebGUIClientCertCheckBackend
    # health checking is DISABLED
    mode tcp
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    server WebGUI 127.0.0.1:443 ssl verify none

# Backend: WebserverBackend ()
backend WebserverBackend
    # health checking is DISABLED
    mode tcp
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 30s
    timeout server 30s
    server Webserver 192.168.82.4:443 ssl verify none



Wenn ich den HAProxy starte und mich per Browser (Firefox und EDGE getestet), kommt sofort ein Verbindungsfehler. In der Log des HAProxys auf der OPNsense erscheint folgendes (IP des phys. Host "geschwärzt"), eine Verbindung ist also da, aber irgendwie wertet der Proxy den SNI nicht korrekt aus:

Feb 26 11:23:37 haproxy[40924]: <IP phys. Host>:58490 [26/Feb/2019:11:23:37.159] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36 haproxy[40924]: <IP phys. Host>:58487 [26/Feb/2019:11:23:36.989] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36 haproxy[40924]: <IP phys. Host>:58485 [26/Feb/2019:11:23:36.842] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36 haproxy[40924]: <IP phys. Host>:58482 [26/Feb/2019:11:23:36.628] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36 haproxy[40924]: <IP phys. Host>:58480 [26/Feb/2019:11:23:36.457] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36 haproxy[40924]: <IP phys. Host>:58478 [26/Feb/2019:11:23:36.203] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:35 haproxy[40924]: <IP phys. Host>:58475 [26/Feb/2019:11:23:35.825] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0


Hält man auf der Fehlermeldungsseite im Browser (Firefox) die F5 Taste gedrückt, erscheint im Log manchmal folgendes, was die Theorie mit der fehlerhaften Auswertung aufkommmen lässt:

Feb 26 11:29:26 haproxy[40924]: <IP phys. Host>:58687 [26/Feb/2019:11:29:26.691] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:29:26 haproxy[40924]: <IP phys. Host>:58685 [26/Feb/2019:11:29:26.662] HTTPSProxy WebGUIClientCertCheckBackend/WebGUI 1/16/17 0 -- 1/1/0/0/0 0/0
Feb 26 11:29:26 haproxy[40924]: <IP phys. Host>:58683 [26/Feb/2019:11:29:26.563] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0


Wo ist in der zweiten Config der Fehler?

February 26, 2019, 08:46:36 PM #3 Last Edit: February 26, 2019, 08:49:46 PM by fabian
Quote from: getle87 on February 26, 2019, 12:37:10 PM
Hallo fabian,

das mit dem TCP Mode hatte ich auch so eingestellt. Der Proxy leitet ja in diesem Modus alles verschlüsselt weiter ohne die Verbindung "aufzubrechen", lediglich der SNI Wert im Klartext wird für das "Routing" ausgewertet, soweit ich das verstanden habe. Ich selber bin leider kein Proxy oder nginx Experte.

Genau, wenn ich das richtig verstanden habe ist das genau das, was du wolltest.

Quote from: getle87 on February 26, 2019, 12:37:10 PM
Wenn ich den HAProxy starte und mich per Browser (Firefox und EDGE getestet), kommt sofort ein Verbindungsfehler. In der Log des HAProxys auf der OPNsense erscheint folgendes (IP des phys. Host "geschwärzt"), eine Verbindung ist also da, aber irgendwie wertet der Proxy den SNI nicht korrekt aus:

Feb 26 11:23:37    haproxy[40924]: <IP phys. Host>:58490 [26/Feb/2019:11:23:37.159] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36    haproxy[40924]: <IP phys. Host>:58487 [26/Feb/2019:11:23:36.989] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36    haproxy[40924]: <IP phys. Host>:58485 [26/Feb/2019:11:23:36.842] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36    haproxy[40924]: <IP phys. Host>:58482 [26/Feb/2019:11:23:36.628] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36    haproxy[40924]: <IP phys. Host>:58480 [26/Feb/2019:11:23:36.457] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:36    haproxy[40924]: <IP phys. Host>:58478 [26/Feb/2019:11:23:36.203] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0
Feb 26 11:23:35    haproxy[40924]: <IP phys. Host>:58475 [26/Feb/2019:11:23:35.825] HTTPSProxy HTTPSProxy/<NOSRV> -1/-1/0 0 SC 1/1/0/0/0 0/0


Wo ist in der zweiten Config der Fehler?

Ich würde da mal im Wireshark sniffen, was im Client Hello steht. um das Rätsel zu lösen. Ist auch irgendwie komisch, dass da HTTPSProxy steht. Aber ich bin kein HAProxy experte. Im nginx plugin würdest du einfach unter streams ein SNI-Mapping anlegen und das mit einem stream server verknüpfen. Das HAProxy-Plugin bietet diese Funktionalität schon länger.

Hallo fabian,

nach weiteren Tests und stückweisen Abgleich mit der Linux Config, hab ich es endgültig hinbekommen. Die Absicherung der WebGUI nach außen mit einem Client Zertifikat funktioniert jetzt endlich, als auch die interne Weiterleitung zum Webserver. Danach hab ich es noch mit einer OpenVPN Weiterleitung von 443 auf 1194 intern ausprobiert, dies funktioniert auch ohne Probleme.
Der Knackpunkt waren die 3 TCP Optionen im Frontend, die beiden ersten müssen als Regel angelegt werden, die letzte muss als Optionsweiterleitung (erweit. Modus) beim Frontend eingetragen werden.


tcp-request content accept if acl_5c75143c261ba1.96471201
tcp-request content accept if acl_5c6e9491ad86b4.89663855
tcp-request inspect-delay 5s


Danach war die Einrichtung ein Kinderspiel. Trotzdem vielen Dank für Deine Hilfe :)

Die Config sieht jetzt wie folgt aus (wenn noch jemand Fehler oder "Bad Practices" findet, dann diese hier posten):

#
# Automatically generated configuration.
# Do not edit this file manually.
#

global
    # NOTE: Could be a security issue, but required for some feature.
    uid                         80
    gid                         80
    chroot                      /var/haproxy
    daemon
    stats                       socket /var/run/haproxy.socket level admin
    nbproc                      1
    nbthread                    1
    maxconn                     4000
    tune.ssl.default-dh-param   1024
    spread-checks               0
    tune.chksize                16384
    tune.bufsize                16384
    tune.lua.maxmem             0
    log /var/run/log len 65535 local0

defaults
    log     global
    option redispatch -1
    maxconn 3000
    timeout client 30s
    timeout connect 5s
    timeout server 30s
    retries 3

# autogenerated entries for ACLs

# autogenerated entries for config in backends/frontends

# autogenerated entries for stats


# Frontend: WebGUIClientCertCheckProxy ()
frontend WebGUIClientCertCheckProxy
    bind 127.0.0.1:8443 name 127.0.0.1:8443 ssl ca-file /tmp/haproxy/ssl/5c6e94492253d2.87190125.calist verify required crt-list /tmp/haproxy/ssl/5c6e94492253d2.87190125.certlist
    mode http
    option http-keep-alive
    default_backend WebGUI
    # tuning options
    timeout client 30s

    # logging options
    option log-separate-errors
    option httplog

# Frontend: HTTPSProxy ()
frontend HTTPSProxy
    bind 192.168.22.2:443 name 192.168.22.2:443
    mode tcp
    default_backend OpenVPNBackend
    # tuning options
    timeout client 30s

    # logging options
    option tcplog
    # ACL: WebGUI-SNI-Rule
    acl acl_5c75143c261ba1.96471201 req.ssl_sni -i cnf-test.local
    # ACL: Webserver-SNI-Rule
    acl acl_5c6e9491ad86b4.89663855 req.ssl_sni -i web-test.local

    # ACTION: 100-WebGUI-TCP-Accept
    tcp-request content accept if acl_5c75143c261ba1.96471201
    # ACTION: 101-Webserver-TCP-Accept
    tcp-request content accept if acl_5c6e9491ad86b4.89663855

    # ACTION: 201-Webserver-ACL-Backend
    use_backend WebserverBackend if acl_5c6e9491ad86b4.89663855
    # ACTION: 200-WebGUI-ACL-Backend
    use_backend WebGUIClientCertCheckBackend if acl_5c75143c261ba1.96471201
    # WARNING: pass through options below this line
    tcp-request inspect-delay 5s

# Backend: WebGUIClientCertCheckBackend ()
backend WebGUIClientCertCheckBackend
    # health checking is DISABLED
    mode tcp
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 5s
    timeout server 30s
    server WebGUIClientCertCheck 127.0.0.1:8443

# Backend: WebserverBackend ()
backend WebserverBackend
    # health checking is DISABLED
    mode tcp
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 5s
    timeout server 30s
    server Webserver 192.168.82.4:443

# Backend: WebGUI ()
backend WebGUI
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 5s
    timeout server 30s
    http-reuse never
    server WebGUI 127.0.0.1:443 ssl verify none

# Backend: OpenVPNBackend ()
backend OpenVPNBackend
    # health checking is DISABLED
    mode tcp
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m 
    stick on src
    # tuning options
    timeout connect 5s
    timeout server 30s
    server OpenVPN 127.0.0.1:1194


top, wenn du ein tutorial machen willst, kannst du das hier dazu schreiben https://github.com/opnsense/docs/blob/master/source/manual/how-tos/haproxy_howtos.rst oder eine eigene Seite anlegen.

Ich verwende Webinoly, um VPS Server (https://webinoly.com/en/) zu erstellen, und Webinoly kann SSL für die Website auf diesem Hosting konfigurieren. Ich habe die obige Nachricht gelesen, weiß aber immer noch nicht, wie ich das machen soll. Können Sie SSL Passthough mit dem HAProxy Plugin Schritt für Schritt überprüfen und erklären? Vielen Dank! Ich habe Google Translate to German verwendet.

English: I'm using webinoly to make VPS Server (https://webinoly.com/en/) and webinoly can configure SSL for website on this hosting. I read message above but I still don't know how to do this. Could you check and explain step by step SSL Passthough with HAProxy Plugin? Thanks!

Internet: Willy.tel Down: 1Gbit/s, UP: 250Mbit/s Glasfaser  |
Router/Firewall: pfSense+ 23.09  |
Hardware: Netgate 6100


Quote from: huuich on August 16, 2020, 04:55:11 AM
Ich verwende Webinoly, um VPS Server (https://webinoly.com/en/) zu erstellen, und Webinoly kann SSL für die Website auf diesem Hosting konfigurieren. Ich habe die obige Nachricht gelesen, weiß aber immer noch nicht, wie ich das machen soll. Können Sie SSL Passthough mit dem HAProxy Plugin Schritt für Schritt überprüfen und erklären? Vielen Dank! Ich habe Google Translate to German verwendet.

English: I'm using webinoly to make VPS Server (https://webinoly.com/en/) and webinoly can configure SSL for website on this hosting. I read message above but I still don't know how to do this. Could you check and explain step by step SSL Passthough with HAProxy Plugin? Thanks!

Hallo huuich,

Du hattest mich über eBay kontaktiert. Konntest Du Deine Frage durch die bereits geposteten Antworten lösen?