HAProxy für Active Directory LDAP

Prinzipiell ist Active Directory auf Redundanz ausgelegt, mehrere Domain Controller sorgen dafür dass immer einer verfügbar ist. AD nutzt hierfür allerdings SRV-DNS-Records, die von Clients die per LDAP auf das Active Directory zugreifen in der Regel nicht beachtet werden. Das hat den Effekt, dass Anwendungen (wenn sie überhaupt die Möglichkeit bieten mehrere LDAP-Server anzugeben) öfter mal stocken wenn der DC der als erstes eingetragen ist nicht erreichbar ist. In der Regel warten sie dann auf einen Timeout bis sie den nächsten DC probieren. Und das bei jeder Abfrage.

Um das zu vermeiden habe ich jetzt zwei Ubuntu-VMs aufgesetzt (16.04, nicht 18.04, siehe den Nachtrag am Ende) auf denen jeweils ein HAProxy läuft, der alle DCs als Backend eingetragen hat. HAProxy verteilt die Zugriffe auf die vorhandenen DCs, sollte einer ausfallen merkt HAProxy das und leitet die Anfragen an einen anderen DC bis der ausgefallene DC wieder da ist. Zwei VMs, da dadurch natürlich der Proxy der Single Point of Failure wird.

Ich habe also:

  • dcproxy1, 10.11.12.2
  • dcproxy2, 10.11.12.3

Dazu kommt eine virtuelle IP-Adresse, die von keepalived immer auf einer der beiden VMs gehalten wird.

Auf beiden VMs die benötigten Dienste installieren:

sudo apt install keepalived haproxy

Ein SSL-Zertifikat erzeugen und auf beide VMs kopieren. Ich habe dafür /etc/ssl/ gewählt. Hinweis: HAProxy benötigt Zertifikate und Key zusammen in einem bundle file.

sudo cat dcproxy.example.com_cert_with_chain.pem dcproxy.example.com_key.pem |sudo tee dcproxy.example.com_bundle.pem

Die Konfiguration für HAProxy ist auf beiden VMs identisch. So sieht meine /etc/haproxy/haproxy.cfg aus:

global
log /dev/log    local0
log /dev/log    local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# 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/
# An alternative list with additional directives can be obtained from
#  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
ssl-default-bind-options no-sslv3
tune.ssl.default-dh-param 2048
defaults
log     global
mode    http
option  httplog
option  dontlognull
timeout connect 5000
timeout client  50000
timeout server  50000
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
frontend ldap_service_front
mode                  tcp
log                   global
bind                  :389
description           LDAP Service
option                tcplog
option                logasap
option                socket-stats
option                tcpka
timeout client        5s
default_backend       ldap_service_back
backend ldap_service_back
server                ldap-1 dc01.ad.example.com:389 check fall 1 rise 1 inter 2s
server                ldap-2 dc02.ad.example.com:389 check fall 1 rise 1 inter 2s
server                ldap-3 dc03.ad.example.com:389 check fall 1 rise 1 inter 2s
mode                  tcp
balance               source
timeout server        2s
timeout connect       1s
option                tcpka
# https://www.mail-archive.com/haproxy@formilux.org/msg17371.html
option                tcp-check
tcp-check             connect port 389
tcp-check             send-binary 300c0201            # LDAP bind request "<ROOT>" simple
tcp-check             send-binary 01                  # message ID
tcp-check             send-binary 6007                # protocol Op
tcp-check             send-binary 0201                # bind request
tcp-check             send-binary 03                  # LDAP v3
tcp-check             send-binary 04008000            # name, simple authentication
tcp-check             expect binary 0a0100            # bind response + result code: success
tcp-check             send-binary 30050201034200      # unbind request
# LDAPS
frontend ldapS_service_front
mode                  tcp
log                   global
bind                  :636 ssl crt /etc/ssl/dcproxy.example.com_bundle.pem
description           LDAPS Service
option                tcplog
option                logasap
option                socket-stats
option                tcpka
timeout client        5s
default_backend       ldaps_service_back
backend ldaps_service_back
server                ldapS-1 dc01.example.com:636 check fall 1 rise 1 inter 2s verify none check check-ssl ssl
server                ldapS-2 dc02.example.com:636 check fall 1 rise 1 inter 2s verify none check check-ssl ssl
server                ldapS-3 dc03.example.com:636 check fall 1 rise 1 inter 2s verify none check check-ssl ssl
mode                  tcp
balance               source
timeout server        2s
timeout connect       1s
option                tcpka
option                tcp-check
tcp-check             connect port 636 ssl
tcp-check             send-binary 300c0201            # LDAP bind request "<ROOT>" simple
tcp-check             send-binary 01                  # message ID
tcp-check             send-binary 6007                # protocol Op
tcp-check             send-binary 0201                # bind request
tcp-check             send-binary 03                  # LDAP v3
tcp-check             send-binary 04008000            # name, simple authentication
tcp-check             expect binary 0a0100            # bind response + result code: success
tcp-check             send-binary 30050201034200      # unbind request

Als nächstes kommt die Konfiguration von keepalived. Die /etc/keepalived/keepalived.conf auf VM1:

vrrp_instance VI_1 {
state MASTER
interface ens160
virtual_router_id 101
priority 101
advert_int 1
authentication {
auth_type PASS
auth_pass SECRET
}
virtual_ipaddress {
10.11.12.1
}
}

Die Konfiguration auf VM2 ist nahezu identisch:

vrrp_instance VI_1 {
state MASTER
interface ens160
virtual_router_id 101
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass SECRET
}
virtual_ipaddress {
10.11.12.1
}
}

Der einzige Unterschied ist die priority.

Das war es schon. Einmal die Dienste neu starten, dann sollte alles funktionieren:

sudo systemctl restart haproxy
sudo systemctl restart keepalived

Die VM mit der höheren ID bekommt die virtuelle IP. Sollte die VM ausfallen dauert es nach meinen Tests unter 5 Sekunden bis die andere VM die IP bekommt.

Auf den Clients wird jetzt dcproxy.example.com als LDAP-Server eingetragen, was auf die floating IP zeigt. Damit ist immer einer der beiden HAProxys erreichbar.

Im vCenter habe ich noch eine DRS-Regel eingerichtet die dafür sorgt dass die beiden VMs nie auf dem gleichen Host laufen, idealerweise eine in jedem Rechnerraum.

Nachtrag 14.04.2019

Nach einiger Zeit ist ein Problem aufgetreten, und zwar haben die VMs die virtuelle IP-Adresse verloren, aber keiner der beiden keepalived-Instanzen war der Meinung er müsste sie wiederherstellen. War auch kein Wunder, die beiden konnten ja Problemlos miteinander reden und haben kein Problem festgestellt. Nach etwas Recherche habe ich dann herausgefunden dass das Problem aufgetreten ist, wenn ein Systemupdate eingespielt wurde, das den systemd neu gestartet hat. Anscheinend hat dann die Netzwerk-Komponente von systemd die gespeicherte Netzwerkkonfiguration geladen, in der die virtuelle IP-Adresse nicht vorkam, und sie damit entfernt.

Das Problem ist ein bekannter Bug im systemd der bei Ubuntu 18.04 mitgeliefert wird. Er ist zwar behoben, aber die Version in der es behoben ist ist bei Ubuntu 18.04 noch nicht dabei.

Ich habe verschiedenste Checks versucht, um den IP-Verlust mit Sicherheit zu erkennen, damit keepalived sie wieder einrichten kann, aber zu guter Letzt habe ich die VMs mit Ubuntu 16.04 neu aufgesetzt. Seitdem ist das Problem nicht wieder aufgetreten.

Veröffentlicht von

Gerald Schneider

Diplom-Informatiker (DH) in Rostock. Ich blogge über Entwicklung, Internet, mobile Geräte und Virtualisierung.

Ein Gedanke zu „HAProxy für Active Directory LDAP“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert