ACL filters when using mode tcp?

Hi, I have a setup I’ve been struggling with for a while.

I want to use tcp mode to pass-through SSL.
I want it so when I enter I get passed through to the backend, but if any other domain than is used to access haproxy with it will be sent to the fallback backend.

Is that possible?

Here is what I’ve tried so far:

        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
        maxconn 10240
        nbproc 4
        nbthread 1
        cpu-map auto:1/1-4 0-3

        log global
        mode tcp
        option tcplog
        option dontlognull
        maxconn 2048
        retries 3
        timeout connect 10s
        timeout client  30s
        timeout server  30s
        timeout http-request 10s
        timeout http-keep-alive 2s
        timeout queue 5s
        timeout tunnel 2m
        timeout client-fin 2s
        timeout server-fin 2s

         bind XXX.YYY.ZZZ.WWW:80
         bind XXX.YYY.ZZZ.WWW:443
         use_backend if { hdr(host) -i }
         use_backend if { hdr_dom(host) -i }
         default_backend fallback

         balance static-rr
         server default AAA.BBB.CCC.DDD:443 check verify none fall 3 rise 2

backend fallback
         balance static-rr
         server fallback

Any suggestions?

Those ACL would access HTTP headers. This is possible when a) the content is not encrypted or it is decrypted by haproxy and b) when the frontend is in http mode (this implies decryption).

In this case though the entire HTTP transaction is encrypted and you cannot access it.

What you can do is parse the SNI value in the SSL client_hello.

tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
use_backend if { req.ssl_sni -i }

Two important notes:

  • you need to wait for the complete SSL client_hello to be in the buffers (first to lines)
  • this will not work for overlapping certificates (one certificate that covers both acl’ed as well as fallback domains, because the SNI decision will be made once per SSL session (during handshake based on the client_hello packet) and the browser will reuse an existing SSL session for different domains, when the certificate allows that

Those 3 lines work wonders for the actual backend, thanks!

But is there any way to have it fallback to another backend if none of those rules fire? Like, if I change it to:

tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
use_backend if { req.ssl_sni -i }
use_backend if { req.ssl_sni -i }

I have then added “default_backend fallback” after those 4 lines but it doesn’t seem to register?
I have a web server running on the same machine as haproxy which listens on and it works fine using “curl” so it is running - but the backend is never used?

My fallback backend simply looks like this:

backend fallback
         balance static-rr
         server fallback

8080 is probably not an HTTPS/SSL port. You can’t connect incoming HTTPS on port 443 to a plain HTTP server.

works fine using “curl”

Exactly, using HTTP. Not HTTPS.
(You also need to remove binding to port 80 on your frontend, this will do the wrong thing)

When this is fixed, post the output of

curl -v https://XXX.YYY.ZZZ.WWW:443/

from the haproxy box, to see what happens.

1 Like