Cluster haproxy actif/actif, ssl et multisites

Un petit moment que je n’avais pas fait d’articles sur des mises en place et nouveaux services. Cette fois je pars sur un cluster haproxy, du ssl, et plusieurs sites. L’idée de base est de remplacer mon reverse proxy Nginx par un Haproxy.

En fait, j’ai déjà un haproxy en place mais qui ne travaille que pour TeamSpeak. A coté de lui j’ai un Nginx qui fait reverse proxy pour les différents sites hébergés. On va tout remettre sous Haproxy, cela facilitera la maintenance. Partons donc sur un serveur from scratch et chez Core Us c’est principalement Ubuntu.

Première étape, installation des services

Pour faire notre cluster Heartbeat et Haproxy, on doit installer les softs et créer les configuration. Il faut d’abord créer un nœud du cluster et une fois validé, on le clonera ensuite pour faire le second. Je travaille avec une Ubuntu Server avec OpenSSH

apt-get install heartbeat haproxy

Seconde étape, configuration de Heartbeat

Suffisamment de tutoriels relatent de la configuration d’HeartBeat. Nous n’allons pas la refaire ici. Juste présenter nos fichiers de conf

/etc/ha.d/ha.cf
logfile /var/log/ha-log
logfacility local0
keepalive 2
deadtime 10
initdead 20
bcast eth2
udpport 694
auto_failback off
node hap1
node hap2
/etc/ha.d/haresources
# Resources hap1
hap1 IPaddr2::10.1.1.11/24/eth0:1/10.1.1.255\
 IPaddr2::10.1.1.13/24/eth0:3/10.1.1.255 \
 IPaddr2::10.1.1.15/24/eth0:5/10.1.1.255 \
IProute2::10.1.1.254/eth0 haproxy

# Resources hap2
hap2 IPaddr2::10.1.1.12/24/eth0:2/10.1.1.255\
IPaddr2::10.1.1.14/24/eth0:4/10.1.1.255 \
IPaddr2::10.1.1.16/24/eth0:6/10.1.1.255 \
IProute2::10.1.1.254/eth0 haproxy

On notera l’utilisation d’une resource IProute2 qui n’existe pas de base dans HeartBeat. C’est un script maison utilisé pour gérer la route par défaut lors des bascules de ressources. On peut retrouver les informations dans cet article : Route par defaut

Troisième étape, configuration de HAProxy

Sachant que notre configuration HAProxy deviendrait assez vite conséquente et ingérable en monolithique. Nous avons donc cherché à reproduire le modèle de configuration des sites dans Apache2.
Avant toutes choses, comme nous avons un proxy actif/actif, il nous faut des fichiers de configuration identiques sur chacun des nœuds. Cela implique donc de pouvoir faire écouter des services sur des IP par encore configurées sur un nœud. Pour cela, il suffit de modifier un paramètre de configuration système. On édite le fichier /etc/sysctl.conf et on ajoute la ligne suivante à la fin :

net.ipv4.ip_nonlocal_bind=1

Le fichier de configuration de base contient donc uniquement les paramètres globaux:

/etc/haproxy/haproxy.cfg

global
 log /dev/log local0
 log /dev/log local1 notice
 chroot /var/lib/haproxy
 stats socket /run/haproxy/admin.sock mode 660 level admin
 stats timeout 30s
 user haproxy
 group haproxy
 daemon

#########################################################################
# Paramètres SSL Globaux
 # Default SSL material locations
 ca-base /etc/ssl/certs
 #crt-base /etc/ssl/private
 crt-base /etc/ssl

# Default ciphers to use on SSL-enabled listening sockets.
 # For more information, see ciphers(1SSL). This list is from:
 # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
 ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
 ssl-default-bind-options no-sslv3 force-tlsv12
 ssl-server-verify required
 tune.ssl.default-dh-param 2048
 maxconn 2048
 tune.ssl.cachesize 100000
 tune.ssl.lifetime 600
#Fin SSL
#########################################################################

defaults
 log global
 mode http
 #option httplog
 option dontlognull
 timeout connect 5s
 timeout client 10s
 timeout server 10s
 timeout http-request 5s
 errorfile 400 /etc/haproxy/errors/400.http
 errorfile 403 /etc/haproxy/errors/403.http
 errorfile 408 /etc/haproxy/errors/408.http
 errorfile 500 /etc/haproxy/errors/500.http
 errorfile 502 /etc/haproxy/errors/502.http
 errorfile 503 /etc/haproxy/errors/503.http
 errorfile 504 /etc/haproxy/errors/504.http
 option forwardfor
 option http-server-close

On va maintenant voir la partie split de la configuration. On a donc créé 2 sous-dossiers : /etc/haproxy/conf-available et /etc/haproxy/conf-enabled.

Nous nous sommes ensuite appuyé sur des scripts déjà développés que nous avons légèrement modifiés ( source )

haenconf

#!/bin/bash

if [[ $EUID -ne 0 ]]; then
 echo "You must be a root user" 2>&1
 exit 1
fi

if [ $# -lt 1 ]; then
 echo "Invalid number of arguments"
 echo "Here are the conf available"
 ls /etc/haproxy/conf-available/ | sed -e 's/.cfg//g'
 exit 1
fi

cd /etc/haproxy/conf-enabled
if [ -f $1.cfg ]; then
 echo "Enabling $1..."
 ln -s ../conf-available/$1.cfg ./
 echo "To activate the new configuration, you need to run:"
 echo " /etc/init.d/haproxy restart"
else
 echo "Configuration file not found"
 echo "Here are the configuration available"
 ls /etc/haproxy/conf-available/ | sed -e 's/.cfg//g'
fi

Script de désactivation

hadisconf

#!/bin/bash

if [[ $EUID -ne 0 ]]; then
 echo "You must be a root user" 2>&1
 exit 1
fi

if [ $# -lt 1 ]; then
 echo "Invalid number of arguments"
 exit 1
fi

echo "Disabling $1..."

rm -f /etc/haproxy/conf-enabled/$1.cfg

echo "To activate the new configuration, you need to run:"
echo " /etc/init.d/haproxy restart"

Voyons maintenant les fichiers de configuration site. Nous avons une partie avec du filtrage sur les fqdn ou les domaines, et d’autres où on gère par IP principalement pour des raisons de certificat.
Première version, filtrage par fqdn :

/etc/haproxy/conf-available/default.cfg
frontend http_in
 bind *:80
httplog
 reqadd X-Forwarded-Proto:\ http

# Define domain
 acl host_coreus hdr_dom(host) -i core-us
acl host_domaineclient hdr_dom(host) -i domaineclient.tld
# Switch
 use_backend back_coreus if host_coreus
use_backend back_mut if host_domaineclient
 
 default_backend coreus_accueil

Et maintenant la configuration par IP avec une redirection http vers https:

/etc/haproxy/conf-available/client.cfg

frontend http_client
 bind 10.10.10.1:80
 bind 10.10.10.2:80
 redirect scheme https code 301 if !{ ssl_fc }

frontend https_client
 bind 10.10.10.1:443 ssl crt /etc/letsencrypt/live/client/client.pem ca-file /etc/ssl/certs/UTN_USERFirst_Hardware_Root_CA.pem
 bind 10.10.10.2:443 ssl crt /etc/letsencrypt/live/client/client.pem ca-file /etc/ssl/certs/UTN_USERFirst_Hardware_Root_CA.pem
 option httplog
 reqadd X-Forwarded-Proto:\ http
 use_backend back_artisan

backend back_client
 option httpclose
# add X-FORWARDED-FOR
 option forwardfor
# add X-CLIENT-IP
 http-request add-header X-CLIENT-IP %[src]
 server srv-client 10.1.1.100:80

 

Voilà, c’est fini.