
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.
Danke dir , das ist eine sehr hilfreiche und ausführliche Anleitung!
/thorsten