13 Loadbalancer mit lloadd

Nachdem Sie in Kapitel 12, «Replikation des OpenLDAP-Baums», eine Landschaft aus zwei oder mehr LDAP-Servern erstellt haben, besitzen Sie eine solide und ausfallsichere Umgebung. Nun können Sie sich dem Thema Lastverteilung zuwenden. Ziel dieses Kapitels ist es, in Ihrer Umgebung den bestehenden LDAP-Servern einen Loadbalancer vorzuschalten, welcher die Anfragen gleichmäßig auf die einzelnen LDAP-Server verteilt.

13.1 Übersicht über lload

OpenLDAP bietet Ihnen mit lload eine solche Lösung der Lastverteilung. Dabei verteilt lload nicht die Verbindungen, sondern nimmt die Lastverteilung auf Basis der einzelnen Operationen durch. Daher setzt lload identische Daten auf allen LDAP-Servern voraus. Der Algorithmus kontrolliert nicht, welche Operationen der Client im Einzelnen durchführt und kann daher auch keine „intelligente Verteilung“ durchführen. Beim Einsatz von OpenLDAP 2.5 sollte ein Client, welcher eine durchgehende Verbindung z.B. für mehrere Schreiboperationen zu genau einem LDAP-Server benötigt, eine Verbindung direkt mit einem LDAP-Server anstelle des Loadbalancers aufbauen. Ab Version 2.6 existiert die Möglichkeit, den Loadbalancer für einen Client kohärente Verbindungen zu einem LDAP-Server aufbauen zu lassen.

13.1.1 Funktionsweise von lload

Schauen wir uns die Funktionsweise von lload etwas genauer an. Der Loadbalancer baut beim Start des Dienstes eine Verbindung zum LDAP-Verzeichnis auf. Dazu authentifiziert sich der Dienst mit einem eigens dafür einzurichtenden Benutzer. Verbindet sich nun ein Client mit dem Loadbalancer, leitet dieser die Anfragen des Clients über diese Verbindung an die LDAP-Server weiter. Diese Anfragen finden dabei mit den Rechten des verbundenen Clients statt. Bild 13.1 zeigt Ihnen schematisch den Aufbau.

Bild 13.1 Schema eines Loadbalancers

13.1.2 Voraussetzungen

Grundvoraussetzung für den Einsatz eines Loadbalancers ist natürlich, dass die dahinter liegenden LDAP-Server, auf welche der Loadbalancer die Verbindungen verteilt, einen identischen Datenbestand besitzen. Daher ist eine entsprechende Replikation zwischen den LDAP-Servern unerlässlich, um konsistente Ergebnisse zu erhalten.

Bei der Konfiguration geben Sie neben diesem Benutzer – dem bindDN – an, um welche Art Verbindung es sich handelt. Neben der Verbindung pro Operation gibt es wie erwähnt ab OpenLDAP 2.6 auch die Möglichkeit einer kohärenten Verbindung. Da es Clients gibt, welche einen hohen Datendurchsatz für Leseoperationen benötigen und daher nicht auf eine kohärente Verbindung angewiesen sind und es andererseits Clients geben wird, welche z.B. für Schreiboperationen eine dauerhafte Verbindung für mehrere Operationen zu einem LDAP-Server benötigen, sollten Sie zwei unterschiedliche Konfigurationen erstellen.

Wie beschrieben, benötigen wir einen weiteren Benutzer im LDAP-Verzeichnis, mit welchen der Loadbalancer sich gegenüber dem LDAP-Verzeichnis beim Start authentifiziert. Die späteren Abfragen werden dann im Namen des Benutzers durchgeführt, welcher die Abfrage vom Client aus absetzt. Dabei wird dessen bindDN vom Loadbalancer an den jeweiligen LDAP-Server übertragen, ohne eine weitere Authentifizierung durchzuführen. Eine solche Proxy-Authentifizierung wird aber standardmäßig vom LDAP-Server bzw. dem jeweiligen Backend nicht erlaubt, und es ist eine entsprechende Anpassung notwendig.

In diesem Kapitel werden wir den Loadbalancer über einen separaten LDAP-Server beschreiben. Es gibt auch die Möglichkeit, lload als eigenen Daemon ohne slapd -Service zu betreiben. Allerdings hat die hier beschriebene Methode den Vorteil, dass wir dann auch auf die Leistungsdaten des monitor-Overlays zurückgreifen können.

13.2 Vorbereitungen für lload

Wie beschrieben, müssen vor dem Einsatz eines Loadbalancers einige Vorbereitungen getroffen werden, die wir hier nun schrittweise beschreiben.

13.2.1 Proxy-Authentifizierung

Als Erstes sollten Sie die Konfiguration der LDAP-Server durchführen. Beachten Sie, dass Sie dies für alle beteiligten LDAP-Server tun. Wenn Sie die config-Datenbank ebenfalls replizieren, ist dies natürlich nur einmal notwendig.

Für die einzelnen Server ist die Proxy-Authentifizierung für die Backends zu aktivieren. Dies können Sie zum Beispiel mit dem LDIF aus Listing 13.1 einrichten.

Listing 13.1 Einrichtung von syncprov

dn: cn=config changetype: modify replace: olcAuthzpolicy olcAuthzpolicy: to

Der Wert für das Attribut olcAuthzpolicy kann dabei die Werte none (Default) für „keine Proxy-Authentifizierung“, to für das Erlauben ankommender, from für ausgehende oder both für ein- und ausgehende Proxy-Authentifizierungen annehmen. In unserem Fall benötigen wir lediglich eingehende.

13.2.2 Erstellen des Proxy-Benutzers

Nun können Sie den eigenen Benutzer für lload in Ihrem LDAP-Verzeichnis einrichten. Listing 13.2 zeigt Ihnen ein Beispiel für eine LDIF-Datei für einen solchen Benutzer. Dieser Benutzer benötigt zusätzlich die Eigenschaft, eine Proxy-Authentifizierung durchzuführen. Dies wird anhand des Attributs authzTo realisiert. Dieses Attribut gibt anhand einer LDAP-URI an, für welche Objekte der lload-Benutzer eine Proxy-Authentifizierung durchführen darf.

Listing 13.2 lload-Benutzer

dn: uid=lloadd,ou=users,dc=example,dc=net objectClass: account objectClass: simpleSecurityObject objectClass: top uid: lloadd userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$MTIzZmRmZjY3ODY1NDMy$ \ bFN6MX4smW70QiwRG+jiQLsLv3C69LDQHL+ZE/infR8 authzTo: ldap:///dc=example,dc=net??sub?(|(uid=*)(cn=*))

Mit dem Setzen des Attributs authzTo, wie in Listing 13.2 gezeigt, können sich Benutzer mit ihremcn oder ihrer uid authentifizieren. Eine weitere Möglichkeit für den Wert von authzTo ist die Angabe über einen regulären Ausdruck der Form dn.regex:^uid=[^,]*,dc=example, dc=com$ oder eines einzelnen Distinguished Names wie dn:uid=berater,ou=users,dc=example,dc=net.

Image

Hinweis: Beachten Sie bei der Bearbeitung mit dem ApacheDirectoryStudio oder einer Suche nach dem Attribut authzTo, dass es sich um ein operationales Attribut handelt.

Image

Image

Wichtig: Ein Benutzer mit Schreibrechten auf das Attribut authzTo seines Benutzerobjektes kann sich eine Hintertür schaffen, die Identität eines beliebigen anderen Objektes anzunehmen. Daher ist dieses Attribut dringend mit einer entsprechenden ACL zu versehen.

Image

13.2.3 Rechte für den Proxy-Benutzer

Damit der Benutzer eine Proxy-Authentifizierung für einen anderen Benutzer in einer Datenbank durchführen kann, benötigt er noch das auth-Privileg für die jeweiligen Attribute, in diesem Fall die Anmeldung mit dem cn sowie der uid. Listing 13.3 zeigt Ihnen eine LDIF-Datei für die Gewährung eines entsprechenden Rechts.

Listing 13.3 ACL zur Proxy-Anmeldung

dn: olcDatabase={2}mdb,cn=config changetype: modify add: olcAccess olcAccess: {0} to attrs=uid,cn by dn.exact=uid=lloadd,ou=users,dc=example,dc=net auth by *

Der neue Benutzer muss nun noch in die Lage versetzt werden, die Benutzer im LDAP-Verzeichnis zu finden. Dazu benötigt er die entsprechenden Rechte in der Datenbank bzw. den entsprechenden Bereichen. In unserem Fall benötigt er das Leserecht auf das Attribut uid im gesamten Baum. Die LDIF-Datei in Listing 13.4 gibt ein Beispiel für entsprechende ACLs:

Listing 13.4 Einrichten der ACL für den lload-Benutzer

dn: olcDatabase={2}mdb,cn=config changetype: modify add: olcAccess olcAccess: {1} to * by dn.exact="uid=lloadd,ou=users,dc=example,dc=net" read by * break - add: olcLimits olcLimits: {0} dn.exact="uid=lloadd,ou=users,dc=example,dc=net" time=unlimited size=unlimited

Image

Wichtig: Beachten Sie, dass die ACL aus Listing 13.4 nach der ACL aus Listing 13.3 steht, da sonst die auth-Berechtigung nicht greift.

Image

13.3 Einrichten des Loadbalancers

Zunächst einmal benötigen Sie also einen neuen OpenLDAP-Server. Nach der Einrichtung eines Betriebssystems installieren Sie die OpenLDAP-Pakete von Symas, wie beispielsweise in Kapitel 3, «Installation des ersten OpenLDAP», beschrieben.

13.3.1 Modul

Jetzt geht es an die Einrichtung von lload. Zunächst einmal muss das entsprechende Modul geladen werden. Mit einer LDIF-Datei wie der in Listing 13.5 können Sie Ihren neuen Server entsprechend einrichten:

Listing 13.5 Laden des lload-Moduls

dn: cn=module{0},cn=config changetype: modify add: olcModuleload olcModuleLoad: lloadd.la

13.3.2 Backend

Nun geht es an die eigentliche Konfiguration des Dienstes. Das Modul benötigt ein eigenes Backend. Das Listing 13.6 liefert Ihnen ein solches:

Listing 13.6 Erstellen des lload-Backends

dn: olcBackend=lload,cn=config objectClass: olcBackendConfig objectClass: olcBkLloadConfig olcBackend: lload olcBkLloadListen: ldap://:1389 olcBkLloadListen: ldaps://:1636 olcBkLloadBindconf: bindmethod=simple timeout=0 network-timeout=5 \ binddn="uid=lloadd,ou=users,dc=example,dc=net" credentials="geheim" keepalive=0:0:0 tcp-user-timeout=0 \ tls_cert="/opt/symas/etc/openldap/example-net-cert.pem" \ tls_key="/opt/symas//etc/openldap/example-net-key.pem" \ tls_cacert="/opt/symas/etc/openldap/cacert.pem" olcBkLloadFeature: proxyauthz olcBkLloadIOThreads: 1 olcBkLloadSockbufMaxClient: 16777215 olcBkLloadSockbufMaxUpstream: 16777215 olcBkLloadMaxPDUPerCycle: 10 olcBkLloadIOTimeout: 10000

Die Parameter des Backends im Einzelnen:

Image       olcBkLloadListen
Da der slapd bereits die Ports 389 und 636 belegt, benötigt das lload-Modul eigene Ports für ldap bzw. ldaps.

Image       olcBkLloadBindconf
Dieser Parameter legt fest, wie der Loadbalancer ein Bind zu den LDAP-Servern durchführt.

Image       olcBkLloadFeature
In diesem Fall wird die Weiterleitung der Clientauthentifizierung aktiviert.

Image       olcBkLloadIOThreads
Wie viele Threads sollen gestartet werden?

Image       olcBkLloadSockbufMaxClient
Die maximale Größe der Buffer für ankommende LDAP-Anfragen eines Clients.

Image       olcBkLloadSockbufMaxUpstream
Dieser Wert gibt die maximale Größe für LDAP-Anfragen an, welche an die dahinter liegenden LDAP-Server weiterzuleiten sind.

Image       olcBkLloadMaxPDUPerCycle
Die Anzahl maximaler Anfragen (Protocol Data Units), die während eines Abfragezyklus bearbeitet werden können.

Image       olcBkLloadIOTimeout
Gibt den Timeout für I/O-Operationen in Millisekunden an.

Image

Wichtig: Beachten Sie die Ports in der Konfiguration des Backends. In unserem Fall läuft der slapd auf den Standardports 389 und 636. Clients oder Consumer, welche später auf das eigentliche LDAP-Verzeichnis „hinter“ dem Loadbalancer zugreifen wollen, müssen die abweichenden Ports (hier 1389 und 1636) verwenden.

Image

13.3.3 Tier

Nun können Sie die erste Konfiguration für eine Verbindung zu einem LDAP-Verzeichnis bzw. den jeweiligen LDAP-Servern einrichten. Dazu werden sogenannte Tier erstellt. Diese enthalten dann wiederum Objekte für die jeweiligen LDAP-Server. In Listing 13.7 wird ein solcher Tier inklusive der beiden LDAP-Server erstellt.

Listing 13.7 Verbindungskonfiguration zu zwei LDAP-Servern

dn: cn={0}tier 1,olcBackend={0}lload,cn=config objectClass: olcBkLloadTierConfig cn: {0}tier 1 olcBkLloadTierType: roundrobin dn: cn={0}server 1,cn={0}tier 1,olcBackend={0}lload,cn=config objectClass: olcBkLloadBackendConfig cn: {0}server 1 olcBkLloadBackendUri: ldap://provider01.example.net olcBkLloadStartTLS: yes olcBkLloadNumconns: 10 olcBkLloadBindconns: 5 olcBkLloadRetry: 5000 olcBkLloadMaxPendingOps: 50 olcBkLloadMaxPendingConns: 10 olcBkLloadWeight: 1 dn: cn={1}server 2,cn={0}tier 1,olcBackend={0}lload,cn=config objectClass: olcBkLloadBackendConfig cn: {1}server 2 olcBkLloadBackendUri: ldap://provider02.example.net olcBkLloadStartTLS: yes olcBkLloadNumconns: 10 olcBkLloadBindconns: 5 olcBkLloadRetry: 5000 olcBkLloadMaxPendingOps: 50 olcBkLloadMaxPendingConns: 10 olcBkLloadWeight: 1

Wie Sie sehen, legen Sie mit dem Attribut olcBlkLloadTierType des tier-Objekts fest, welcher Art die Verbindung zu den beiden Servern sein soll. Die möglichen Werte für dieses Attribut lauten:

Image       roundrobin
Hierbei werden die Provider nacheinander kontaktiert.

Image       weighted
Hierbei werden die einzelnen Provider in der Liste über den zusätzlichen Parameter weight gewichtet. Der Wert gibt an, wie oft ein Provider für eingehende Verbindungen genutzt wird, bevor zu einem anderen Provider gewechselt wird.

Image       bestof
Auch bei diesem Wert benötigen die Provider einen Parameter weight. Bei der Wahl eines Providers werden zwei Server eines tier ausgewählt, deren durchschnittliche Latenz mit deren weight multipliziert und dann der Server mit dem besseren Ergebnis verwendet wird.

Innerhalb des tier-Objektswerden nun die einzelnen Server für diese Verbindung definiert. Zu konfigurieren sind hier folgende Parameter:

Image       olcBkLloadBackendUri
Dieser Wert legt die URI fest, unter welcher der Provider erreicht werden kann. Sie können hier natürlich auch ldaps verwenden.

Image       olcBkLloadStartTLS
Mit dem Wert critical ist eine TLS-Verbindung zwingend notwendig. Der Wert yes versucht zunächst, eine TLS-Verbindung aufzubauen. Kommt diese nicht zustande, wird die Verbindung ohne Verschlüsselung erstellt.

Image       olcBkLloadNumconns
Dieser Wert gibt die Anzahl möglicher Verbindungen zu diesem Server an.

Image       olcBkLloadBindconns
Für Bind-Anfragen wird diese maximale Anzahl von Verbindungen verwendet.

Image       olcBkLloadRetry
Kommt eine Verbindung nicht zustande, gibt dieser Wert an, wie lange (in Millisekunden) gewartet wird, bevor ein neuer Versuch unternommen wird.

Image       olcBkLloadMaxPendingOps
Hiermit geben Sie an, wie viele unbeendete Operationen maximal erlaubt sind.

Image       olcBkLloadMaxPendingConns
Dieser Parameter legt die Anzahl maximal gleichzeitiger unbeendeter Verbindungen fest, die zu diesem Server erlaubt sind.

Image       olcBkLloadWeight
Für die Tier-Typen weighted und bestof müssen Sie hier das jeweilige „Gewicht“ des Providers eintragen.

Wenn Sie nun Abfragen an den Loadbalancer stellen, werden diese nacheinander auf die beiden LDAP-Server provider01 und provider02 verteilt. Im vorliegenden Fall verteilt der Loadbalancer die einzelnen Operationen mit dem gewählten Round-Robin-Verfahren nacheinander auf die einzelnen LDAP-Server. Bild 13.2 zeigt Ihnen schematisch den Ablauf.

Bild 13.2 Verteilung der Operationen durch den Loadbalancer

13.3.4 Schreiboperationen

Im bisherigen Beispiel würde für jede Operation ein anderer LDAP-Server ausgewählt. Dies ist bei Schreiboperation nicht ideal. Daher gibt es bei der Konfiguration des Backends noch einen weiteren Parameter, den wir bislang nochnicht betrachtet haben. Richten Sie das Backend mit den Parametern wie in Listing 13.6 ein, so werden Sie beim erneuten Abrufen der Eigenschaften einen zusätzlichen Parameter entdecken: olcBlkLloadWriteCoherence. Dieser gibt die Zeitspanne (in Sekunden) an, welche ein Client nach seiner ersten Schreiboperationen mit dem dann vom Loadbalancer zugewiesenen LDAP-Server verbunden bleibt. Nehmen wir an, der Wert stehe auf 10. Löst ein Client seine erste Schreiboperation im LDAP-Verzeichnis aus und weist ihm der Loadbalancer den LDAP-Server provider01 zu, so bleibt der Client zehn Sekunden für alle weiteren Operationen mit diesem Server verbunden. Ein Wert von -1 würde den Client nach der ersten Schreiboperation dauerhaft mit dem zugewiesenen LDAP-Server verbinden. Der Standartwert 0 deaktiviert diese Funktion. Wenn Sie also für beide Fälle vorsorgen (beliebige Verteilung jeder Operation zur gleichmäßigen Verteilung auf alle LDAP-Server und kohärente Verbindungen beispielsweise für Änderungen), so richten Sie zwei Backends ein: eines mit einem Wert für olcBlkLload-WriteCoherence von 0 (oder ohne dass Sie den Parameter setzen) und einen mit einem Wert ungleich 0 für eine dauerhaftere Verbindung zu einem LDAP-Server. Clients oder Anwendungen, welche nur Abfragen an das LDAP-Verzeichnis stellen oder welche dieses zur Authentifizierung verwenden, nutzen dann das erste Backend. Diejenigen, die öfter und umfangreichere Änderungen am LDAP-Verzeichnis durchführen, verwenden dann das Letztere. Je nachdem, auf welchen Port ein Client dann zugreift, erreicht er entweder das eine oder andere Backend.