Good afternoon dear community members!
I’m experimenting with haproxy as a balancer and facing some difficulties.
Clients connect tcp-streams (not http data) to my system using client certificates. The certificates may be up-do-date and working but may also be expired. In order to “catch” these expired certificates I am trying to establish “transparent” proxy-server (so to speak) in front our real balancers/backend which has to do nothing but check incoming certificates and log them (cn/dn/not_before/not_after) and pass the stream right along to backend. It’s must be kind of Man-In-Middle.
In haproxy settings I enabled setting “crt-ignore-err 10” to ignore expired certs errors and everything seems to be working good: the client certs logs to file and even clients with expired certificates can pass trough.
Scheme looks like this:
client_with_certificate —> haproxy_host:20252 (ssl) —> backend-host:50252 (ssl)
The connection has to be passed through haproxy to our backend servers, where I can one more time check the TLS/SSL certificate and finally decide to cut it off if it has expired.
But I am confused with the settings. It must be SSL/TLS between haproxy and backend, but how to pass the original client certificate? Is it possible?
Current configs attached:
global
log /dev/log local0 debug
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM->
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
tune.ssl.default-dh-param 2048
defaults
log global
mode tcp
option httplog
option dontlognull
option httplog
timeout connect 5000
timeout client 50000
timeout server 50000
frontend my_frontend
bind *:20252 ssl crt /etc/haproxy/cert_and_key.pem ca-file /etc/haproxy/ca.crt verify required crt-ignore-err 10
mode tcp
option tcplog
timeout client 10s
default_backend my_backend
log-format '[%t] %ci:%cp %ft {%[ssl_c_verify],%{+Q}[ssl_c_s_dn(cn)],%{+Q}[ssl_c_i_dn]},%{+Q}[ssl_c_notbefore],%{+Q}[ssl_c_notafter]'
backend my_backend
balance leastconn
server s1 _my_server_addr_:50252 ssl verify required ca-file /etc/haproxy/ca.crt
With that setup it is not working. Connection dies between haproxy and backend and on the backend side I see errors:
2025/04/30 15:35:35 [info] 1762878#1762878: *16 client sent no required SSL certificate while SSL handshaking, client: CLIENT_IP, server: 0.0.0.0:50252
2025/04/30 15:35:35 [info] 1762878#1762878: *16 SSL_shutdown() failed (SSL: error:14094123:SSL routines:ssl3_read_bytes:application data after close notify) while SSL handshaking, client: CLIENT_IP, server: 0.0.0.0:50252
which is strange and seems like in connection between haproxy and backend has nothing to do with certificates.
I have experimented with options like ‘send-proxy’, ‘no-check-send-proxy’, etc, in backend section but none of that worked. If I add ‘send-proxy’, the error changes to:
SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number)
And I am completely lost here.
Any help will be appreciated.