Hi,
I am trying to write a config that allows me to work with this setup:
I currently have one client connecting to two different services (borth port 443) on two different servers (different IPs). I would like that client to connect to the same server.
Service 1 is a mix of http and tcp, while Service 2 is pure tcp (protobuf).
The SNI is empty so I can’t use that to write my ACL route.
Is it possible to route via matched certificate?
Something like:
frontend in
bind *:443 ssl crt /link/to/service1.pem crt /link/to/service2.pem
mode tcp
acl backend1 cert matches service1.pem
acl backend2 cert matches service2.pem
use_backend tcp_backend1 if backend1
use_backend tcp_backend2 if backend2
Any help is appreciated!
How does it select the correct certificate without SNI?
At the moment I am using the same .pem for both services so that’s probably why that works at all.
I am using something akin to this to see the SNI
frontend in
mode tcp
tcp-request inspect-delay 3s
tcp-request content capture req.ssl_sni len 10
log-format "capture0: %[capture.req.hdr(0)]"
The resulting loglines are empty except for “capture0:”.
I am happy to try other ways of separating the traffic. Unfortunately I can’t change anything about the client.
First of all you are accessing req.ssl_sni
which will always be empty because you don’t have a SSL client hello in the buffer, but you are terminating(deciphering) SSL, so you need to be using ssl_fc_sni
instead.
Then what you are logging is the first captured HTTP header, which is completely unrelated of what you are trying to do; you don’t work with HTTP headers here at all.
Try this instead:
frontend in
bind *:443 ssl crt /link/to/service1.pem crt /link/to/service2.pem
mode tcp
log-format "ssl variables: %[ssl_fc_sni]/%sslv/%sslc"
To find out whether or not the client send SNI you can also take a packet capture and check the server name value in the client hello.
Afterwards you can simply match SNI with acls like:
use_backend tcp_backend1 if { ssl_fc_sni -i www.backend1.com }
use_backend tcp_backend2 if { ssl_fc_sni -i www.backend2.com }
Or you can match one and default_backend
the other one, if you only have 2 scenarios you need to cover and you want to match only a single scenario via SNI.
I really appreciate your help, thank you!
It seems like I am out of luck though:
<134>Apr 25 11:44:47 haproxy[30]: ssl variables: -/TLSv1.2/ECDHE-RSA-AES128-SHA256 <-Service A
<134>Apr 25 11:44:50 haproxy[30]: ssl variables: -/TLSv1.2/ECDHE-RSA-AES128-SHA256 <-Service A
<134>Apr 25 11:44:57 haproxy[30]: ssl variables: -/TLSv1.2/ECDHE-RSA-AES128-SHA256 <-Service B
It seems like it can’t be done, which is too bad. Unless you have another idea?
Did you try both clients? The one using protobuf and the one using HTTP and other TCP protocols?
You only need SNI capable clients for one of the two scenarios.
If none of the clients support SNI, you only choice is getting a single certificate that matches both hostnames (via SAN or wildcard), and then try to match something in the first client packet to make a routing decision.
For example, HTTP can be matched. I’m not familiar with protobuf though, I don’t know if the first packet comes from the client and if it contains something useful to make a routing decision.
Yes, I tried both. It’s hard to see in my last message, but I marked which request(s) where made to which service. Both empty unfortunately.
I have a single certificate, unfortunately I can’t find anything to match by. What makes this worse is that Service A sometimes gets http-requests and sometimes tcp requests (If I only route http-requests to Service A the client doesn’t work as intended).
Looks like you out of luck then. This is going to require separate ports or IP addresses then.