Any ideas why "verify required" is allowing connections with no client cert?
Could this be an haproxy bug? I hate to even ask that, because it's so presumptuous and this software is so well-written. It's one thousand times more likely that I'm doing something wrong. But from where I sit it seems simple: - I used "verify require" which should require a client cert - I can connect without specifying a client cert So, am I - misusing/misunderstanding "verify require"? - screwing up some other piece of haproxy config? - using the wrong socat/openssl syntax to send (or not) the client cert? - thinking a client cert is valid with tcp when it isn't? I'm not sure what else to try, without spending money on a real client cert, which doesn't seem like it should matter. Hopefully someone can tell me what I'm doing wrong! Also, sorry about the HTML email for my original post. Best, Donovan From: <Meyers>, Donovan Meyers <[email protected]> Date: Tuesday, July 22, 2014 3:33 PM To: "[email protected]" <[email protected]> Subject: Client certs on tcp and securing stats socket Hi all, First of all, thanks again and always for the great work and an excellent product. I'm looking for a secure way to communicate with the haproxy stats socket for remote management of haproxy (without ssh), preferably without running some extra API service or anything. I love that 1.5 can now listen on a socket instead of a file. My concern is securing it. My current best idea is to have the stats socket on 127.0.0.1:7828, and to have haproxy handle authentication before forwarding remote connections to it. The only authentication I could think of would be client SSL certificates. Having the socket on 127.0.0.1:7828 works great -- you can connect from locally on the box but not from elsewhere. Having a TCP-mode proxy listening and forwarding to there works great too, even with SSL. Haproxy is proxying connections to its own stats socket! Where I'm running into trouble is requiring a client cert -- even with "verify required" on my frontend (or listen) bind line, I can connect with no client cert. My intention is to use an ACL to check for specific information in the client cert (using ssl_c_s_dn, ssl_c_serial, and/or ssl_c_sha1). I also ran into trouble matching against that information, but then I discovered that I wasn't even requiring a client cert. I'm using all self-signed certs. Maybe there's an issue with the way I'm generating certs that's causing this? Here's how I generated them: FILENAME=haproxy-server openssl genrsa -out $FILENAME.key 1024 openssl req -new -key $FILENAME.key -x509 -days 3653 -out $FILENAME.crt cat $FILENAME.key $FILENAME.crt >$FILENAME.pem FILENAME=haproxy-client openssl genrsa -out $FILENAME.key 1024 openssl req -new -key $FILENAME.key -x509 -days 3653 -out $FILENAME.crt cat $FILENAME.key $FILENAME.crt >$FILENAME.pem At first I didn't enter any info for the certs (just pressed Enter on each line), but then I recreated the client cert with some valid info. Here's my config: global daemon pidfile /var/run/haproxy.pid stats socket [email protected]:7828 log 127.0.0.1 local0 debug defaults log global option redispatch retries 3 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout check 10s listen default_stats bind 0.0.0.0:10800 mode http stats enable listen main-service bind 0.0.0.0:80 mode http frontend stats-socket bind 10.108.0.166:7828 ssl crt /root/haproxy-ssl/haproxy-server.pem verify required ca-file /root/haproxy-ssl/haproxy-client.crt mode tcp log-format %ci:%cp\ [%t]\ %ft\ %b/%s\ %Tw/%Tc/%Tt\ %B\ %ts\ %ac/%fc/%bc/%sc/%rc\ %sq/%bq\ %{+Q}[ssl_c_s_dn] default_backend local_socket backend local_socket server localhost 127.0.0.1:7828 Here's my haproxy version and deets: HA-Proxy version 1.5.2 2014/07/12 Copyright 2000-2014 Willy Tarreau <[email protected]> Build options : TARGET = linux2628 CPU = generic CC = gcc CFLAGS = -O2 -g -fno-strict-aliasing OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_PCRE=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.1e-fips 11 Feb 2013 Running on OpenSSL version : OpenSSL 1.0.1e-fips 11 Feb 2013 OpenSSL library supports TLS extensions : yes OpenSSL library supports SNI : yes OpenSSL library supports prefer-server-ciphers : yes Built with PCRE version : 7.8 2008-09-05 PCRE library supports JIT : no (USE_PCRE_JIT not set) Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND Available polling systems : epoll : pref=300, test result OK poll : pref=200, test result OK select : pref=150, test result OK Total: 3 (3 usable), will use epoll. Here's how I'm connecting with a client cert: socat stdio openssl-connect:domeyers-haproxy-socket-test.gha.usw1.cld.scea.com:7828,cer t=/root/haproxy-ssl/haproxy-client.pem,cafile=/root/haproxy-ssl/haproxy-ser ver.crt OR (less often - I tried openssl in case there was a problem with my socat) openssl s_client -connect domeyers-haproxy-socket-test.gha.usw1.cld.scea.com:7828 -cert ./haproxy-client.crt -key ./haproxy-client.key And without: socat stdio openssl-connect:domeyers-haproxy-socket-test.gha.usw1.cld.scea.com:7828,caf ile=/root/haproxy-ssl/haproxy-server.crt openssl s_client -connect domeyers-haproxy-socket-test.gha.usw1.cld.scea.com:7828 Here is it allowing my connection, without a client cert, despite the config above: [root@domeyers-haproxy-socket-test haproxy-ssl]# socat stdio openssl-connect:domeyers-haproxy-socket-test.gha.usw1.cld.scea.com:7828,caf ile=/root/haproxy-ssl/haproxy-server.crt show stat # pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,e resp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,ql imit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_s tatus,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5x x,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt,comp_ in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,last_agt,qtime,ctime,rtime, ttime, default_stats,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,2,0,,,,0,0 ,0,0,,,,0,0,0,0,0,0,,0,0,0,,,0,0,0,0,,,,,,,, default_stats,BACKEND,0,0,0,0,200,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,0,6304,0,,1, 2,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0,0,0,0,0,-1,,,0,0,0,0, main-service,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,3,0,,,,0,0, 0,0,,,,0,0,0,0,0,0,,0,0,0,,,0,0,0,0,,,,,,,, main-service,BACKEND,0,0,0,0,200,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,0,6304,0,,1,3 ,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0,0,0,0,0,-1,,,0,0,0,0, stats-socket,FRONTEND,,,1,1,2000,10,91,12588,0,0,0,,,,,OPEN,,,,,,,,,1,4,0,, ,,0,0,0,1,,,,,,,,,,,0,0,0,,,0,0,0,0,,,,,,,, local_socket,localhost,0,0,1,1,,10,91,12588,,0,,0,0,0,0,no check,1,1,0,,,,,,1,5,1,,10,,2,0,,1,,,,,,,,,,0,,,,0,0,,,,,3,,,1,1,0,59, local_socket,BACKEND,0,0,1,1,200,10,91,12588,0,0,,0,0,0,0,UP,1,1,0,,0,6304, 0,,1,5,0,,10,,1,0,,1,,,,,,,,,,,,,,0,0,0,0,0,0,3,,,1,1,0,59, Log line: 2014-07-22T15:03:10-07:00 localhost haproxy[21598]: 10.108.0.166:60116 [22/Jul/2014:15:03:06.419] stats-socket~ local_socket/localhost 5/1/3890 1352 -- 0/0/0/0/0 0/0 "" I've never seen anything logged as ssl_c_s_dn (the last field) -- it's always empty. At first I thought I wasn't using the client cert the right way for haproxy to receive it, because I was having trouble matching ACLs against it. But then I found that I didn't even need a client cert to connect, so now I'm troubleshooting that. Any help would be appreciated, including alternate options for securing this traffic. For the record, here are some of the config lines I was trying to use to validate fields in the client cert: tcp-request inspect-delay 30s acl client_cert_cn_ok ssl_c_s_dn(CN) -m str my.host.name.com tcp-request content accept if client_cert_cn_ok tcp-request content reject Thanks! Donovan

