I have a very generic simple configuration like this:
use_backend static unless { ssl_c_verify 0 }
use_backend dotwebha-http-10600 if { ssl_c_used }
# fall-through to holding page
default_backend static
The ssl_c_verify doesn’t seem to do anything. If I comment it out it has no effect whether or not you supply a cert.
vru-ws-webtest-b2buat:/# /usr/rbin/haproxy -vv
HA-Proxy version 1.5.18 2016/05/10
Copyright 2000-2016 Willy Tarreau <willy@haproxy.org>
Build options :
TARGET = solaris
CPU = generic
CC = gcc
CFLAGS = -m32 -O2 -g -fno-strict-aliasing -fomit-frame-pointer -DFD_SETSIZE=65536 -D_REENTRANT
OPTIONS = USE_ZLIB=1 USE_OPENSSL=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.2j 26 Sep 2016
Running on OpenSSL version : OpenSSL 1.0.2j 26 Sep 2016
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports prefer-server-ciphers : yes
Built without PCRE support (using libc's regex instead)
Available polling systems :
poll : pref=200, test result OK
select : pref=150, test result OK
Total: 2 (2 usable), will use poll.
vru-ws-webtest-b2buat:/# uname -a
SunOS vru-ws-webtest-b2buat 5.10 Generic_Virtual sun4v sparc sun4v
vru-ws-webtest-b2buat:/#
If you are using 2.0, you may be hitting a bug:
You need to combine it with ssl_c_used
.
Show the entire configuration and the expected behavior, and I can suggest how the configuration should look like.
Here’s the entire text, except I removed all but one of the binds.
global
# Run in the background
daemon
# Log locally - syslog logs to /var/haproxy/logs/haproxy.log
log 127.0.0.1 local0
# Sets the maximum per-process number of concurrent connections to 2400
maxconn 2400
# Where to find ssl certs
crt-base /etc/haproxy
ca-base /etc/haproxy
# local stats socket for hatop command - use "/usr/bin/hatop -s /var/haproxy/haproxy.sock"
stats socket /var/haproxy/haproxy.sock mode 0600 level admin
defaults
# Defaults section is inherited by each frontend/backend if is isn't specified
# Log extended info in standard NSCA format
option httplog
# Log null connections -
# option dontlognull
# Add x-forward-for in header to retain source
option forwardfor
# Log info on health checks by haproxy
option log-health-checks
# Enable most uptodate stats
option contstats
# Times a connection attempt should be retried on a server when a connection either is refused or times out
retries 3
# Break cookie persistence and redistribute them to a working server should a server fail
option redispatch
# Max connections per service
maxconn 200
# Use the same config as in "global" section of cfg
log global
# default listening mode
mode http
# TCP timeout to connect to server
timeout connect 5s
# Timeout for client response
timeout client 50s
# Timeout defines how long to wait for a new HTTP request to start coming after a response was sent.
timeout http-keep-alive 1s
# Backend server timeout
timeout server 50s
# DDoS/Slowloris protection
# Maximum accepted time to receive a complete HTTP request
timeout http-request 15s
# Time to wait to process requests when maxconn has been reached (before dropping request)
timeout queue 30s
# tarpit hold time
timeout tarpit 1m
# hint to number of TCP syns that the system can handle
backlog 10000
monitor-uri /haproxy_test
# Set log format for analysis - this is analysed by awstats.
# It's vital that the capture header lines are in for each frontend so that the log format stays consistent
log-format [%T]\ %ci\ %cp\ %ft\ %b\ %s\ %Tq\ %Tw\ %Tc\ %Tr\ %Tt\ %ST\ %B\ %{+Q}CC\ %{+Q}CS\ %tsc\ %ac\ %fc\ %bc\ %sc\ %rc\ %sq\ %bq\ %{+Q}sslv\ %{+Q}sslc\ %{+Q}hrl\ %{+Q}hsl\ %[ssl_c_verify]\ %{+Q}[ssl_c_s_dn]\ %{+Q}[ssl_c_i_dn]\ %[ssl_c_notafter]\ %{+Q}r
peers mypeers
# Share sticky connection informaton
peer vru-ws-webtest-b2buat 10.208.50.29:1024
frontend b2buat-https-in-ws-9600
# SSL listener
mode http
# Test frontend requiring client certs
# webservices-dot.test is set to the local IP address in /etc/hosts
# Client cert is optional, so that we can redirect to a web page if there is a problem (eg using http!)
bind webservices-dot.test:9600 ssl crt webservices-dot.test_300916.pem ca-file CA_2015.cer verify optional crt-ignore-err all 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
# if there is an error with the certificate, then route the user to a holding page farm
use_backend b2b-bad-cert-static unless { ssl_c_verify 0 }
# check if the certificate has been provided and give access to the application
use_backend dotwebha-http-10600 if { ssl_c_used }
# fallthrough to holding page again
default_backend b2b-no-cert-static
# Capture jboss cookie
capture cookie JSESSIONID len 40
# Max sessions
rate-limit sessions 100
# Compress responses
compression algo gzip
compression type text/html text/plain text/css
# Log User agent
capture request header User-agent len 320
# log the beginning of the referrer
capture request header Referer len 20
# log the amount of data uploaded during a POST
capture request header Content-Length len 10
# logging the content-length is useful with "option logasap"
capture response header Content-Length len 10
# log the expected cache behaviour on the response
capture response header Cache-Control len 8
# log the URL location during a redirection
capture response header Location len 20
backend b2b-bad-cert-static
# This is a dropthough backend to only show local static (error) pages
mode http
# Detect an apacheKiller-like Attack
acl weirdrangehdr hdr_cnt(Range) gt 10
# Clean up the request
reqidel ^Range if weirdrangehdr
# Close connections to the backend while keeping frontend connection open
option http-server-close
# ACL url paths
acl url_expired path /certexpired.html
acl url_revoked path /certrevoked.html
acl url_othererrors path /maintenance.html
# ACL SSL cert return codes
acl cert_expired ssl_c_verify 10
acl cert_revoked ssl_c_verify 23
# Add header
reqadd X-Ssl-Error:\ 10 if cert_expired
reqadd X-Ssl-Error:\ 23 if cert_revoked
reqadd X-Ssl-Error:\ other if ! cert_expired ! cert_revoked
# Redirect against ACLs above
redirect location /certexpired.html if cert_expired ! url_expired
redirect location /certrevoked.html if cert_revoked ! url_revoked
redirect location /maintenance.html if ! cert_expired ! cert_revoked ! url_othererrors
# Local apache server
server localhost 127.0.0.1:4444 check
backend b2b-no-cert-static
# This is a dropthough backend used to inform b2b peers that they
# have not sent a client SSL certificate
# All we have to do here is send a message to inform the peer
# so no servers are configured, and the proxy will send a 503
# Service temporarily unavailable - send a client cert next time!
mode http
errorfile 503 /etc/haproxy/errorfiles/503_nocert.http
backend dotwebha-http-10600
timeout server 900s
# Insert cookie so that we can track the haproxy session
cookie SERVERID insert indirect nocache
# Track the session using the JSESSIONID cookie
appsession JSESSIONID len 52 timeout 3h request-learn prefix
# Proxy transaction to the backend apache servers
# option httpchk GET /heartbeat/thump HTTP/1.0
# Balancing algorithm
balance roundrobin
# Sticky table
stick-table type ip size 20k peers mypeers
# Backend servers, 32 connections each, tracked by cookie and checked using httpchk above
server vru-ws-webtest-b2buat 10.208.50.29:10600 maxconn 400 check cookie A id 1
# Local backup server if above both fail
server localhost 127.0.0.1:4444 maxconn 500 backup
# All else fails - 503
errorfile 503 /etc/haproxy/errorfiles/503.http
listen admin
# Admin server showing stats
bind *:8080
stats enable
stats uri /
Ok, so what you would like to achieve is:
- allow access if the client certificate is provided and verified without errors
- redirect to
b2b-bad-cert-static
if a client certificate has been provided, but has failed validation
- redirect to
b2b-no-cert-static
if no client certificate has been provided
I believe ssl_c_verify
can be 0, if no cert was provided (as there is no error), so that’s why I’m saying you need to combine the two. Also, I’d turn the logic around, and make it fail-safe: only forward to the production backend if a certificate has been provided and is valid, as opposed to match some error conditions and fallback to production if it did not match.
# allow access if client certificate is provided + validated without errors
use_backend dotwebha-http-10600 if { ssl_c_used } { ssl_c_verify 0 }
# use b2b-no-cert-static if no client certificate has been provided
use_backend b2b-no-cert-static if ! { ssl_c_used }
# use b2b-bad-cert-static if there is something wrong wwith the ssl verification
use_backend b2b-bad-cert-static if { ssl_c_used } ! { ssl_c_verify 0 }
# no fallback; if bug/misconfiguration happened, make haproxy fail
1 Like
That makes more sense. I’ll try that out.
Thanks