Https frontend -> http backend : SSL handshake failure

Hi all,

I’m trying to setup HaProxy as a load balancer for squid proxies and it’s working fine with http, but I can’t make it work with https.
I’m trying to setup something like this:

Client :       Uses "https://proxy.mydomain.com:8081" as navigation proxy
    |
 (https)
    |
    V
HaProxy :      Frontend is configured to receive https request on port 8081
               Backend configured forward to squid proxy sever via http on port 8080
    |
  (http)
    |
    V
Squid Proxy :  Receives http requests on port 8080

My HaProxy configuration is like this:

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000

http-errors myerrors
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

frontend https_in
    mode http
    bind *:8081 ssl crt /etc/haproxy/certs/certificat.pem no-sslv3
    option httplog
    option logasap
    default_backend https_proxies

backend https_proxies
    log global
    mode http
    cookie SERVERID insert indirect nocache
    balance source
    option httpclose
    option forwardfor header X-Client
    option forwardfor
    server proxy1 squidserver1:8080 check
    server proxy2 squidserver2:8080 check
    server proxy3 squidserver3:8080 check

My certificate (and chained certificate) is correct if I try openssl s_client -connect proxy.mydomain.com:8081 :

...
SSL handshake has read 3388 bytes and written 388 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---

In the logs i’m getting errors:
May 14 12:05:05 haproxysrv haproxy[2507533]: 10.49.199.197:64773 [14/May/2024:12:05:05.909] https_in/1: SSL handshake failure

I configured the same with http only and it’s working fine:

frontend http_in
    mode http
    bind *:8080
    option httplog
    option logasap
    default_backend http_proxies

backend http_proxies
    log global
    mode http
    cookie SERVERID insert indirect nocache
    balance source
    option httpclose
    option forwardfor header X-Client
    option forwardfor
    server proxy1 squidserver1:8080 check
    server proxy2 squidserver2:8080 check
    server proxy3 squidserver3:8080 check

Anyone have an idea on what I’m doing wrong?

Best regards,

Fabien

have you checked the ssl config of haproxy?
have a look at Mozilla SSL Configuration Generator

i think your ssl config is missing some things. eg

 bind    :443 ssl crt /path/to/<cert+privkey+intermediate> alpn h2,http/1.1

Hi Mrit,

Thank you for your reply. I did try using the MOZ configuration but i’m still getting SSL Handshake error.

global
...
###MOZ CONFIG
    # intermediate configuration
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

    ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
    ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

    # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
    ssl-dh-param-file /tmp/dhparam
### END MOZ CONFIG
...
frontend https_in
    mode http
    bind *:8081 ssl crt /etc/haproxy/certs/certificat.pem alpn h2,http/1.1
    option httplog
    option logasap
    #MOZ CONFIG
    redirect scheme https code 301 if !{ ssl_fc }
    http-response set-header Strict-Transport-Security max-age=63072000
    default_backend https_proxies

BR

OK I found a solution for the SSL Handshake, it seems to be mainly a client configuration issue… But i’m not satified with the solution.
Indeed, I had to separate HTTP and HTTPS trafic:
HTTP Request → HTTP Proxy
HTTPs Request → HTTPs Proxy

I had to change my PROXY.PAC file to use HTTPS proxy redirection:

function FindProxyForURL(url, host)
{
// variable strings to return
var proxy_http = "PROXY proxy.mydomain.com:8080";
var proxy_https = "HTTPS proxy.mydomain.com:8081"
var proxy_no = "DIRECT";

// REGLES //
// Somes rules for urls that don't need PROXY

// Redirtect to HTTPS Proxy if proto is HTTPS
if (url.startsWith("https:") || url.startsWith("snews:")) {
    return proxy_https;
}

//Redirect to HTTP Proxy if proto is HTTP
return proxy_http;
}

I also had to tweak my Front End:

frontend https_in
    mode http
    bind *:8080
    bind *:8081 ssl crt /etc/haproxy/certs/certificat.pem alpn h2,http/1.1
    option httplog
    option logasap
    default_backend http_proxies

backend http_proxies
    log global
    mode http
    cookie SERVERID insert indirect nocache
    balance source
    option httpclose
    option forwardfor header X-Client
    option forwardfor
    server proxy1 squidserver1:8080 check
    server proxy2 squidserver2:8080 check
    server proxy3 squidserver3:8080 check

I had to do so because if I handle HTTP trafic from my PROXY.PAC via an HTTPS Proxy, the connexion fails due to headers not handled by Squid.

Any idea if I can force HTTP request to pass through HTTPS connexion between client and HA Proxy?

I want this scenario to be true for HTTP or HTTPS requests:

Client :       Uses "https://proxy.mydomain.com:8081" as navigation proxy
    |
 (https)
    |
    V
HaProxy :      Frontend is configured to receive https request on port 8081
               Backend configured forward to squid proxy sever via http on port 8080
    |
  (http)
    |
    V
Squid Proxy :  Receives http requests on port 8080