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