Can 1.6 do SNI on backend?


#1

I’m trying to connect haproxy to a server that requires SNI.
Documentation mostly discusses SNI on the front-end.

A simple verifyhost fails. And the sni parameter seems to be looking for SNI information from the client-end.

Does HAProxy support SNI on back end in 1.6.5?


#2

Yes, see the sni keyword.


#3

I have read that. But the client is not doing SNI.

I have the following configuration:

custom application -> HTTP -> Front End -> Back End -> HTTPS target using SNI.

I’m looking for the ability to explicitly set an SNI on the back end when the front-end client is doing HTTP. Many of the SNI examples show a -i parameter, but there’s no documentation on that in the SNI documentation itself.


#4

sni str(blabla.com)


#5

Sorry for being dense, but I just cannot figure out how to use the SNI to validate the back end.
Here’s a specific example using an SNI test site:

option    httpchk GET /
server  velox bob.sni.velox.ch:443 ca-file /etc/haproxy/GeoTrustSSLCA.crt check-ssl ssl resolvers dns force-tlsv12 verify required sni str(bob.sni.velox.ch) fall 1 weight 100 observe layer7 check

The above line passes the health check (layer 7).
If I change the above line to include an invalid SNI:
sni str(bob.sni.velox.ch123)

It still reports a successful healthcheck, which would indicate HAProxy is not checking the SNI, though it may be sending it.

If I revert to the original and add verifyhost, I get a failure on layer6 – SSL handshake failure.

server  velox bob.sni.velox.ch:443 ca-file /etc/haproxy/GeoTrustSSLCA.crt check-ssl ssl resolvers dns force-tlsv12 verify required sni str(bob.sni.velox.ch) verifyhost bob.sni.velos.ch fall 1 weight 100 observe layer7 check

What I cannot figure out is how to do the verify on the SNI name itself.
–Ray


#6

SNI is just a TLS extension header in the client hello, that helps the server to decide which certificate to serve. It has no significance regarding certificate verification.

If you want to verify the hostname, you have to set verifyhost. SNI is irrelevant.


#7

Thanks. Guess I’ll need to go back and re-wrap my head around SNI.
My understanding was that, after the client passed the TLS extension in the header that the server would deliver the certificate appropriate to that domain name. The client would then verify against the delivered certificate, not the default certificate.


#8

I ran into a misconfigured web site that nicely showed this problem.
Below are the two openssl commands able to demonstrate the problem (name changed for privacy reasons):

First use OpenSSL to connect to the site and extract the fingerprint:
openssl s_client -connect www.somesite.net:443 < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin

SHA1 Fingerprint=60:1C:04:94:5B:71:37:61:39:2D:0C:4B:AC:8D:F9:0E:91:D1:07:36

Second use OpenSSL to connect to the site using SNI and extract the fingerprint:
openssl s_client -servername www.somesite.net -connect www.somesite.net:443 < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin

Using Qualys SSL Labs, we determined that the site had the www.somesite.net name as both the CommonName and the AlternateName on the certificate. We discovered this problem because the certificate delivered without SNI was invalid.

My expectation would be that HAProxy, when sending the SNI header would then check the returned certificate rather than the certificate returned without SNI header. I can see that the SNI is not being verified by sending an invalid SNI value and not getting a failed connection.


#9

I don’t know what you are trying to say here. In a TLS handshake, there is one certificate returned from the server, and haproxy verifies that exact certificate based on your configuration (verify, verifyhost).


#10

Hi Lukas:

We’ve created a demonstration environment that simplifies the issue.

An Nginx server configured for SNI is running at IP address 96.126.109.140.
When you use OpenSSL to connect to it without SNI, you get an invalid certificate.
When you use OpenSSL to connect to it with SNI, you get a valid certificate.
My question is, how do I configure the haproxy backend to connect to this IP address and validate the certificate returned by the SNI-enabled request? There is no valid certificate at the IP-level. This is an example of an environment we ran into.
We want to configure HAProxy to validate it is talking to private.AuricSystems.com (sni.AppropriateSolutions.com).

Examples:
Return invalid certificate from raw IP address:
openssl s_client -connect 96.126.109.140:443

Return valid certificate from SNI request:
openssl s_client -servername private.auricsystems.com -connect 96.126.109.140:443

Return a second valid certificate from same server with different SNI:
openssl s_client -servername sni.appropriatesolutions.com -connect 96.126.109.140:443

Regards
–Ray


#11

This works (SNI is set to private.auricsystems.com and the returned certificate is validated against the hostname private.auricsystems.com):

server test private.auricsystems.com:443 ssl sni str(private.auricsystems.com) verifyhost private.auricsystems.com ca-file </etc/ca-file>

Haproxy refuses to connect if the hostname is something else:
server test private.auricsystems.com:443 ssl sni str(private.auricsystems.com) verifyhost mail.com ca-file </etc/ca-file>

But you are right about one thing: the health check actually does not send SNI to the server, and that is probably the issue here.


HAProxy 1.6, Backend SNI not working in my implementation
#12

Thanks for the clarification. I was so focused on the health checks failing that I did not consider that it would work without the health check. I’ll document this thread and issue a ticket.
–Ray


TLS ServerName extension during ssl-hello-chk