Protecting services with client certificates using Haproxy

 What we want to achieve

We want to be able to connect to services inside a private network using client certificates, in this example we will be connecting to Redis.

haproxy-client-certs-overview.png

 Install or compile Haproxy

I am using Debian, so this is what I use to compile Haproxy for testing out this setup.

apt-get -y install make gcc g++ libssl-dev

wget http://www.haproxy.org/download/1.8/src/haproxy-1.8.4.tar.gz
tar xzf haproxy-1.8.4.tar.gz
cd haproxy-1.8.4
make TARGET=generic USE_OPENSSL=1
make install PREFIX=/usr/local

 Install and configure firewall

I am testing with a Redis-server, but it can be anything. First firewall off everything except for port 22 (ssh) and port 88 (our external redis port):

apt-get -y install ufw

ufw default deny incoming
ufw default allow outgoing
ufw allow 22
ufw allow 88

 Install Redis

apt-get -y install redis-server

Since Debian and Debian-related distros have the terrible idea that software need to run by default, you should now have a running redis-server on port 6379.

 Generate certificates

This is just for testing, please use some better tooling like easy-rsa to manage your certificates:

# MASTER CERTS:
openssl genrsa -nodes -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt # with cname=haproxytest.kaspergrubbe.com
cat ca.crt ca.key > ca.pem

# CLIENT CERTS:
openssl genrsa -out client.key 4096
openssl req -new -key client.key -out client.csr # FQDN=client.kaspergrubbe.com
openssl x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
cat client.crt client.key > client.pem

 Setup Haproxy server

This let Haproxy listen on port 88, and it will verify the connecting certificates, and if the authentication is succesful, it will forward the traffic to redis on 127.0.0.1:6379.

Create a file named: haproxy_server.cfg:

global
  pidfile /var/run/haproxy.pid
  maxconn 4000
  tune.ssl.default-dh-param 2048

listen redis
  bind 0.0.0.0:88 ssl crt /root/ca.pem ca-file /root/ca.crt verify required
  mode tcp
  server redis-1 127.0.0.1:6379 maxconn 1024

Run the config in a non-daemonized way:
haproxy -f haproxy_server.cfg.

 Connecting to Redis through another Haproxy

Create a file named: haproxy_client.cfg:

global
  pidfile haproxy.pid
  maxconn 4000

listen redis
  bind 0.0.0.0:7945
    mode tcp
  server redis-serv01 haproxytest.kaspergrubbe.com:88 ssl crt client.pem ca-file ca.crt

Run the config in a non-daemonized way:
haproxy -f haproxy_client.cfg.

Now you should be able to connect to Redis from your terminal:

$ redis-cli -h localhost -p 7945
localhost:7945> ping
PONG

 Connect to Redis through Ruby

If you do not want to install a Haproxy instance just to manage the client certificates, you can connect directly from your favorite programming language, here is an example on how to do it in Ruby:

require 'socket'
require 'openssl'

sock = TCPSocket.new('haproxytest.kaspergrubbe.com', 88)

ctx = OpenSSL::SSL::SSLContext.new
ctx.cert = OpenSSL::X509::Certificate.new(File.read('/root/client.pem'))
ctx.key  = OpenSSL::PKey::RSA.new(File.read('/root/client.key'))
# ctx.key = OpenSSL::PKey::RSA.new(File.read('client.key'), 'secret_password')

@socket = OpenSSL::SSL::SSLSocket.new(sock, ctx).tap do |socket|
  socket.sync_close = true
  socket.connect
  socket.write "PING\n"
  socket.each_line do |line|
    puts line
  end
end

 Todo:

Consider using CRL-files for making your life easier, CRL stands for Client Revocation List, and it is a list of certificates that you no longer trust for one reason or another, so if a server gets hacked, or an employee laptop goes missing, you can revoke the certificate and sleep nicely afterwards knowing that they can’t use the certificate for anything.

When you have a crl-file, It is as easy as adding crl-file <crlfile> to the server configuration.

There is a nice article about crls here: https://jamielinux.com/docs/openssl-certificate-authority/certificate-revocation-lists.html

 
2
Kudos
 
2
Kudos

Now read this

GolfQuis: a golfing iOS game built by Boolex that leaks passwords

I was looking for a company to help me build a small prototype for an idea I had for a mobile application. So to find a company I asked around, and someone mentioned the company Boolex. I naturally wanted to check out the quality of... Continue →