HAProxy for converting HTTP to HTTPS request with server requiring SNI

Hi Team,

I have a client which can only send HTTP requests. However, the server will accept only messages from clients which can support TLS 1.2 with SNI. Without SNI, the server handshake fails.

We are trying to implement HAProxy , but no luck so far.

One question I want to check is whether HAProxy supports this kind of architecture?

Client(HTTP)—>HAProxy(Convert into HTTPS with SSL certificates and add SNI)–> Server

Any help would be very useful.

Regards,
Satya

Absolutely, it would look like this for example:

backend blabla
 server server1 192.168.1.10:443 ssl sni req.hdr(host)
 server server2 192.168.1.11:443 ssl sni req.hdr(host)

If you also want health checks with a TLS handshake (not only a connect on port 443), then you need haproxy 1.8 and the check-sni setting.

Hi,

Looks like the SNI keyword is not applicable for the version I am using.

error: unknown keyword ‘sni’

HA-Proxy version 1.5.18 2016/05/10
Build options :
TARGET = linux2628
CPU = generic
CC = gcc
CFLAGS = -O2 -g -fno-strict-aliasing
OPTIONS = USE_LINUX_TPROXY=1 USE_ZLIB=1 USE_REGPARM=1 USE_OPENSSL=1 USE_PCRE=1

Default settings :
maxconn = 2000, bufsize = 16384, maxrewrite = 8192, maxpollevents = 200

Encrypted password support via crypt(3): yes
Built with zlib version : 1.2.3
Compression algorithms supported : identity, deflate, gzip
Built with OpenSSL version : OpenSSL 1.0.1e-fips 11 Feb 2013
Running on OpenSSL version : OpenSSL 1.0.1e-fips 11 Feb 2013
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports prefer-server-ciphers : yes
Built with PCRE version : 7.8 2008-09-05
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND

Available polling systems :
epoll : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result OK
Total: 3 (3 usable), will use epoll.

here is the haproxy.config file details :
global
ssl-default-bind-options no-sslv3
ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA

defaults
mode http
log global
option httplog
option dontlognull
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000

frontend http_front

	bind localhost:443 ssl crt /etc/haproxy/certs/cert.pem
	reqadd X-Forwarded-Proto:\ https
	default_backend http_back

backend http_back
server server1 192.168.1.1:443 ca-file /etc/ssl/certs/root.pem ssl sni (server1)

Correct, the SNI keyword requires haproxy 1.6. It’s a fetch, so a static value would look like this:

sni str(server1)

Hi Lukas,

I am running HAProxy on Linux machine. Could you please help me the documentation for upgrading from 1.5 version?

Thanks!!

Regards,
Satya

I’m not sure I can help you. Exactly what Distribution and which release are you using?

Here is the version details

LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
Distributor ID: OracleServer
Description: Oracle Linux Server release 6.8
Release: 6.8
Codename: n/a

No, I don’t know that one.

Hi,

We have uninstalled 1.5 and installed 1.7 in the Linux machine.

I am trying to use the ssl sni option to connect to the server which requires SNI for incoming traffic. Still I am facing error. Here is the logic I have put in place

frontend localhost80
bind *:80
mode http
redirect scheme https code 301 if !{ ssl_fc }

frontend localhost443
bind *:443
option tcplog
mode tcp
tcp-request inspect-delay 5s
default_backend outbound

backend outbound
mode tcp
option ssl-hello-chk
server server1 10.192.1.1:443 ssl sni req.hdr(server1)

Please let me know if I am doing it correct

No, you either specify a static string like I suggested: ssl sni str(server1)
Or you use the host header: ssl sni req.hdr(host)

However you seem to set the SNI value to the content of the http header “server1”, which very likely does not exist and you just confused strings with http headers.

1 Like

Now getting a different error.

curl: (51) SSL: certificate subject name ‘*.sdppcf.com’ does not match target host name ‘test.dc.com

curl to the server1 directly is working fine without passing any certs.

Is there a way to pass the cacert in the backend?

This all depends on your configuration and your backend. Did you use req.hdr(host)?

Nope, we have used sni str(server1).

   server test.sdppcf.com 10.192.1.1:443 sni str(test.sdppcf.com)

Ok. Then please use req.hdr(host) instead.

Apologies. I didn’t get you. req.hdr(host) would fetch the host name from the HTTP header isnt it.

As I have informed earlier - below would be the flow.

Client(HTTP)—>HAProxy(Convert into HTTPS with SSL certificates and add SNI)–> Server(sdppcf.com)

As client system doesn’t support SNI, the onus is on the HAProxy code to add the SNI before it makes a call to the server.

Can I add the “http-request set-header Host test.sdppcf.com” in the frontend and use it?

Summary of the frontend and backend:

frontend localhost80
bind *:80
mode http
redirect scheme https code 301 if !{ ssl_fc }

frontend localhost443
bind *:443
http-request set-header Host test.sdppcf.com
option tcplog
mode tcp
tcp-request inspect-delay 5s
default_backend outbound

backend outbound
mode tcp
option ssl-hello-chk
server server1 10.192.1.1:443 ssl sni req.hdr(Host) check -CAfile /etc/haproxy/certs/server1.pem

What is the SNI value that your backend requires to serve the correct certificate?

SNI value that the server is looking for is test.sdppcf.com

Then sni str(test.sdppcf.com) is correct and that is the certificate that is delivered. Double check your curl command you used and which failed for you.

still facing issues
curl output:
[root@localhost haproxy]# curl -X GET https://localhost/health
curl: (51) SSL: certificate subject name ‘*.sdppcf.com’ does not match target host name ‘localhost’

browser ouput:
404 Not Found: Requested route (‘localhost’) does not exist.
when pressed F12 to see certificate details in the browser ,it gives this error ERR_CERT_COMMON_NAME_INVALID