Search code examples
sslhaproxysni

How to pass the custom SNI with haproxy in TCP mode


I have a public ssl endpoint something.example.com, which requires SNI extension to be used. I cant access it directly, so I want to pass it through haproxy (which is set up in the server with internet access)

This is not working: openssl s_client -connect something.example.com:443

This is working fine: openssl s_client -connect something.example.com:443 -servername something.example.com

My haproxy config (version 1.8.24):

frontend my_frontend
    bind *:443
    mode tcp
    log global
    option tcplog
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }
    use_backend my_backend

backend my_backend
    mode         tcp
    server       my-server something.example.com:443 sni str(something.example.com)

When Im logged in the haproxy server, I can do:

curl -v https://something.example.com/ and can see the SSL connection is established

but when doing curl -v https://127.0.0.1/ Im facing:

curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:443

What is wrong? I already tried to terminate ssl, replace the host header but with no luck. My understanding is that SNI itself is separated from ciphered request and with above configuration I should be able to connect to backend.

PS. Backend server is not managed by me.


EDIT: as stated in the comments, it is impossible to pass custom SNI in TCP mode configuration. Following can be done for http mode, with TLS termination, below is working fine:

frontend log_frontend
    bind *:443 ssl crt /etc/pki/tls/private/mycert.pem
    mode http
    log global
    option httplog
    option forwardfor
    use_backend log_backend

backend log_backend
    mode         http
    server       my-server something.example.com:443 ssl verify none sni str(something.example.com)

Solution

  • My understanding is that SNI itself is separated from ciphered request ...

    SNI is part of the SSL/TLS handshake, specifically the ClientHello sent at the beginning of the handshake by the client. It is impossible to replace any part of the TLS handshake, including SNI. Instead TLS need to be terminated (which means proper certificates etc are needed) and then a new TLS session has to be created with the expected SNI set.