Tidying up haproxy.cfg

Proof of Concept #haproxy

I made a little perl script that I can keep haproxy.cfg nice and tidy with. If you know Ansible’s assemble module, it’s pretty much like that, but on steroids.

This script lets you not only separate config file parts into conf.d-like files but provides some simple, yet useful Jinja2 like {{templating|function}}s as well as the ability to transparently join multiple lines the right order just as it should have been done from the beginning of time. In this Let’s Encrypt-heated encrypt-everything-era this script also comes handy when one have to deal with enormous amount of TLS certificates (per frontend).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env perl
use strict;
use warnings;

# template function
sub certlist($){
    my $dir=shift;
    opendir(my $dh, '/etc/haproxy/'.$dir) || die "Can't open TLS dir '$dir': $!";
    my @certs = grep{/-bundle$/}readdir($dh);
    my $certlist = join(' ',map{$_="crt /etc/haproxy/$dir/".$_} @certs);
    if (-e $dir.'/ca.cer') {
        $certlist.=' ca-file /etc/haproxy/'.$dir.'/ca.cer';
    }
    closedir $dh;
    return $certlist;
}

my $ls=0;
while(<>) {
    s/^ {4,8}/\t/;
    s/\{\{ *tls *\| *([\S\/]+) *\}\}/certlist($1)/e;
    s/^[\t\s]+/ / if $ls;
    if (m/\\$/) {
        s/\s*[\\\r\n]+$//;
        $ls=1;
    } else {
        $ls=0;
    }
    print;
}

Combine this with this wholesome Makefile right here and you will have a complete, error-prone way to manage your HAproxy configfiles:

all: config test config_submit reload
config:
	cat $(sort $(wildcard /etc/haproxy/conf.d/*.conf)) | perl linemerger.pl > /etc/haproxy/haproxy.cfg.new
config_submit:
	mv /etc/haproxy/haproxy.cfg{,.prev}
	mv /etc/haproxy/haproxy.cfg{.new,}
test: config
	haproxy -c -f /etc/haproxy/haproxy.cfg.new
reload:
	systemctl reload haproxy

Update: Since HAProxy version 2.2 the {{ tls }} templating function is now practically superseded by the new ssl option called crt-list which also offers to have different TLS options per SNI. Nice.