10 | Erweiterte Funktionen durch Overlays |
OpenLDAP bringt sämtliche grundlegenden Funktionalitäten für einen Verzeichnisdienst mit. Diese stellen alle Dienste und Funktionen bereit, welche von allen Datenbanken eines LDAP-Servers benötigt werden. In einigen Situationen und für einige Datenbanken können allerdings zusätzliche Funktionen nützlich oder notwendig sein. Diese können über Overlays bereitgestellt werden. Diese Funktionen werden dem LDAP-Service (ähnlich wie Plug-ins in einem Browser) hinzugefügt und konfiguriert. Dabei gelten sie entweder für alle oder einzelne Datenbanken. Overlays bereiten entweder Daten für die Darstellung oder Weitergabe auf, manipulieren diese in der Datenbank oder stellen zusätzliche Funktionen wie Protokollierung oder Überwachung bereit.
Hinweis: Achten Sie darauf, dass Sie die Konfigurationseinträge für die Overlays einer Datenbank immer unterhalb des rootDN-Eintrags erstellen. Einige der Overlays benötigen den rootDN zwingend.
10.1 | Datenaufbereitung |
Zunächst werden wir einige der Overlays behandeln, welche Daten für die Darstellung aufbereiten, ohne diese in der Datenbank zu ändern.
10.1.1 | translucent |
Mit dem translucent-Modul lässt sich eine Art transparenter Proxy zu anderen LDAP-Servern einrichten. So können Sie Informationen eines Objekts aus verschiedenen LDAP-Datenbanken von verschiedenen LDAP-Servern zusammenführen. Unterscheiden sich die Werte einzelner Attribute in der lokalen und der entfernten Datenbank, so wird standardmäßig der Wert der lokalen Datenbank genutzt.
Wozu wird das benötigt? Nehmen wir zwei separate Benutzerdatenbanken eines Unternehmens. Datenbank A dient zur reinen Authentifizierung der Benutzer und besitzt somit Anmelde- und Sicherheitsinformationen. In Datenbank B sind persönliche Informationen wie Geburtstag, Anschrift und andere Attribute der Benutzer hinterlegt. Eine LDAP-Abfrage soll nun alle gesperrten Benutzerkonten sowie einige persönliche Angaben der jeweiligen Konten zurückliefern. Es sollen also die gesperrten Konten aus Datenbank A nebst der dort abgelegten Sperrinformationen sowie Werte aus persönlichen Attributen aus Datenbank B gesucht und das Resultat beider Anfragen in einem Ergebnis zurückgegeben werden.
Dieses Overlay sammelt also quasi alle möglichen Informationen über ein Objekt aus verschiedenen LDAP-Verzeichnissen zusammen und stellt sie Ihnen als ein einheitliches Ergebnis zur Verfügung.
Das translucent-Modul deaktiviert die Schemaüberprüfung in der lokalen Datenbank. Werte eines Attributs aus der entfernten Datenbank müssen damit nicht dem lokalen Schema entsprechen. Widersprechen also die Regeln zu einem Attribut wie mail aus der entfernten Datenbank nicht den lokalen Regeln der abgefragten Datenbank, so liefert dies keinen Fehler.
Hinweis: Um Objekte der lokalen und der entfernten Objekte übereinanderzulegen, müssen ihre Kontexte identisch sein. Liegen also die Benutzerobjekte eines individuellen Benutzers in verschiedenen Kontexten (zum Beispiel cn=emustermann, ou=verwaltung,dc=example,dc=net in der lokalen und cn=emustermann, ou=administration,dc=example,dc=net in der entfernten Datenbank), so können diese nicht zusammengeführt werden.
Schauen wir uns ein Beispiel an. Nehmen wir zwei LDAP-Server provider01 und provider02. Während provider01 der Authentifizierung dient, beinhaltet provider02 persönliche Informationen zu den Benutzern.
Fragen wir (wie im Beispiel in Listing 10.1) die beiden Server nach den Informationen zu einem Benutzerobjekt:
Listing 10.1 Abfrage ohne translucent
provider01:~ # ldapsearch -H ldap://provider01 -D "cn=admin,dc=example,dc=net" \ -W '(cn=jdoe)' givenName sn displayName title description dn: cn=jdoe,ou=users,dc=example,dc=net sn: Doe givenName: Jane provider01:~ # ldapsearch -H ldap://provider02 -D "cn=admin,dc=example,dc=net" \ -W '(cn=jdoe)' givenName sn displayName title description dn: cn=jdoe,ou=users,dc=example,dc=net sn: Doe title: CIO description: Chief Information Officer givenName: Jane-Mary displayName: Jane Doe
Während also in der Datenbank des provider01 von den gesuchten Attributen lediglich sn und givenName mit einem Wert belegt sind, besitzt Server provider02 auch Werte für die weiteren Attribute title, description und displayName. Die Werte für givenName unterscheiden sich zudem zwischen den beiden Datenbanken.
Aktivieren Sie auf dem Server provider01 das translucent-Overlay und lassen Sie die Informationen durch die des provider02 ergänzen, dann sieht das Suchergebnis bei der gleichen Abfrage an den provider01 anders aus, wie Sie in Listing 10.2 sehen:
Listing 10.2 Abfrage mit translucent
provider01:~ # ldapsearch -H ldap://provider01 -D "cn=admin,dc=example,dc=net" \ -W '(cn=jdoe)' givenName sn displayName title description dn: cn=jdoe,ou=users,dc=example,dc=net sn: Doe title: CIO description: Chief Information Officer givenName: Jane displayName: Jane Doe
Es werden also die Informationen beider Datenbanken zusammengeführt, wobei der Konflikt für das Attribut givenName aufgelöst wird, indem der auf dem Server provider01 gespeicherte Wert zurückgegeben wird.
Bevor wir uns mit der Konfiguration des translucent-Overlays befassen, müssen wir einen kurzen Blick auf ein weiteres mögliches Backend werfen: LDAP. Dabei handelt es sich nicht um eine weitere physische Datenbank wie mdb, sondern um einen Verweis auf ein anderes LDAP-Verzeichnis. Ankommende Anfragen oder aufzulösende Verweise werden dabei an das entfernte LDAP-Verzeichnis weitergeleitet. Über dieses Backend werden in der Folge die zusätzlichen Informationen abgefragt.
Eine dynamische Konfiguration für ein solches LDAP-Backend finden Sie in Listing 10.3:
Listing 10.3 Beispiel eines LDAP-Backends für OLC
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: back_ldap.la dn: olcDatabase=ldap,cn=config objectClass: olcDatabaseConfig objectClass: olcLDAPConfig olcDatabase: ldap olcSuffix: dc=example,dc=net olcDbURI: "ldap://yellowpages.technik.net" olcDbACLBind: bindmethod=simple binddn="uid=proxyuser,dc=technik,dc=net" \ credentials="geheim"
Dieses Beispiel würde somit Anfragen an Objekte im Kontext dc=technik,dc=net an den angegebenen LDAP-Server yellowpages.technik.net mit den angegebenen Anmeldeinformationen weiterleiten.
Zu den einzelnen Parametern:
olcSuffix
Bei Weiterleitung von Referenzen auf Objekte in anderen (Teil-)Bereichen Ihres LDAP-Verzeichnisses, welche auf entfernten Servern abgelegt sind, geben Sie hier den entsprechenden Kontext an.
olcDbURI
Geben Sie hier eine URI-Adresse an, über welche Sie Informationen des unter suffix definierten Kontextes abrufen können. Dieser Parameter kann mehrfach mit unterschiedlichen Adressen definiert werden.
olcDbACLBind
Hier geben Sie diverse Optionen für die Anmeldung am entfernten Verzeichnis an. Diese hängen von der gewählten bindmethod ab. In diesem Fall sind es lediglich der Benutzername (binddn) und das Kennwort (credentials). Möglich sind hier aber auch Angaben zur Authentifizierung mit SASL-Mechanismen und zur Kommunikation über TLS.
Im Manual zu slapd-ldap finden Sie weitere Informationen sowie weitere Parameter, welche Sie unter olcDbACLBind angeben können. An dieser Stelle sei noch auf einen weiteren Parameter hingewiesen: starttls. Für eine gesicherte Kommunikation insbesondere über Netzwerke, welche nicht in Ihrem Schutzbereich liegen, empfiehlt sich der Einsatz verschlüsselter TLS-Verbindungen. Der Parameter kann die Werte no (keine Nutzung von TLS), yes (TLS wird versucht, bei Misserfolg aber nicht verwendet) oder critical (TLS muss verwendet werden) annehmen. Hinzu kommen dann weitere Parameter wie tls_cert, tls_cacert, tls_cipher_suite.
Hinweis: Wie Sie sehen, benötigt das LDAP-Backend einen Benutzer zur Authentifizierung am jeweils anderen LDAP-Server. Dieses Konto muss dort vorher angelegt sein und benötigt mindestens Leserechte auf den auszulesenden Attributen. Einen möglichen Benutzer für die Authentifizierung finden Sie in Listing 10.4.
Listing 10.4 LDIF für den Proxyuser
dn: uid=proxy,dc=example,dc=net objectClass: account objectClass: simpleSecurityObject uid: proxy userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,\ p=1$ZGJmZGRkc3NzMTIzNDU$W+3A5630GWZE2pOfoT4pI8huoD9Uuss0tFw/CGmhIJ0
Nach dem obligatorischen Laden des Moduls muss das Overlay innerhalb der Datenbank definiert werden, in welcher sich diejenigen Objekte befinden, für welche Sie Suchen in entfernten Verzeichnissen durchführen wollen. In Listing 10.5 sehen zunächst, wie Sie die benötigten Module über für die dynamische Konfiguration laden können:
Listing 10.5 Laden des translucent-Moduls
dn: cn=module{0},cn=config changetype: modify add: olcModuleload olcModuleload: translucent.la dn: cn=module{0},cn=config changetype: modify add: olcModuleload olcModuleload: back_ldap.la
Zur Konfiguration des Overlays benötigen Sie nun zwei weitere Objekte: eines für das Overlay in der Objektdatenbank und eines für die LDAP-Datenbank innerhalb des Overlays für den Verweis auf das entfernte LDAP-Verzeichnis. Das Overlay-Objekt wird (da es sich ja auf die Objektdatenbanken bezieht) als untergeordnetes Objekt der Datenbank erstellt. Dieser Logik folgend müssen Sie das Objekt zur LDAP-Datenbank für das entfernte Verzeichnis wiederum als untergeordnetes Objekt für das Overlay-Objekt erstellen. Listing 10.6 gibt Ihnen ein Beispiel:
Listing 10.6 Dynamische Konfiguration der Datenbanken
dn: olcOverlay=translucent,olcDatabase={2}mdb,cn=config objectClass: olcOverlayConfig objectClass: olcTranslucentConfig olcOverlay: translucent olcTranslucentStrict: TRUE olcTranslucentNoGlue: TRUE olcTranslucentLocal: sn olcTranslucentRemote: mail olcTranslucentBindLocal: TRUE olcTranslucentPwModLocal: TRUE dn: olcDatabase=ldap,olcOverlay={0}translucent, \ olcDatabase={2}mdb,cn=config objectClass: olcLDAPConfig objectClass: olcTranslucentDatabase olcDatabase: ldap olcDbURI: ldap://provider02.example.net/ olcDbACLBind: binddn="uid=proxy,dc=example,dc=net" credentials="geheim"
Hinweis: Kommt es beim Import der LDIF-Datei zu einem Fehler wie ldap_add: Invalid syntax (21) für eines der Booleschen Attribute, schauen Sie noch einmal genau, ob sich hinter dem Wert noch Leerzeichen befinden. Falls ja, entfernen Sie diese. Das Zeilenende muss sich direkt hinter dem Booleschen Wert befinden, damit der LDIF-Import den Wert nicht als Zeichenkette interpretiert.
Zu den Parametern im Einzelnen:
olcTranslucentStrict
Werden Attribute nur in einem der beiden Verzeichnisse gelöscht, so führt dies durch diesen Parameter zu einer Fehlermeldung. Wird beispielsweise lokal ein Attribut gelöscht und besitzt der Benutzer, mit welchem das Overlay sich mit dem entfernten LDAP-Server verbindet, nicht die hinreichenden Berechtigungen, diese Löschung auch in der entfernten Datenbank durchzuführen, so schlägt die Operation mit einer Constraint violation fehl. Ohne diese Parameter wird die Löschung ohne Meldung ignoriert und stillschweigend nicht durchgeführt.
olcTranslucentNoGlue
Werden Objekte in der lokalen Datenbank hinzugefügt oder verschoben und die entsprechenden übergeordneten Objekte oder das Objekt selber existieren noch nicht im entfernten Verzeichnis, dann versucht diese, verleimende glue-Einträge zu erstellen, falls dieser Parameter nicht gesetzt ist. Wird dieser Parameter gesetzt,müssen diese Einträge vorher manuell erstellt werden.
Hinweis: Solange lokale Objekte in der entfernten Datenbank nicht erstellt wurden, sind diese auch in der lokalen Datenbank nicht sichtbar.
olcTranslucentLocal
Mit diesem Parameter legen Sie fest, nach welchen Attributen ausschließlich in der lokalen Datenbank gesucht werden soll. Befinden sich auch in der entfernten Datenbank Werte für diese Attribute, so werden diese bei der Suche ignoriert.
olcTranslucentRemote
Hiermit geben Sie eine Liste von Attributen an, die im Gegensatz zu olcTranslucentLocal nur in der entfernten Datenbank gesucht werden sollen. Eventuell lokal existierende Werte werden somit außer Acht gelassen.
olcTranslucentBindLocal
Sollte der Bind-Prozess bei der entfernten Datenbank aufgrund eines Authentifizierungsproblems scheitern, so wird versucht, diesen mit den lokalen Anmeldeinformationen zu wiederholen, wenn Sie diesen Parameter setzen.
olcTranslucentPwmodLocal
Hiermit aktivieren Sie die erweiterten Funktionen zur Kennwortänderung nach RFC 3062 für lokal gespeicherte Konten, welche auch in der entfernten Datenbank existieren. Damit kann die Kennwortänderung eines lokalen Benutzers auf das entsprechende Benutzerobjekt in der entfernten Datenbank übertragen werden.
Es folgen die Parameter für das entfernte LDAP-Verzeichnis, hier die Adresse des LDAP-Servers und die Anmeldeinformationen (der Suffix wird hier nicht benötigt, da er sich aus der übergeordneten Datenbank ergibt).
Hinweis: Für die Konfiguration der entfernten LDAP-Datenbank gibt es noch weitere Möglichkeiten der Konfiguration wie zum Beispiel Zugriff per TLS etc. Hierzu finden Sie weitere Hinweise im vorigen Abschnitt.
Wird nur der Parameter olcTranslucentLocal definiert, finden Suchen nach den angegebenen Attributen ausschließlich in der lokalen Datenbank statt. Entsprechend wird nur die entfernte Datenbank durchsucht, wenn ausschließlich der Parameter translucent_remote gesetzt wird. Geben Sie weder translucent_local noch translucent_remote an, so wird in der entfernten Datenbank nach allen Attributen gesucht. Würden Sie in den Parameter olc-TranslucentRemote unter anderem das Attribut givenName eintragen, so ergäbe die Abfrage in Listing 10.2 für das Attribut givenName nicht den Wert Jane aus der lokalen Datenbank, sondern Jane-Mary aus der Datenbank des entfernten Servers.
An dieser Stelle richten wir das Augenmerk noch einmal auf den Parameter translucent_no_glue. In folgendem Beispiel wird noch einmal gezeigt, was passiert, wenn ein lokales Objekt in dem anderen LDAP-Verzeichnis nicht gefunden wird: Es wird auch lokal nicht angezeigt. In Listing 10.7 wird zunächst ein neuer Benutzer invisible auf dem Server provider01 angelegt. Eine anschließende Suche auf den gleichen Server schlägt fehl. Erst nachdem der Benutzer auch auf dem anderen Server provider erzeugt wurde, ist die Suche auf dem provider01 erfolgreich:
Listing 10.7 Fehlender Glue-Eintrag
provider01:~# ldapadd -H ldap://provider01 -D "cn=admin,dc=example,dc=net" -w geheim dn: cn=invisible,dc=example,dc=net objectClass: person cn: invisible sn: Unsichtbar adding new entry "cn=invisible,dc=example,dc=net" provider01:~# ldapsearch -D "cn=admin,dc=example,dc=net" -w geheim \ -H ldap://provider01 -b "cn=invisible,dc=example,dc=net" # extended LDIF # # LDAPv3 # base <cn=invisible,dc=example,dc=net> with scope subtree # filter: (objectclass=*) # requesting: ALL # # search result search: 2 result: 32 No such object matchedDN: dc=example,dc=net # numResponses: 1 provider01:~# ldapadd -H ldap://provider02 -D "cn=admin,dc=example,dc=net" \ -w geheim dn: cn=invisible,dc=example,dc=net objectClass: person cn: invisible sn: Unsichtbar adding new entry "cn=invisible,dc=example,dc=net" provider01:~# ldapsearch -D "cn=admin,dc=example,dc=net" -w geheim \ -H ldap://provider01 -b "cn=invisible,dc=example,dc=net" # extended LDIF # # LDAPv3 # base <cn=invisible,dc=example,dc=net> with scope subtree # filter: (objectclass=*) # requesting: ALL # # invisible, example.net dn: cn=invisible,dc=example,dc=net objectClass: person cn: invisible sn: Unsichtbar # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1
Wenn Sie nun dem Benutzer im entfernten Verzeichnis auf provider02 ein neues Attribut hinzufügen, wird dies auch bei einer Suche über das Verzeichnis auf provider01 sichtbar. Besitzt das Attribut allerdings in der Datenbank auf provider01 einen anderen Wert, so überschreibt dieser den Wert aus der Datenbank von provider02.
10.1.2 | valsort |
Das valsort-Overlay dient dazu, Rückgaben von mehrwertigen Attributen auf- oder absteigend zu sortieren. Die Sortierung findet dabei auf dem Server zu dem Zeitpunkt statt, an welchem die Werte des Attributs abgefragt werden. Es findet also keine Manipulation der Daten in der Datenbank statt.
Kommen wir zu einem Beispiel. Die Mitgliedsliste eines Gruppenobjekts enthält die Namen von Benutzerobjekten. Ein Beispiel dafür finden Sie in Listing 10.8:
Listing 10.8 Suche mit der Standardreihenfolge
provider01:~ # ldapsearch -H ldap://localhost \ -D "cn=admin,dc=example,dc=net" \ -W ’(cn=it-staff)’ member -LLL dn: cn=it-staff,ou=groups,dc=example,dc=net member: cn=kania,ou=users,dc=example,dc=net member: cn=ollenburg,ou=users,dc=example,dc=net member: cn=schmidt,ou=users,dc=example,dc=net member: cn=meier,ou=users,dc=example,dc=net member: cn=schmitz,ou=users,dc=example,dc=net
Die Standardreihenfolge ist die der letzten Änderung. Mit dem valsort-Overlay können Sie nun die Reihenfolge bestimmen, beispielsweise auf- oder absteigend von a bis z oder z bis a. Ein mögliches Ergebnis der gleichen Suche wie in Listing 10.8 finden Sie in Listing 10.9:
Listing 10.9 Suche mit der geänderten Reihenfolge
provider01:~ # ldapsearch -H ldap://localhost \ -D "cn=admin,dc=example,dc=net" \ -W ’(cn=it-staff)’ member member: cn=kania,ou=users,,dc=example,dc=net member: cn=meier,ou=users,dc=example,dc=net member: cn=ollenburg,ou=users,,dc=example,dc=net member: cn=schmidt,ou=users,dc=example,dc=net member: cn=schmitz,ou=users,dc=example,dc=net
Die Konfiguration erfolgt dabei in einer Datenbank für das jeweilige Attribut, im obigen Beispiel also auf das Attribut member.
Zunächst schauen wir uns direkt die dynamische Konfiguration an. Nach dem Laden des Moduls (siehe Listing 10.10) bestimmen Sie für eine Datenbank die Sortierreihenfolge für einzelne Attribute, wie in Listing 10.11 an einem Beispiel gezeigt.
Listing 10.10 Laden des valsort-Moduls über OLC
dn: cn=module{0},dc=config changetype: modify add: olcModuleLoad olcModuleLoad: valsort.la
Listing 10.11 Konfiguration des valsort-Overlays über OLC
dn: olcOverlay=valsort,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcValSortConfig olcOverlay: valsort olcValSortAttr: member dc=example,dc=net alpha-ascend olcValSortAttr: givenName dc=example,dc=net alpha-ascend olcValSortAttr: postalCode dc=example,dc=net alpha-ascend
Für die Attribute member und givenName wird also für den ganzen Teilbaum dc=example, dc=net die Sortierreihenfolge alphanumerisch aufsteigend und für das Attribut postalCode die Reihenfolge numerisch aufsteigend gewählt.
Folgende Sortierungen sind möglich:
alpha-ascend
(für Zeichen und Zeichenketten) alphanumerisch aufsteigend
alpha-descend
(für Zeichen und Zeichenketten) alphanumerisch absteigend
numeric-ascend
(für Zahlenwerte) numerisch aufsteigend
numeric-descend
(für Zahlenwerte) numerisch absteigend
weighted
(für gewichtete Werte) Sind den Werten des Attributs Gewichtungen in Form{x} (wobei x ein numerischer Wert ist) vorangestellt, werden diese aufsteigend sortiert. Die Gewichtungen werden bei der Ausgabe unterdrückt und nicht ausgegeben.
Dieser Sortierung kann eine der vier anderen Sortierungen nachgestellt werden, um bei gleichen Gewichten eine Sortierung festzulegen.
Nehmen wir also an, wir wollten die Mitglieder der IT-Abteilung stets nach dem Wechsel der Kolleg/innen in das Unternehmen anzeigen lassen. Bringen Sie also die Mitgliedsliste der Gruppe cn=it-staff,ou=groups,dc=example,dc=net in die richtige historische Reihenfolge:
cn={1993}kania,ou=users,dc=example,dc=net
cn={2001}ollenburg,ou=users,dc=example,dc=net
cn={2019}schmidt,ou=users,dc=example,dc=net
cn={2005}meier,ou=users,dc=example,dc=net
cn={1989}schmitz,ou=users,dc=example,dc=net
Wurde für die Sortierreihenfolge zusätzlich festgelegt, dass es sich um eine gewichtete (weighted) Suche handeln soll:
valsort-attr member dc=example,dc=net weighted alpha-ascend, so liefert eine LDAP-Suche auf die Mitglieder dieser Liste folgendes Resultat:
Listing 10.12 Ausgabe einer gewichteten Liste
provider01:~ # ldapsearch -H ldap://localhost \ -D "cn=admin,dc=example,dc=net" \ -W ’(cn=it-staff)’ member -LLL dn: cn=it-staff,ou=groups,dc=example,dc=net member: cn=schmitz,ou=users,dc=example,dc=net member: cn=kania,ou=users,dc=example,dc=net member: cn=ollenburg,ou=users,dc=example,dc=net member: cn=meier,ou=users,dc=example,dc=net member: cn=schmidt,ou=users,dc=example,dc=net
Wie Sie sehen, wird die Gewichtung nicht mit ausgegeben. Wollen Sie die Gewichtung im Resultat anzeigen lassen, so können Sie dem ldapsearch-Befehl die Option -E 1.3.6.1.4.1.4203.666.5.14=::MAMBAf8= mitgeben (damit setzen Sie die erweiterte Suchoperation LDAP_CONTROL_VALSORT Ihrer Suche explizit auf die richtige Kodierung). Das Ergebnis finden Sie in Listing 10.13:
Listing 10.13 Ausgabe der Gewichtungen
provider:~ # ldapsearch -H ldap://localhost \ -D "cn=admin,dc=example,dc=net" \ -W ’(cn=it-staff)’ member -E 1.3.6.1.4.1.4203.666.5.14=::MAMBAf8= dn: cn=it-staff,ou=groups,dc=example,dc=net member: cn={1989}schmitz,ou=users,dc=example,dc=net member: cn={1993}kania,ou=users,dc=example,dc=net member: cn={2001}ollenburg,ou=users,dc=example,dc=net member: cn={2005}meier,ou=users,dc=example,dc=net member: cn={2019}schmidt,ou=users,dc=example,dc=net
Hinweis: Wenn Sie eine Gewichtung für Attribute einfügen, müssen zukünftig alle Attribute eine Gewichtung in dem jeweiligen Bereich Ihrer Datenbank besitzen. In unserem Fall müssten also sämtliche Attribute vom Type member im gesamten Kontext dc=example,dc=net eine Gewichtung erhalten.
Hinweis: Achten Sie bei der Festlegung der Sortierreihenfolge für ein Attribut auf den Datentyp. Eine numerische Sortierung bei Zeichenketten ergibt zum Beispiel wenig Sinn.
10.1.3 | deref |
Das Overlay deref bietet Ihnen die Möglichkeit, bei Suchen zusätzliche Informationen zu erhalten, die im gefundenen Objekt direkt nicht enthalten sind, dieses Objekt aber auf ein anderes Objekt verweist, welches die weiteren Attribute besitzt.
Ein Beispiel dafür wäre, dass Sie sich die Mitglieder einer Gruppe anzeigen lassen wollen, aber sich zusätzlich in dieser Suche auch die Vor- und Nachnamen der Mitglieder zurückgeben lassen wollen. Das Gruppenobjekt besitzt lediglich das member-Attribut. Dessen Werte allerdings sind ja die jeweiligen DN der Objekte der Mitglieder. In diesen wiederum finden sich die gesuchten Attribute givenName und sn. In der Suche per ldapsearch können Sie – nach dem Laden des Overlays deref – die Suchergebnisse über eine erweiterte Operation erweitern. Dazu ergänzen Sie die Suche um den Parameter -E ’deref=member:givenName,sn’.
10.1.3.1 | Einrichtung von deref |
Zum Laden des Moduls können Sie die folgende LDIF-Datei verwenden:
Listing 10.14 Laden des Moduls deref
dn: cn=module{0},cn=config changetype: modify add: olcModuleload olcModuleload: deref.la
Nun muss das Overlay noch für die Datenbank aktiviert werden. Dies lässt sich mit einer LDIF-Datei wie der folgenden realisieren:
Das Overlay besitzt keine weiteren Parameter, da sie die gesuchten zusätzlichen Attribute in der späteren Suche angeben.
10.1.3.2 | Verwenden von dereferenzierten Suchen |
Nehmen wir das oben begonnene Beispiel auf und verwenden dafür eine Gruppe cn= allusers,ou=groups,dc=example,dc=net. Als Mitglieder seien in dieser Gruppe zum Beispiel die Benutzer cn=userA,ou=users,dc=example,dc=net und cn=userB,ou=users,dc=example, dc=net eingetragen.
Listing 10.15 Benutzer und Gruppe für deref
dn: cn=user_A,ou=users,dc=example,dc=net objectClass: inetOrgPerson givenName: Anna cn: user_A sn: User dn: cn=user_B,ou=users,dc=example,dc=net objectClass: inetOrgPerson givenName: Berta cn: user_B sn: User dn: cn=allusers,ou=groups,dc=example,dc=net objectClass: groupOfNames member: cn=user_A,ou=users,dc=example,dc=net member: cn=user_B,ou=users,dc=example,dc=net cn: allusers
In Listing 10.16 sehen Sie das Ergebnis einer Suche ohne Verwendung einer Derefenzierung:
Listing 10.16 Herkömmliche Suche ohne deref
provider01:~# ldapsearch -D cn=admin,dc=example,dc=net -H ldap://provider01 -x -w geheim -b dc=example,dc=net ’(cn=allusers)’ -LLL dn: cn=allusers,ou=groups,dc=example,dc=net member: cn=user_A,ou=users,dc=example,dc=net member: cn=user_B,ou=users,dc=example,dc=net cn: allusers objectClass: groupOfNames objectClass: top
Führen wir die Suche nach der Gruppe nun mit der entsprechenden deref-Erweiterung durch, erhalten Sie, wie in Listing 10.17 zu sehen, die gewünschten zusätzlichen Informationen:
Listing 10.17 Suche mit deref
provider01:~# ldapsearch -D cn=admin,dc=example,dc=net -H ldap://provider01 -x -w geheim -b dc=example,dc=net ’(cn=allusers)’ -LLL -E deref=member:givenName,sn dn: cn=allusers,ou=groups,dc=example,dc=net # member: <givenName=Anna>;<sn=User>;cn=user_A,ou=users,dc=example,dc=net # member: <givenName=Berta>;<sn=User>;cn=user_B,ou=users,dc=example,dc=net member: cn=user_A,ou=users,dc=example,dc=net member: cn=user_B,ou=users,dc=example,dc=net cn: allusers objectClass: groupOfNames objectClass: top
10.2 | Datenmanipulation |
In diesem Abschnitt sollen einige Overlays beschrieben werden, mit denen Objektdaten in einer Datenbank manipuliert werden.
10.2.1 | memberOf |
Tragen Sie Benutzer in Gruppen als Mitglieder ein, hilft Ihnen das Overlay memberof , bei den jeweiligen Benutzern das operationale Attribut memberOf mit dem Gruppennamen zu füllen. So versetzen Sie sich in die Lage, beim Benutzer auslesen zu können, zu welchen Gruppen das Objekt gehört.
Hinweis: Das Overlay memberof besitzt seit der aktuellen Version 2.5 den Status deprecated. Für Umgebungen mit einer Replikation wird zudem vom Einsatz dieses Overlays abgeraten. Empfohlen wird stattdessen der Einsatz des Overlays dynlist (siehe Abschnitt 10.2.2).
Das Overlay benötigt immer eine Gruppe, die ein Attribut mit einem vollständigen DN besitzt. Die DN-Syntax für das Attribut ist die 1.3.6.1.4.1.1466.115.121.1.12 oder 1.3.6.1.4.1.1466.115.121.1.34.
Hinweis: Gruppen vom Typ GroupOfURLs können nicht zusammen mit dem Overlay memberof genutzt werden, da diese Objektklasse kein Attribut besitzt, in welchem der DN eines Objekts abgelegt werden kann. Deren member-Attribut wird ja erst beim Zugriff auf das Objekt mit den Ergebnissen einer LDAP-Suche gefüllt.
Die LDIF-Datei, mit der Sie die eine Konfiguration dynamisch über OLC hinzufügen können, finden Sie in Listing 10.18. Nach dem Laden des Moduls werden zwei Konfigurationen für das Overlay für die beiden Klassen groupOfNames und groupOfUniqueNames eingerichtet.
Listing 10.18 Dynamische Konfiguration von memberOf
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: memberof.la dn: olcOverlay=memberof,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcMemberOf objectClass: olcOverlayConfig olcOverlay: memberof olcMemberOfGroupOC: groupOfNames olcMemberOfMemberAD: member olcMemberOfDangling: error olcMemberOfRefInt: TRUE dn: olcOverlay=memberof,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcMemberOf objectClass: olcOverlayConfig olcOverlay: memberof olcMemberOfGroupOC: groupOfUniqueNames olcMemberOfMemberAD: uniqueMember olcMemberOfDangling: error olcMemberOfRefInt: TRUE
Die Parameter haben dabei die folgende Bedeutung:
1. olcMemberOfGroupOC
Über dieses Attribut wird der Gruppentyp festgelegt. Der Default-Wert ist hier groupOfNames.
2. olcMemberOfMemberAD
Hier wird festgelegt, welches Attribut der Gruppe beobachtet werden soll. Wichtig ist hier, dass das Attribut einen kompletten DN speichert. Der Default-Wert für diesen Parameter ist member.
3. olcMemberOfDangling
Dieser Parameter ist sehr hilfreich, wenn Sie den DN eines Benutzers von Hand eintragen. Denn hier wird der DN überprüft und entsprechend der Einstellung des Parameters reagiert. Der Parameter kann folgende Werte annehmen:
(a) ignore
Fehler werden ignoriert, und der falsche DN wird in die Gruppe eingetragen. Das ist auch das Standardverhalten.
(b) drop
Der falsche DN wird nicht eingetragen, und es gibt auch keine Fehlermeldung.
(c) error
Hier wird eine Fehlermeldung ausgeworfen, die auf den falschen DN hinweist. Die Standardmeldung ist eine Constraint violation.
4. olcMemberOfRefInt
Ja, auch das Overlay memberOf kann für die referentielle Integrität sorgen.
Wie Sie hier sehen, wird das Overlay zweimal konfiguriert. Das ist auch richtig so, denn Sie können das Overlay immer nur für einen Gruppentyp konfigurieren. Wollen Sie mehrere Gruppentypen konfigurieren, müssen Sie für jeden Typ eine eigene Konfiguration erstellen.
Legen Sie jetzt
eine Benutzerin cn=demouser,ou=users,dc=example,dc=net und
eine Gruppe cn=demogruppe,ou=groups,dc=example,dc=net
an und fügen Sie demouser anschließend der demogroup hinzu. Kontrollieren Sie dann, wie sich das im Anschluss auf das Benutzerobjekt auswirkt. Anhand von Listing 10.19 können Sie die Schritte nachverfolgen:
Listing 10.19 Interne Attribute eines Demousers
provider01:~# ldapadd -D "cn=admin,dc=example,dc=net" -wgeheim dn: cn=demouser,ou=users,dc=example,dc=net objectClass: inetOrgPerson cn: demouser sn: User givenName: Demo adding new entry "cn=demouser,ou=users,dc=example,dc=net" dn: cn=demogroup,ou=groups,dc=example,dc=net objectClass: groupOfNames cn: demogroup member: cn=demouser,ou=users,dc=example,dc=net adding new entry "cn=demogroup,ou=groups,dc=example,dc=net" provider01:~ # ldapsearch -D "cn=admin,dc=example,dc=net" -wgeheim \ ’(cn=demouser)’ -LLL givenName sn + dn: cn=demouser,ou=users,dc=example,dc=net sn: User structuralObjectClass: inetOrgPerson entryUUID: 63957b7c-9f36-1039-8073-b712325e471e creatorsName: cn=admin,dc=example,dc=net createTimestamp: 20221119163549Z memberOf: cn=demogroup,ou=groups,dc=example,dc=net givenName: Demo entryCSN: 20221119164117.493849Z#000000#000#000000 modifiersName: cn=admin,dc=example,dc=net modifyTimestamp: 20221119164117Z entryDN: cn=demouser,ou=users,dc=example,dc=net subschemaSubentry: cn=Subschema hasSubordinates: FALSE
Hier sehen Sie den zusätzlichen memberOf -Eintrag für die Gruppe. So können Sie jetzt über eine gezielte Suche feststellen, in welchen Gruppen ein DN eingetragen ist.
Hinweis: Achten Sie auf das Plus-Symbol (+) beim ldapsearch-Befehl. Das Attribut memberOf ist ein operationales Attribut und wird bei einer Suchoperation standardmäßig nicht mit ausgegeben.
Ein Problem ergibt sich, wenn Sie das Modul erst aktivieren, wenn bereits Gruppen mit Mitgliedern in Ihrem Verzeichnis vorhanden sind. Diese werden von dem Overlay nicht nachträglich durchsucht und die entsprechenden Benutzerobjekte aktualisiert. Dies geschieht ausschließlich bei Änderungen an einem Gruppenobjekt, wenn ein Benutzerobjekt hinzugefügt oder gelöscht wird. Dazu müssen Sie sich eines Skripts bedienen, welches die Gruppenobjekte im Verzeichnis nach Mitgliedern durchsucht und die entsprechenden Benutzerobjekte aktualisiert. Ein Beispiel für solch ein Skript findet Sie in Listing 10.20. Nachdem Sie Ihre Anmeldenamen und dessen Kennwort eingegeben haben, werden die Mitglieder aller Gruppen einmal gelöscht und wieder hinzugefügt. Damit wird auch das operationale Attribut memberOf der jeweiligen Benutzer aktualisiert.
Listing 10.20 Skript zum Aktualisieren des memberOf-Attributs
#!/bin/bash echo -n "Bitte geben sie den DN des Administratorkontos an : " read ADM echo -n "Bitte geben sie das Kennwort zur LDAP-Authentifizierung ein : " read PASS for GRP in ‘ldapsearch -D "$ADM" -w$PASS -b "dc=example,dc=net" \ ’(objectClass=groupOfNames)’ -LLL dn|grep "^dn:"|sed s/"dn: "//‘ do for MEMBER in ‘ldapsearch -D "$ADM" -w$PASS -b $GRP -LLL \ member|grep "^member:"|sed s/"member: "//g‘ do ldapmodify -D "$ADM" -w$PASS << EOF dn: $GRP changetype: modify delete: member member: $MEMBER dn: $GRP changetype: modify add: member member: $MEMBER EOF done done
10.2.2 | dynlist |
Mit dem dynlist-Overlay können Sie das Attribut einer Klasse dynamisch gestalten, d. h. anstatt bei einer Instanz eines Objektes statische Werte in ein Attribut einzutragen, können Sie diesen Wert als Suchfilter definieren. Bei jedem Abruf dieses Attributs erhalten Sie dann als Wert das Ergebnis dieser Suche zurück.
Seinen Einsatz findet dieses Overlay häufig im Fall von dynamischen Gruppen. Insbesondere in großen und sich häufig ändernden Umgebungen (Benutzer/innen wechseln beispielsweise das Team oder die Abteilung) kann die Pflege der einzelnen Gruppen eine zeitaufwendige Sache werden. Damit Sie die Liste der Gruppenmitglieder nicht dauernd manuell pflegen müssen und sich diese Liste dynamisch ändert, kann das Overlay dynlist diese Aufgabe übernehmen. Dabei wird die Gruppenmitgliedschaft durch Eigenschaften des Benutzerobjekts geregelt. So können Sie beispielsweise einen Benutzer dynamisch in eine Gruppe Ingenieure aufnehmen, sobald dessen Attribut employeeType den Wert Ingenieur enthält.
In diesem Abschnitt werden wir das dynlist-Overlay im Zusammenhang mit eben diesen dynamischen Gruppen einrichten. Dazu verwenden wir statt der Klasse groupOfNames die Objektklasse GroupOfURLs. Diese Klasse besitzt das Attribut memberURL. Daher müssen Sie das Schema zunächst um die Klasse groupOfURLs erweitern. Dieses Attribut member-URL erhält als Wert eine LDAP-Suche in Form einer URI. Ein Beispiel hierfür wäre:
ldap:///dc=example,dc=net?dn?sub?(employeeType=Ingenieur),
also eine Suche nach allen Objekten unterhalb des Kontextes dc=example,dc=net, deren Attribut employeeType den Wert Ingenieur besitzt. Als Rückgabe wird dann das Attribut dn dieser Objekte geliefert. In Bild 10.1 ist dies schematisch dargestellt.
Bild 10.1 Ablauf einer Anfrage nach Mitgliedern einer dynamischen Gruppe
Die Schemaerweiterung können Sie durch den folgenden Befehl aus Listing 10.21 erreichen:
Listing 10.21 Schemaerweiterung für dynlist
slapadd -b cn=config -l /opt/symas/etc/openldapschema/dyngroup.ldif
Erinnerung: Denken Sie daran, dass mit diesem Befehl die LDIF-Datei unter dem Benutzer nach /opt/symas/etc/openldap/slapd.d/cn=config/cn=schema/ kopiert wird, mit dem Sie gerade angemeldet sind. Tun Sie das also als Benutzer root, so kann der slapd-Daemon, welcher ja als Benutzer openldap läuft, nicht darauf zugreifen. Daher sollte der Befehl also entweder mit sudo -u openldap vorangestellt ausgeführt werden oder Sie müssten im Anschluss mit chown die Rechte nachjustieren.
Als Nächstes können Sie nun das entsprechende Modul laden. Das Listing 10.22 zeigt eine passende LDIF-Datei.
Listing 10.22 Laden des dynlist-Moduls
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: dynlist.la
Nun können Sie die datenbankspezifische Konfiguration des Overlays erstellen. Diese Konfiguration definiert für eine Objektklasse (in unserem Fall groupOfURLs) das Attribut, welches eine LDAP-Such-URI enthält (hier also memberURL) und unter welchem Attributsnamen die Werte zurückgegeben werden sollen (in unserem Beispiel owner). Sie können dazu die LDIF-Datei aus Listing 10.23 verwenden:
Listing 10.23 Einrichtung von dynlist
dn: olcOverlay=dynlist,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcDynamicList objectClass: olcOverlayConfig olcOverlay: dynlist olcDlAttrSet: groupOfURLs memberURL
Im vorliegenden Beispiel wird also festgelegt, dass das Attribut memberURL von Objekten der Klasse groupOfURLs in der Datenbank eine Such-URI enthalten wird. Damit erhalten Sie eine dynamische Liste.
Nehmen wir als Beispiel eine Mailingliste. Legen wir einen Benutzer mit einer E-Mail-Adresse wie in Listing 10.24 an.
Listing 10.24 Anlegen eines Benutzers mit einer Mailadresse
dn: cn=ing-1,ou=users,dc=example,dc=net objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person cn: ing-1 userPassword: {ARGON2}$argon2i$v=19$m=4096,t=3,p=1$ZGJmZGRkc3NzMTIzNDg$0t \ RScpmdeUoX14JfH6SWf7mtx6sjL30vFR+IeVgmiK8 sn: Ingenieur mail: ing-1@example.net employeeType: Ingenieur
Als Nächstes legen Sie nun eine dynamische Liste an, welche die Mail-Adresse aller Ihrer Ingenieure zurückliefern soll. In Listing 10.25 sehen Sie ein Beispiel dafür.
Listing 10.25 Anlegen einer Mailingliste für Ingenieure
dn: cn=Mailingliste,ou=groups,dc=example,dc=net objectClass: groupOfURLs cn: Mailingliste memberURL: ldap:///dc=example,dc=net?mail?sub?(employeeType=Ingenieur)
Im Attribut memberURL ist die benötigte Suche hinterlegt. Diese durchsucht den Kontext dc=example,dc=net und den Teilbaum darunter nach Objekten, bei welchen das Attribut employeeType den von uns gewünschten Wert Ingenieur enthält, und gibt als Ergebnis den Wert des Attributes mail zurück. Eine Abfrage per ldapsearch liefert Ihnen nun das erwartete Ergebnis, wie in Listing 10.26 gezeigt:
Listing 10.26 Ergebnis einer dynamischen Liste
root@provider01:~# ldapsearch -D cn=admin,dc=example,dc=net -x -W \ -H ldap://localhost -b dc=example,dc=net ’(cn=Mailingliste)’ dn: cn=Mailingliste,ou=groups,dc=example,dc=net objectClass: groupOfURLs cn: Mailingliste memberURL: ldap:///dc=example,dc=net?mail?sub?(employeeType=Ingenieur) mail: ing-1@example.net
Hinweis: Das jeweilige Attribut, welches in einer dynamischen Liste als angezeigter Wert Verwendung findet, wird in der Datenbank nicht geändert. Sie erhalten beim Zugriff auf das Objekt für dieses Attribut diejenigen Werte, die zu diesem Zeitpunkt als das Ergebnis der jeweiligen Abfrage aus der Datenbank zurückgegeben werden.
Sollen die zurückgegebenen Attribute unter dem Namen eines anderen Attributs angezeigt werden, so können Sie die Konfiguration des Attributs olcDlAttrSet aus Listing 10.23 anpassen. Geben Sie dort als dritten Wert eine Zuordnung in der Form Anzeigeattribut:Suchattribut an. Besitzen also die Benutzer im Feld description ihre Mailadresse, so würde sich das Attribut olcDlAttrSet wie folgt ändern:
Listing 10.27 Geänderte Zuordnung des Rückgabewertes
olcDlAttrSet: groupOfURLs memberURL mail:description
10.2.2.1 | Dynamische Gruppen |
Darüber hinaus lassen sich mit dynlist auch dynamische Gruppen realisieren. Dazu fügen Sie dem Attribut olcDlAttrSet aus Listing 10.23 als dritten Wert member an. Damit werden die durch die memberURL zurückgegebenen Objektnamen(DN) als member angezeigt. Listing 10.28 zeigt Ihnen die angepasste Konfiguration des Overlays:
Listing 10.28 Konfiguration für dynamische Gruppen
dn: olcOverlay=dynlist,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcDynamicList objectClass: olcOverlayConfig olcOverlay: dynlist olcDlAttrSet: groupOfURLs memberURL member
Legen Sie zum Testen nun ein Objekt der Klasse groupOfURLs wie in Listing 10.29 an:
Listing 10.29 Einrichtung einer dynamischen Gruppe
dn: cn=Ingenieure,ou=groups,dc=example,dc=net objectClass: groupOfURLs cn: Ingenieure memberURL: ldap:///dc=example,dc=net??sub?(employeeType=Ingenieur)
In dem Beispiel wird also kein spezielles Attribut wie mail aus Listing 10.24 zurückgegeben. Mit der angepassten Konfiguration aus Listing 10.28 liefert die Suche dann die gewünschte Liste von Mitgliedern.
Listing 10.30 Rückgabe einer dynamischen Gruppe
root@provider01:~# ldapsearch -D cn=admin,dc=example,dc=net -x -W \ -H ldap://localhost -b dc=example,dc=net ’(cn=Ingenieure)’ dn: cn=Ingenieure,ou=groups,dc=example,dc=net cn: Ingenieure objectClass: groupOfURLs memberURL: ldap:///dc=example,dc=net??sub?(employeeType=Ingenieur) member: cn=ing-1,ou=users,dc=example,dc=net
Nun gibt es zwar eine dynamische Gruppe von Benutzern, aber in den Benutzerobjekten ist nicht ersichtlich, in welchen Gruppen diese Mitglied sind. Dazu benötigen wir nur noch eine Ergänzung in der Konfiguration des Overlays aus Listing 10.28. Das Attribut olcDlAttr-Set wird ein weiteres Mal ergänzt. Hinzugefügt wird nun jenes Attribut der gefundenen Objekte, in welchem die Namen der dynamischen Gruppen hinterlegt werden sollen, in denen das Objekt als Mitglied aufgelistet wird. Dies wird für gewöhnlich das (operationale) Attribut memberOf eines Benutzerobjekts sein. Wird ein Benutzer also Mitglied (member) einer dynamischen Gruppe, so wird deren Name beim Benutzerobjekt unter memberOf eingetragen. Wenn Sie diese Funktionalität nun nicht nur für dynamische Gruppen, sondern auch statische Gruppen der Klasse groupOfNames bekommen möchten, so geben Sie zusätzlich auch noch deren Klassennamen mit an. Im Beispiel von Listing 10.31 wird genau dies umgesetzt:
Listing 10.31 Konfiguration für dynamische Gruppen
dn: olcOverlay=dynlist,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcDynamicList objectClass: olcOverlayConfig olcOverlay: dynlist olcDlAttrSet: groupOfURLs memberURL member+memberOf@groupOfNames
Wichtig: Mit der letzten Änderung erreichen Sie den gleichen Effekt wie mit der Einrichtung des (veralteten) Overlays memberof (siehe Abschnitt 10.2.1).
10.2.3 | refint |
Mit dem Overlay refint wird die referenzielle Integrität einer Datenbank geprüft und gewährleistet, d. h. Verweise auf Objekte in der Datenbank werden kontrolliert und korrigiert, falls etwas am Objekt geändert wird.
Ein klassisches Beispiel sind Gruppen bzw. Gruppenmitgliedschaften. Das Hinzufügen eines Benutzers zu einer Gruppe führt zum Eintrag des DNs des Benutzerobjekts in das Attribut member der Gruppe. Wird der DN umbenannt, weil sich der RDN oder der Kontext des Objekts ändert, oder wird der Benutzer gelöscht, dann würde der member-Eintrag im Gruppenobjekt ungültig. Das Overlay refint hilft genau an dieser Stelle, indem es beim Erstellen einer Referenz auf ein Objekt eine Art Rückverweis aus dem referenzierenden das referenzierte Objekt erstellt. Ändert sich nun das Objekt, so ändert sich auch der entsprechende Eintrag. Im Fall der Gruppe würde sich der entsprechende member-Eintrag ändern, wenn sich am DN des Mitglieds etwas ändert.
Ein kurzes Beispiel: Nehmen wir eine Gruppe cn=personalrat,ou=groups,dc=example, dc=net mit dem Mitglied cn=meier,ou=users,dc=example,dc=net. Der DN des Benutzers steht also als Wert im member-Attribut der Gruppe. Heiratet der Benutzer und ändert seinen Namen, so ändert sich eventuell auch dessen Benutzerobjekt, beispielsweise in cn=schneider,ou=users,dc=example,dc=net. Ohne das refint-Overlay würde das member-Attribut damit einen falschen Wert enthalten. Mit dem Overlay wird bei der Änderung am (referenzierten) Benutzerobjekt automatisch auch eine Änderung an dem (referenzierenden) Gruppenobjekt durchgeführt und das member-Attribut aktualisiert, so wie Sie es in Bild 10.2 sehen.
Bild 10.2 Referenzielle Integrität
Natürlich können Sie alle Gruppen vom Typ GroupOfUniqueNames, GroupOfNames und GroupOfURLs immer auch dynamisch mit dem Overlay dynlist (s. u.) erstellen, aber in großen Verzeichnisbäumen ist es oft sinnvoll, bestimmte Gruppen statisch zu verwalten. Das Problem mit dynamisch erzeugten Objekten ist deren Ressourcennutzung, da zur Änderung der Gruppen immer der Verzeichnisbaum durchsucht werden muss. In größeren Bäumen sollten Sie daher stets abwägen, ob Sie eine Gruppe statisch oder dynamisch verwalten wollen.
Damit wir das Overlay testen können, sollen als Erstes verschiedene Objekte vom Typ GroupOfUniqueNames, GroupOfNames und GroupOfURLs angelegt werden.
Hinweis: Denken Sie daran, dass Sie für die Erstellung von Objekten des Typs GroupOfURLs das entsprechende Schema dyngroup.ldif einbinden müssen, beispielsweise mit einem Befehl wie ldapadd -D cn=admin,dc=example,dc=net -W -f /opt/symas/etc/openldap/schema/dyngroup.ldif.
Damit Sie die Objekte nicht alle von Hand anlegen müssen, nutzen Sie die LDIF-Datei first.ldif mit dem Inhalt aus Listing 10.32:
Listing 10.32 LDIF für die ersten Objekte
dn: cn=benutzer,ou=groups,dc=example,dc=net objectClass: posixGroup gidNumber: 10000 cn: benutzer dn: uid=u1,ou=users,dc=example,dc=net objectClass: posixAccount objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person loginShell: /bin/bash homeDirectory: /home/u1 gidNumber: 10000 uid: u1 cn: user 1 userPassword:: $argon2i$v=19$m=4096,t=3,p=1$4oCdc2FsdHNhbHRzYWx0c2FsdOKAnQ$lkpaRI/mgLUwziwi/3/PRKxoRHrBoEfwg1RB+Inwqgc uidNumber: 10000 sn: 1 givenName: user dn: uid=u2,ou=users,dc=example,dc=net objectClass: posixAccount objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person loginShell: /bin/bash homeDirectory: /home/u2 gidNumber: 10000 uid: u2 cn: User 2 userPassword:: $argon2i$v=19$m=4096,t=3,p=1$4oCdc2FsdHNhbHRzYWx0c2FsdHnigJ0$gfNbRryMdQMuy035XsscaLR1WpuM3JfSLF5SICOeniI= uidNumber: 10001 sn: 2 givenName: User dn: uid=u3,ou=users,dc=example,dc=net objectClass: posixAccount objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person loginShell: /bin/bash homeDirectory: /home/u3 gidNumber: 10000 uid: u3 cn: User 3 userPassword:: $argon2i$v=19$m=4096,t=3,p=1$4oCdc2FsdHNhbHRzYWx0eXNhbHR54oCd$ZWG6w6/PeJNlqjsgwT2X3JH1F02M/UEu/mvBLoWZQPk= uidNumber: 10002 sn: 3 givenName: User dn: uid=u4,ou=users,dc=example,dc=net objectClass: posixAccount objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person loginShell: /bin/bash homeDirectory: /home/u4 gidNumber: 10000 uid: u4 cn: User 4 userPassword:: $argon2i$v=19$m=4096,t=3,p=1$4oCdc2FsdHNhbHR5c2FsdHlzYWx0eeKAnQ$njk04Ufc9ZSmzB68gAok6s9hF2H7aNqXAcGQoD/tyso= uidNumber: 10003 sn: 4 givenName: User dn: uid=u5,ou=users,dc=example,dc=net objectClass: posixAccount objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person loginShell: /bin/bash homeDirectory: /home/u5 gidNumber: 10000 uid: u5 cn: User 5 userPassword:: $argon2i$v=19$m=4096,t=3,p=1$4oCdc2FsdHlzYWx0eXNhbHR5c2FsdHnigJ0$uCWTCFCsYF847+xen2x2EuL1eU8d8kdl9SFzZ7gtZ4I= uidNumber: 10004 sn: 5 givenName: User dn: cn=Namen,ou=groups,dc=example,dc=net cn: Namen objectClass: groupOfNames member: uid=u1,ou=users,dc=example,dc=net dn: cn=unique,ou=groups,dc=example,dc=net cn: unique objectClass: groupOfUniqueNames uniqueMember: uid=u2,ou=users,dc=example,dc=net dn: cn=urls,ou=groups,dc=example,dc=net cn: urls objectClass: groupOfURLs memberURL: uid=u3,ou=users,dc=example,dc=net
Hier werden neben den benötigten Gruppen auch gleich die Benutzer angelegt und als Mitglieder in den Gruppen eingetragen. Alle Benutzer aus dem LDIF haben das Passwort geheim.
Wie Sie an dem LDIF sehen, müssen Sie beim Anlegen der Objekte vom Typ GroupOfUniqueNames und GroupOfNames mindestens einen Benutzer beim Anlegen der Gruppe zuordnen. Gemäß der Schemadefinition kann eine Gruppe dieses Typs nie ohne Mitglieder existieren. Hier empfiehlt es sich, eventuell immer einen Dummy-Account quasi als Platzhalter zu erstellen. Anders bei einer Gruppe vom Typ GroupOfURLs, welche auch ohne die Zuweisung eines Mitglieds erstellt werden kann.
Die dynamische Konfiguration entnehmen Sie dem Listing 10.33:
Listing 10.33 Dynamische Konfiguration von refint
dn: cn=module{0},cn=config changetype: modify add: olcModuleload olcModuleload: refint.la dn: olcOverlay=refint,olcDatabase={2}mdb,cn=config objectClass: olcOverlayConfig objectClass: olcRefintConfig olcOverlay: refint olcRefintAttribute: memberURL uniqueMember member olcRefintNothing: cn=dummy,ou=users,dc=example,dc=net
In Listing 10.33 sehen Sie die Zeile olcRefintNothing: cn=dummy,ou=users,dc=example,dc=net. Dieser Eintrag sorgt dafür, dass es keine Gruppe ohne Mitglieder gibt. Wie oben beschrieben, müssen die beiden Objekte GroupOfNames und GroupOfUniqueNames immer mindestens ein Mitglied haben.
Löschen Sie jetzt den letzten Benutzer der Gruppe, wird das Overlay als Mitglied den vorgegebenen Namen als Mitglied eintragen. Der Name muss ein gültiger DN sein, das Objekt selbst muss aber nicht im Verzeichnisbaum existieren. Wenn Sie neue Mitglieder in die Gruppe eintragen, müssen Sie den Dummy-Eintrag händisch entfernen.
Wie können Sie nun sehen, ob ein Gruppenobjekt vom refint-Overlay verändert wurde? Dazu müssen Sie sich die internen Attribute der Gruppe ansehen: Dort wird nach einer solchen Änderung dann als modifiersName der Wert cn=Referential Integrity Overlay eingetragen. Listing 10.34 zeigt diese Attribute:
Listing 10.34 Liste der internen Attribute
root@provider01:~# ldapsearch -D cn=admin,dc=example,dc=net -w geheim \ # -b dc=example,dc=net ’(cn=Namen)’ -LLL + dn: cn=Namen,ou=groups,dc=example,dc=net structuralObjectClass: groupOfNames entryUUID: 345942a0-50f8-1037-9b86-fff2818e7f58 creatorsName: cn=admin,dc=example,dc=net createTimestamp: 20221029132415Z entryCSN: 20221029145958.037873Z#000000#000#000000 modifyTimestamp: 20221029145958Z modifiersName: cn=Referential Integrity Overlay entryDN: cn=Namen,ou=groups,dc=example,dc=net subschemaSubentry: cn=Subschema hasSubordinates: FALSE
Wollen Sie den Namen des Attributs modifiersName ändern, können Sie das über den Parameter olcRefintModifiersName in der Konfiguration des Overlays realisieren. Der Wert für das Attribut muss ein Distinguished Name sein, wobei das Objekt nicht existieren muss. In Listing 10.35 sehen Sie ein Beispiel, wie Sie das Overlay entsprechend abändern können.
Listing 10.35 Änderung des Modifiers
dn: olcOverlay={2}refint,olcDatabase={2}mdb,cn=config changetype: modify add: olcRefintModifiersName olcRefintModifiersName: cn=refint,dc=example,dc=net
Damit sieht das Ergebnis dann wie folgt aus:
Listing 10.36 Rückgabe des geänderten Modifiers
root@provider01:~# ldapsearch -D cn=admin,dc=example,dc=net -w geheim \ # -b dc=example,dc=net ’(cn=Namen)’ -LLL + dn: cn=Namen,ou=groups,dc=example,dc=net structuralObjectClass: groupOfNames entryUUID: 345942a0-50f8-1037-9b86-fff2818e7f58 creatorsName: cn=admin,dc=example,dc=net createTimestamp: 20221035105378Z entryCSN: 20221035105378.137454Z#000000#000#000000 modifyTimestamp: 20221035105378Z modifiersName: cn=refint,dc=example,dc=net entryDN: cn=Namen,ou=groups,dc=example,dc=net subschemaSubentry: cn=Subschema hasSubordinates: FALSE
Hinweis: Der LAM prüft intern, ob ein Objekt, das gelöscht werden soll, zu den entsprechenden Gruppentypen gehört, und löscht sie aus der Gruppe. Zudem prüft der LAM, ob Sie das letzte Mitglied einer Gruppe löschen, die ohne Mitglieder nicht existieren kann. Wenn das der Fall ist, verweigert der LAM das Löschen der Gruppe mit einer entsprechenden Fehlermeldung. Das Overlay refint wird beim Einsatz des LAM nicht berücksichtigt!
Einen wichtigen Punkt müssen Sie noch bedenken: Das Löschen der Mitglieder mittels des Overlays refint wird bei einer Replikation NICHT auf die Slave-Server repliziert. Das bedeutet, Sie müssen das Overlay auf allen LDAP-Servern einrichten.
Jetzt werden alle Gruppen, in denen DNs als Mitgliedsname verwendet werden, automatisch aktualisiert.
10.2.4 | unique |
Das unique-Overlay sorgt dafür, dass der Wert eines Attributs innerhalb einer Datenbank (entweder im gesamten Baum oder einem Teilbaum) eindeutig ist. Ein gutes Beispiel für die Nutzung des Overlays unique ist das Attribut mail. In diesem Attribut können Sie die Mail-Adresse eines Benutzers hinterlegen. Nur besitzen Benutzer häufig nicht nur eine, sondern mehrere Mail-Adressen. In der Praxis kommen gern noch Mail-Adressen einer oder mehrerer Funktionen oder von bestimmten Projekten hinzu. Dabei kommt es dann irgendwann dazu, dass Mail-Adressen doppelt eingetragen werden. Mithilfe von valsort können Sie das Attribut zwar sortieren und damit vielleicht einen doppelten Eintrag schneller finden, aber schöner wäre es doch, wenn der Server darauf achtet, dass ein doppelter Eintrag gar nicht erst möglich ist. Genau dafür ist das Overlay unique verantwortlich. In der aktuellen Version wurde das Overlay zudem dahingehend überarbeitet, sogenannte Race Conditions zu vermeiden. Dabei wird die Datenbank gesperrt, sobald eine Änderung an einem unique-Attribut vorgenommen wird. Damit kann vermieden werden, dass zwei Objekte gleichzeitig den identischen Wert in dem jeweiligen Attribut erhalten.
Die Einrichtung des Overlays ist relativ einfach. Wenn Sie das Overlay konfigurieren, denken Sie wieder daran, dass das entsprechende Modul geladen werden muss. Die Attribute, welche später in der Datenbank eindeutig sein sollen, definieren Sie über LDAP-URIs.
Für die dynamische Konfiguration können Sie die LDIF-Dateien aus Listing 10.37 verwenden:
Listing 10.37 Dynamische Konfiguration von refint
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: unique.la dn: olcOverlay=unique,olcDatabase={2}mdb,cn=config objectClass: olcUniqueConfig olcOverlay: unique olcUniqueURI: ldap:///dc=example,dc=net?uid?sub
Nach dem Aktivieren des Overlays sorgt der Parameter olcUniqueURI dafür, dass ein Wert für das Attribut uid im gesamten LDAP-Verzeichnis nicht mehrfach auftreten kann und somit keine doppelten Anmeldenamen vergeben werden können.
Sollten Sie versuchen, eines der Attribute bei zwei unterschiedlichen Objekten mit einem identischen Wert zu belegen, erhalten Sie die Fehlermeldung RESULT tag=103 err=19 text=some attributes not unique im Log. Auch der LAM oder das Apache Directory Studio werden beim Versuch, eines der Attribute einem schon vorhandenen Wert zuzuweisen, eine entsprechende Fehlermeldung ausgeben.
Versuchen Sie daher, zwei Benutzer mit derselben UID in unterschiedlichen OUs anzulegen. Als Erstes können Sie zum Beispiel einen Benutzer wie in Listing 10.38 anlegen.
Listing 10.38 Bestehender Benutzer
dn: uid=chef,ou=users,ou=produktion,ou=firma,dc=example,dc=net objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson sn: Eins givenName: User uid: chef cn: Chef
Wenn Sie jetzt versuchen, die folgende LDIF-Datei aus Listing 10.39 zu importieren,
Listing 10.39 Zu importierender Benutzer mit gleicher UID
dn: uid=chef,ou=users,ou=verwaltung,ou=firma,dc=example,dc=net objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson sn: Zwei givenName: User uid: chef cn: Chef
wird das zu einem Fehler führen, wie Listing 10.40 zeigt:
Listing 10.40 Erwarteter Fehler beim Import
provider01:~ # ldapadd -D "cn=admin,dc=example,dc=net" -W -f userzwei.ldif adding new entry "uid=chef,ou=users,ou=Verwaltung,dc=example,dc=net" ldap_add: Constraint violation (19) additional info: some attributes not unique
Im LDAP Account Manager sieht der Fehler nach einem Dateiupload der zweiten LDIF-Datei wie in Bild 10.3 aus:
Bild 10.3 Fehlermeldung im Apache Directory Studio
10.2.5 | constraint |
Durch die Definitionen von Attributen im Schema eines Verzeichnisdienstes werden die Typen der einzelnen Attribute einer Objektklasse definiert. In manchen Fällen kann das aber nicht genügen, und es sollen genauere Festlegungen und Regeln für die Inhalte getroffen werden. Mithilfe des Overlays constraint lassen sich die bereits durch den Attributtyp vorgegebenen Einschränkungen weiter verfeinern. Ein Beispiel hierfür wäre wiederum das Attribut mail. Als Attributtyp ist hier im Standardschema der Typ IA5String (International Alphabet No.5, die internationale ASCII-Version) festgelegt. Damit lassen sich für dieses Attribut beliebige Zeichenketten als E-Mail-Adresse (und damit eventuell nicht erwünschte) eintragen. Anhand von Constraints können Sie an dieser Stelle genaue Vorgaben für den Aufbau oder die Werte dieses Attributs in der Datenbank wie z.B. <Text>@<Text>.<Text> oder <Text>@hanser-fachbuch.de festlegen. Wird dann versucht, einen Wert in ein Attribut einzutragen, welcher den jeweiligen Regeln nicht entspricht, so erhalten Sie Constraint violation-Fehler.
Schauen wir uns die dynamische Konfiguration an. Zunächst wird wie gehabt das entsprechende Modul geladen und anschließend das dazu gehörige Konfigurationsobjekt angelegt. Beispielhafte LDIF-Dateien finden Sie in Listing 10.41:
Listing 10.41 OLC-Konfiguration für constraint
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: constraint.la dn: olcOverlay=constraint,olcDatabase={2}mdb,cn=config changetype: add objectClass: top objectClass: olcConfig objectClass: olcOverlayConfig objectClass: olcConstraintConfig olcOverlay: constraint olcConstraintAttribute: mail regex ^[[:alnum:]]+@[[:alnum:]]+\.[[:alnum:]]+$ olcConstraintAttribute: mail regex ^[[:alnum:]]+@hanser.de$ \ restrict="ldap:///ou=redakteure,dc=example,dc=net??sub"
Dieses Beispiel legt zunächst das Format des mail-Attributs auf die Form<Zeichen>@<Zeichen>.<Zeichen> fest. Für den Teilbaum ou=Verwaltung,dc=example,dc=net wird für den Domänenanteil der E-Mail-Adresse darüber hinaus firma.de vorgeschrieben.
Tipp: Ein Blick in die Manuals von slapo-constraint zeigt Ihnen, dass Sie mit den Regeln sehr weit gehen können. So lässt sich mit dem Beispiel aus Listing 10.42 eine Einschränkung für den Teilbaum dc=example,dc=net mit den Attributen cn, sn und givenName derart konstruieren, dass das Attribut cn immer die Kombination ”given-Name sn” enthalten muss:
Listing 10.42 Komplexere Möglichkeiten mit constraint
constraint_attribute cn,sn,givenName set "(this/givenName + [ ] + this/sn) & this/cn" restrict="ldap:///dc=example,dc=net??sub?( objectClass=inetOrgPerson)"
Legen Sie sich nun als Beispiel die OU und den Benutzer für die Redaktion mit dem Listing 10.43 an. Im Folgenden werden wir dann versuchen, einem Redakteur eine E-Mail zu geben.
Listing 10.43 Anlegen eines Redakteurs
dn: ou=redakteure,dc=example,dc=net objectClass: organizationalUnit ou: redakteure dn: cn=redakteur,ou=redakteure,dc=example,dc=net objectClass: inetOrgPerson cn: redakteur sn: redakteur
In Listing 10.44 nehmen wir eine LDIF-Datei changemail.ldif mit einer Änderung, welche gegen die erste Regel aus Listing 10.41 verstößt:
Listing 10.44 Änderung mit Regelverstoß
provider01:~# cat changemail.ldif dn: cn=redakteur,ou=redakteure,dc=example,dc=net changetype: modify add: mail mail: redakteur@hanser
Der Versuch, diese Datei zu importieren, wird dann mit einem Fehler abbrechen.
Listing 10.45 Verstoß gegen ein Constraint
provider01:~# ldapmodify -D "cn=admin,dc=example,dc=net" -W -f changemail.ldif modifying entry "cn=redakteur,ou=redakteure,dc=example,dc=net" ldap_modify: Constraint violation (19) additional info: modify breaks constraint on mail
Die festgelegte Einschränkung greift. Da der Domänenanteil der E-Mail-Adresse nur eine Ebene statt wie gefordert zwei besitzt, kommt es zu einem entsprechenden Fehler. Korrigieren Sie die LDIF-Datei und versuchen es erneut. Das Ergebnis sehen Sie in Listing 10.46:
Listing 10.46 Import einer regelkonformen LDIF-Datei
provider01:~# cat changemail.ldif dn: cn=redakteur,ou=redakteure,dc=example,dc=net changetype: modify add: mail mail: redakteur@hanser.de provider01:~# ldapmodify -D "cn=admin,dc=example,dc=net" -W -f changemail.ldif modifying entry "cn=redakteur,ou=redakteure,dc=example,dc=net" provider01:~/# ldapsearch -D "cn=admin,dc=example,dc=net" -W ’(cn=redakteur)’ \ mail -LLL dn: cn=redakteur,ou=redakteure,dc=example,dc=net mail: redakteur@hanser.de
10.2.6 | dds |
Wer kennt das nicht? Ein neuer Praktikant, ein Mitarbeiter mit einem Zeitvertrag oder eine externe Mitarbeiterin, welche nur ein paar Tage, Wochen oder Monate im Unternehmen ist, benötigt Zugriff auf Netzwerkressourcen. Alle brauchen ein Konto, um sich im Netz anmelden oder um auf eine Applikation auf einem Webserver zugreifen zu können. Wenn Sie jetzt ein Konto für diese Mitarbeiter anlegen, müssen Sie sicherstellen, dass das Konto nach dem Ausscheiden des entsprechenden Mitarbeiters wieder gelöscht wird. Schöner wäre es doch, wenn der LDAP-Server sich selber um das Löschen der entsprechenden Objekte kümmern würde. Und das kann er auch, und zwar mithilfe des Overlays dds (Dynamic Directory Service). Mit diesem Overlay lassen sich Objekte mit einer begrenzten Lebensdauer erstellen.
Für die dynamische Konfiguration benötigen Sie eine LDIF-Datei wie beispielsweise die in Listing 10.47 gezeigte:
Listing 10.47 OLC-Konfiguration von dds
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: dds.la dn: olcOverlay=dds,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcDDSConfig olcOverlay: dds olcDDSmaxTtl: 1d olcDDSminTtl: 30s olcDDSdefaultTtl: 60s olcDDSinterval: 5s olcDDStolerance: 1s olcDDSmaxDynamicObjects: 10
Die einzelnen Parameter haben dabei die folgenden Bedeutungen:
olcDDSmaxTtl 1d
Dieser Wert gibt an, um welchen Wert eine Lebensdauer für ein dynamisches Objekt maximal verlängert werden kann. Im Beispiel beträgt er genau einen Tag. Der Wert muss zwischen 86400 und 31557600 Sekunden liegen, also einem Tag und einem Jahr.
olcDDSminTtl 30s
Das ist die minimale Verlängerung für die Lebensdauer eines dynamischen Objekts.
olcDDSdefaultTtl 1m
Mit diesem Wert legen Sie fest, wie lang die Lebensdauer beim Erstellen eines Objekts ist. Ist dieser Wert nicht gesetzt, so wird bei neuen Objekten dds-max-ttl als Standardwert eingetragen.
olcDDSinterval 5s
Legt fest, wie oft der LDAP-Server prüfen soll, ob ein dynamisches Objekt gelöscht werden soll. Beachten Sie bei der Festlegung dieses Wertes: Je häufiger Sie den LDAP-Server die dynamischen Objekte prüfen lassen und je mehr dieser Objekte Sie haben, desto höher ist die Last auf dem LDAP-Server. Einen Wert von einer Minute sollten Sie in Produktivsystemen nicht unterschreiten. Die hier verwendeten fünf Sekunden sollen uns nur helfen, schneller zu sehen, ob das Overlay seinen Dienst verrichtet.
olcDDStolerance 1s
Dieser Wert legt eine Frist fest, nach der das Löschen des Objekts starten muss. Immer vom Zeitpunkt aus, zu dem der LDAP-Server den Ablauf der Lebensdauer festgestellt hat.
olcDDSmaxDynamicObjects 10
Über diesen Parameter können Sie die maximale Anzahl an dynamischen Objekten in dem Kontext, auf den sich die Datenbank bezieht, begrenzen. Wenn der Wert nicht gesetzt ist, ist die Anzahl nicht beschränkt.
Für die Verwendung des Overlays müssen die zu verwaltenden Objekte die zusätzliche Objektklasse dynamicObject besitzen. Diese Objektklasse besitzt keine eigenen Attribute. Ein zeitlich begrenztes Objekt wie ein einzelner Benutzer wird später um diese Klasse erweitert. Das Vorhandensein dieser zusätzlichen Klasse zeigt dem LDAP-Dienst an, dass es sich um ein zeitlich begrenztes Objekt handelt.
Vor solch einer Erweiterung müssen Sie zunächst das Overlay selbst konfigurieren, denn während der Erweiterung eines Objekts um die zusätzliche Klasse werden die benötigten Werte für die Attribute der Objektklasse aus der Overlay-Konfiguration ausgelesen.
Erst nachdem Sie diese Konfiguration durchgeführt haben, können Sie das erste dynamische Objekt anlegen. Im Beispiel in Listing 10.48 wird ein SimpleSecurityObject erstellt:
Listing 10.48 LDIF-Datei für ein dynamisches Objekt
dn: uid=praktikant,ou=users,dc=example,dc=net objectClass: SimpleSecurityObject objectClass: dynamicObject objectClass: account uid: praktikant userPassword: $argon2i$v=19$m=4096,t=3,p=1$aWVncmVsaXVocmVsaXVoaXVo$XaM4ud \ wt29uhWsflnneBaSUu/Rx6KGJf0p+NWCKTPts
Speichern Sie das Beispiel aus Listing 10.48 unter dem Namen praktikant.ldif ab und legen Sie das Objekt mit ldapadd an. Anschließend lassen Sie sich das Objekt sofort mit ldapsearch auflisten (denn die Ablaufzeit ist ja in unserem Fall auf eine Minute gestellt), und zwar einmal alle Attribute und einmal alle internen Attribute. Listing 10.49 zeigt den kompletten Vorgang:
Listing 10.49 Anlegen des dynamischen Objekts
provider01:~# ldapadd -D "cn=admin,dc=example,dc=net" -W -f praktikant.ldif adding new entry "cn=praktikant,ou=users,dc=example,dc=net" provider01:~# ldapsearch -D "cn=admin,dc=example,dc=net" -W \ ’(cn=praktikant)’ -LLL dn: cn=praktikant,ou=users,dc=example,dc=net objectClass: person objectClass: dynamicObject cn: praktikant sn: Praktikant provider01:~# ldapsearch -D "cn=admin,dc=example,dc=net" -W \ ’(cn=praktikant)’ -LLL + dn: cn=praktikant,ou=users,dc=example,dc=net entryTtl: 60 entryExpireTimestamp: 20221120094801Z structuralObjectClass: person entryUUID: 72241f3c-9fc6-1039-8a39-d3365007fb84 creatorsName: cn=admin,dc=example,dc=net createTimestamp: 20221120094701Z entryCSN: 20221120094701.481823Z#000000#000#000000 modifiersName: cn=admin,dc=example,dc=net modifyTimestamp: 20221120094701Z entryDN: cn=praktikant,ou=users,dc=example,dc=net subschemaSubentry: cn=Subschema hasSubordinates: FALSE
Beim ersten Auflisten der Attribute sehen Sie keines der dynamischen Attribute, da es sich um sogenannte operationale Attribute handelt. Erst wenn Sie sich die operationalen Attribute des Objekts mit der zusätzlichen Option + anzeigen lassen, sehen Sie die zusätzlichen Werte wie zum Beispiel den entryTtl von 60 Sekunden sowie den entryExpireTimestamp, also den Ablaufzeitpunkt des Objekts eine Minute nach Erstellung (siehe createTimestamp) (Sie werden bemerken, dass die Zeitstempel in der Datenbank stets in UTC angegeben werden, um sie unabhängig vom geografischen Standpunkt des Servers zu machen). Suchen Sie nach einer Minute (beziehungsweise nach dem Zeitpunkt, der unter dem Attribut entryExpireTimestamp angegeben ist) erneut nach dem Objekt, und Sie werden feststellen, dass das Objekt verschwunden ist.
Was ist, wenn der Praktikant nun länger als ursprünglich geplant bleibt und Sie also die Lebensdauer des dynamischen Objekts verlängern wollen? Und wer darf die Lebensdauer verlängern?
Zuerst beantworten wir mal die Frage, wer die Zeit verlängern darf: zum einen der Benutzer, welcher im rootDN eingetragen ist, zum anderen jeder, der an dem Attribut entryTtl das Recht manage besitzt. Mit diesem Recht können Sie interne Attribute ändern. Schlagen wir noch einmal einen Bogen zurück zu Kapitel 9, «Berechtigungen mit ACLs»: Wenn beispielsweise der Besitzer eines Objekts die Lebensdauer selbstständig verlängern können soll, müssen Sie die Liste Ihrer ACLs um die Regel aus Listing 10.50 erweitern:
Listing 10.50 ACL für die Änderung der Lebensdauer
access to attrs=entryTtl by self manage by * read
Jetzt zur Frage, wie Sie die Lebensdauer verändern. Dazu können Sie zum Beispiel die LDIF-Datei change-ttl.ldif verwenden. Listing 10.51 zeigt den Inhalt der Datei:
Listing 10.51 LDIF zum Ändern der Lebensdauer
dn: cn=praktikant,ou=users,dc=example,dc=net changetype: modify replace: entryTtl entryTtl: 300
Damit hat praktikant fünf weitere Minuten, in der Datenbank zu überleben.
Theoretisch. Denn wenn Sie jetzt das Objekt erneut anlegen und anschließend versuchen, das Objekt mithilfe der LDIF-Datei zu verändern, werden Sie auf den Fehler aus Listing 10.52 treffen:
Listing 10.52 Fehler beim Ändern der entryTtl
provider01:~# ldapmodify -x -D "cn=admin,dc=example,dc=net" -W \ -f change-ttl.ldif modifying entry "cn=praktikant,ou=users,dc=example,dc=net" ldap_modify: Constraint violation (19) additional info: entryTtl: no user modification allowed provider01:~# ldapmodify -x -D "cn=praktikant,ou=users,dc=example,dc=net" -W \ -f change-dyn.ldif modifying entry "cn=ffluechtig,ou=users,dc=example,dc=net" ldap_modify: Constraint violation (19) additional info: entryTtl: no user modification allowed
Sowohl der rootDN als auch der Benutzer selbst bekommen eine Fehlermeldung beim Versuch, das Attribut zu verändern, und das, obwohl die ACL gesetzt wurde. Warum ist das so? Das Attribut entryTtl ist laut RFC4512 ein NO-USER-MODIFICATION-Attribut. Das schließt sogar den rootDN ein. Also kann niemand auf diesem Weg das Attribut ändern. Aber für das Kommando ldapmodify gibt es den Parameter -e relax. Damit aktivieren Sie eine Erweiterung, mit der auch operationale Attribute geändert werden können. In Listing 10.53 schauen wir uns noch einmal die Situation nach dem Anlegen und nach dem Verlängern an:
Listing 10.53 Erfolgreiches Ändern des Attributs entryTtl
provider01:~/LDAP# ldapadd -D "cn=admin,dc=example,dc=net" -W \ -f praktikant.ldif adding new entry "cn=praktikant,ou=users,dc=example,dc=net" provider01# ldapsearch -D "cn=admin,dc=example,dc=net" -W \ ’(cn=praktikant)’ -LLL + dn: cn=praktikant,ou=users,dc=example,dc=net entryTtl: 60 entryExpireTimestamp: 20221120102834Z structuralObjectClass: person entryUUID: 1c30d5c4-9fcc-1039-8a45-d3365007fb84 creatorsName: cn=admin,dc=example,dc=net createTimestamp: 20221120102734Z entryCSN: 20221120102734.261455Z#000000#000#000000 modifiersName: cn=admin,dc=example,dc=net modifyTimestamp: 20221120102734Z entryDN: cn=praktikant,ou=users,dc=example,dc=net subschemaSubentry: cn=Subschema hasSubordinates: FALSE provider01# ldapadd -D "cn=admin,dc=example,dc=net" -W \ -f change-ttl.ldif -e relax modifying entry "cn=praktikant,ou=users,dc=example,dc=net" provider01# ldapsearch -D "cn=admin,dc=example,dc=net" -W \ ’(cn=praktikant)’ -LLL + dn: cn=praktikant,ou=users,dc=example,dc=net structuralObjectClass: person entryUUID: 1c30d5c4-9fcc-1039-8a45-d3365007fb84 creatorsName: cn=admin,dc=example,dc=net createTimestamp: 20221120102734Z entryTtl: 300 entryExpireTimestamp: 20221120103243Z entryCSN: 20221120102743.596669Z#000000#000#000000 modifiersName: cn=admin,dc=example,dc=net modifyTimestamp: 20221120102743Z entryDN: cn=praktikant,ou=users,dc=example,dc=net subschemaSubentry: cn=Subschema hasSubordinates: FALSE
Nach dem Anlegen hätte er nur die standardmäßig eingestellte Minute in der Datenbank verbracht (entryExpireTimestamp: 20221120102834Z, eine Minute nach createTimestamp: 20221120102734Z). Nach der (jetzt erfolgreichen) Verlängerung hat er fünf weitere Minuten bis zur Löschung erhalten (entryExpireTimestamp: 20221120103243Z, fünf Minuten nach dem modifyTimestamp: 20221120102743Z).
Hinweis: Wenn Sie später die Replikation einrichten (siehe Kapitel 12, «Replikation des OpenLDAP-Baums»), müssen Sie darauf achten, dass die Attribute entryTl und entryExpireTimestamp nicht repliziert werden. Auf einen Slave-LDAP-Server müssen in der syncrepl-Direktive die Zeilen aus Listing 10.54 eingetragen werden:
Listing 10.54 Einträge auf einem Slave-Server
schemachecking = off exattrs=entryTtl,entryExpireTimestamp
Ohne diese Einträge wird eine Replikation nicht funktionieren.
Dann ist da noch das immer wiederkehrende Thema Performance. Da auf das Attribut entryExpireTimestamp regelmäßig zugegriffen wird (falls der Wert für dds-interval gering eingestellt ist, wird er dies umso häufiger tun), ist es wichtig, dieses Attribut zu indizieren. Erstellen Sie deshalb für die jeweilige Datenbank einen Index wie in Listing 10.55:
Listing 10.55 Eintrag für den Index
dn: olcDatabase={2}mdb,cn=config changetype: modify add: olcDbIndex olcDbIndex: entryExpireTimestamp eq
Erzeugen Sie im Anschluss die Indexdatenbank mit dem Befehl slapindex, wie in Listing 10.56 aufgezeigt:
Listing 10.56 Erzeugen der Indexdatenbank
root@provider01:~# slapindex The first database does not allow slapindex; using the first available one (2)
Der Hinweis hinsichtlich der Datenbank macht darauf aufmerksam, dass die Datenbanken 0(config) und 1(monitor) keinen Index unterstützen, sondern erst die mdb-Datenbank mit der Nummer 2. Mit dem Befehl slapindex -n2 könnte diese Meldung vermieden werden, da sie direkt das Auffrischen des Index der zweiten Datenbank startet.
Damit sind Sie jetzt in der Lage, mithilfe der verschiedenen Overlays bestimmte Vorgänge zu automatisieren oder zu vereinfachen.
10.3 | Zusatzfunktionen |
Im letzten Abschnitt dieses Kapitels wollen wir uns nun Overlays anschauen, welche zusätzliche Funktionen mitbringen. Dazu gehören zwei Overlays für Protokollierung, eines für die Einführung von Kennwortrichtlinien sowie eines, welches Sie für die spätere Replikation der Datenbank(en) benötigen.
10.3.1 | Vorabbemerkungen zur Protokollierung |
Bevor wir mit der Protokollierung beginnen, hier noch ein paar generelle Anmerkungen hinsichtlich deren Sinn und Zweck. Sie sollten sich vor der Einrichtung ein paar Fragen stellen, inwieweit Sie überhaupt protokollieren wollen, müssen und/oder dürfen. Bei der Protokollierung (und damit auch der Überwachung der Aktivitäten innerhalb der Datenbank und somit auch eventuell der betroffenen Benutzer) gelangen Sie schnell in die Bereiche des Datenschutzes, für die zumindest in unseren Gefilden zum Glück strenge Regelungen gelten.
Mit den beiden Overlays accesslog und auditlog können Sie die Zugriffe auf und Änderungen an Objekten in einer LDAP-Datenbank zum Teil sehr detailliert protokollieren. So können Sie z.B. überwachen, welche Benutzer an welchen Objekten Adressinformationen ändern oder welche Benutzer sich wann und von wo mit ihrem Verzeichnis verbunden haben. Dies kann in einigen Fällen sicher sinnvoll sein, wenn Änderungen in bestimmten Bereichen nachvollziehbar sein müssen. Dabei können aber schnell, wie eingangs erwähnt, datenschutzrechtliche Belange berührt werden, da es sich um personenbezogene Daten handelt und Sie den Zugriff auf diese Protokollinformationen genügend absichern müssen.
Überlegen Sie sich also daher gut, was Sie protokollieren und wer darauf (Lese-)Rechte bekommt. Stellen Sie aber auch sicher, dass die Protokolle revisionssicher angelegt werden, sie also im Nachhinein nicht geändert werden können.
Hinzu kommen aber auch rein praktische Erwägungen. Stark genutzte LDAP-Server erzeugen eine massive Anzahl von Ereignissen. Diese zu protokollieren, belastet den oder die Server gegebenenfalls in einem erheblichem Maße: zum einen durch das eigentliche Protokollieren, zum anderen durch den dadurch belegten Platz.
Fragen Sie sich daher vor der Einrichtung der Protokollierung:
In welchen Datenbanken ist eine Protokollierung notwendig oder sinnvoll?
Welche Art der Zugriffe möchten Sie protokollieren?
Wer benötigt (Lese-)Rechte auf die Informationen der Protokolle?
Wie lang müssen oder dürfen Sie die Informationen aufbewahren?
Welche gesetzlichen Regelungen müssen Sie einhalten?
Wie stellen Sie sicher, dass die Protokollinformationen nicht geändert werden?
Wen müssen Sie in den Entscheidungsprozess mit einbeziehen (Betriebsrat, Datenschutzbeauftragte/r)?
Hinweis: Hier soll Ihnen keine Angst vor der Protokollierung gemacht werden. Sie werden sehen, dass es kein Hexenwerk ist, sie einzurichten. Aber es bedarf einiges an Vorüberlegungen, sie sinnvoll und vor allem rechtskonform einzurichten.
10.3.2 | accesslog |
Das Overlay accesslog ist eine von zwei Möglichkeiten der Protokollierung. Die Informationen werden dabei als Objekte in einer eigenen LDAP-Datenbank abgelegt und können durch entsprechende Abfragen ausgelesen werden.
Hinweis: Diese Art der Protokollierung wird für die Delta-Replikation zwischen LDAP-Servern benötigt. Wir kommen in Kapitel 12, «Replikation des OpenLDAP-Baums», noch einmal darauf zurück.
Folgende vier Zugriffsarten aus der Tabelle 10.1 auf die Objekte einer Datenbank können Sie damit überwachen:
Tabelle 10.1 Zu überwachende Zugriffe des Overlays accesslog
session |
fasst die Operationen bind, unbind und abandon zusammen. |
reads |
umfasst die compare- und search-Operationen. |
writes |
beinhaltet die Operationen add, delete, modify und modrdn. |
all |
alle Zugriffe: session, reads und writes |
Für die dynamische Konfiguration sind folgende drei Schritte notwendig:
1. Laden des Moduls: Zunächst müssen Sie dem LDAP-Service mitteilen, dass das entsprechende Modul geladen werden soll. Dazu müssen Sie dem Objekt cn=module{0}, cn=config einen weiteren Wert für das Attribut olcModuleLoad hinzufügen, z.B. mit folgender LDIF-Datei:
Listing 10.57 OLC-Konfiguration zum Laden des accesslog-Moduls
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: accesslog.la
2. Erstellen der Datenbank für die Protokollobjekte: Damit das Overlay seine Objekte in einem eigenen, separaten Kontext ablegen kann, benötigen Sie dafür eine neue eigene Datenbank. Diese lässt sich beispielsweise mit folgenden LDIF-Anweisungen anlegen:
Listing 10.58 OLC-Konfiguration für die accesslog-Datenbank
dn: olcDatabase=mdb,cn=config changetype: add objectClass: olcMdbConfig objectClass: olcDatabaseConfig olcDatabase: mdb olcDbDirectory: /var/symas/ldap-accesslog olcAccess: to * by dn.base="cn=admin,dc=example,dc=net" read olcSuffix: cn=myaccesslog
Denken Sie daran, den angegebenen Ordner vor der Erstellung des Datenbankobjekts zu erstellen und die entsprechenden Rechte für den entsprechenden Benutzer (openldap) sowie die Gruppe (openldap) zu vergeben, unter dem der LDAP-Dienst auf Ihrem Server läuft.
Listing 10.59 Verzeichnis für das AccessLog
mkdir /var/symas/ldap-accesslog chown openldap.openldap /var/symas/ldap-accesslog chmod 750 /var/symas/ldap-accesslog
Wo wir gerade von Rechten sprechen: In dem Beispiel unter Listing 10.58 sehen Sie, dass hier auch gleich die Zugriffsrechte festgelegt werden. Hier können oder sollten Sie aus Datenschutzgründen eigene Benutzer anlegen und verwenden. Möglich ist hier natürlich auch die Verwendung der Attribute olcRootDN und olcRootPW, sodass Sie einen Benutzer verwenden, welcher im LDAP-Verzeichnis erst gar nicht angezeigt wird.
3. Konfiguration des accesslog-Overlays: Im letzten Schritt können Sie nun das Objekt für die Konfiguration des accesslog-Overlays anlegen. Für unser Beispiel lässt sich dazu beispielsweise folgende LDIF-Datei aus Listing 10.60 verwenden. Beachten Sie dabei, dass wir das Overlay für die MDB-Datenbank mit den LDAP-Objekten und nicht für die soeben angelegte MDB-Datenbank mit dem Accesslog einrichten.
Listing 10.60 OLC-Konfiguration des accesslog-Overlays
dn: olcOverlay=accesslog,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcAccessLogConfig objectClass: olcOverlayConfig olcAccessLogDB: cn=myaccesslog olcOverlay: accesslog olcAccessLogOps: reads writes olcAccessLogOld: (objectclass=inetOrgPerson) olcAccessLogOldAttr: givenName sn telephoneNumber mail olcAccessLogPurge: 28+00:00 00+01:00 olcAccessLogSuccess: FALSE
Die Parameter im Einzelnen:
olcAccessLogDB
Definiert den Kontext, in welchem die Protokollobjekte abgelegt werden sollen. Dieser muss mit dem Kontext des vorher angelegten Datenbankobjektes übereinstimmen.
olcAccessLogOps
Legt fest, welche Operationen im Einzelnen protokolliert werden sollen (siehe Tabelle 10.1).
olcAccessLogOld
Für ein Audit kann es eventuell sinnvoll sein, bei Änderungen die vorherigen Werte mit ins Protokoll aufzunehmen. Dieser Parameter definiert LDAP-Filter für diejenigen Objekte Ihrer Datenbank, für die solch eine Speicherung sinnvoll bzw. notwendig ist, im obigen Beispiel in Listing 10.60 also alle Objekte mit der Objektklasse inetOrgPerson.
olcAccessLogOldAttr
Ähnlich wie der vorhergehende Parameter logold dient dieser Parameter zur weiteren Eingrenzung der abzuspeichernden Werte. Hiermit werden die Attribute festgelegt, deren alte Werte protokolliert werden, unabhängig von der Klasse des geänderten Objekts. Für das Beispiel aus Listing 10.60 wären dies der Vor- und Nachname, die Telefonnummer sowie die E-Mail-Adresse.
olcAccessLogPurge
Damit die Protokolldatenbank nicht übermäßig anwächst, lässt sich mit diesem Parameter das maximale Alter der Log-Einträge sowie das Aufräumintervall festlegen. Hinter diesem Parameter geben Sie zunächst das maximale Alter der Log-Einträge und das Intervall an, in welchem nach veralteten Einträgen gesucht werden soll. Das Format für die beiden Zeitangaben ist dabei [T+]hh:mm, also optional die Angabe von Tagen (T), gefolgt von Stunde (hh) und Minute (mm). In Listing 10.60 werden also stündlich alle Einträge gelöscht, welche älter als 28 Tage sind.
Hinweis: Für das maximale Alter der Protokolleinträge gibt es je nach Inhalt eventuell gesetzliche Vorgaben. Informieren Sie sich an dieser Stelle genau, wie lang Sie die Protokolle aufbewahren müssen oder dürfen.
Bedenken Sie bei der Festlegung des Intervalls: Räumen Sie große Protokolldatenbanken zu oft auf, ist der Server nur mit Aufräumen beschäftigt.
olcAccessLogSuccess
Wollen Sie nur erfolgreiche und nicht die fehlgeschlagenen Zugriffe protokollieren, so müssen Sie diesen Parameter setzen.
Die entsprechenden LDIF-Dateien können Sie jetzt mit ldapmodify in Ihre Konfiguration übernehmen. Sie können die drei Änderungen natürlich auch in einer einzelnen Datei hinterlegen. Wichtig ist in jedem Fall, dass Sie die Reihenfolge bei den Änderungen einhalten.
Nachdem Sie diese Änderungen durchgeführt und den slapd-Dienst neu gestartet haben, existiert im LDAP-Verzeichnis ein neues Objekt (in unserem Fall cn=myaccesslog), über welches die Protokolleinträge abgefragt werden können. Listing 10.61 zeigt Ihnen ein Beispiel für solch eine Abfrage:
Listing 10.61 Abfragen auf das AccessLog
ldapsearch -x -D "cn=admin,dc=example,dc=net" -W -b "cn=myaccesslog"
Das Ergebnis kann dann (je nach Detailtiefe der Protokollierung sowie der Zugriffs- bzw. Änderungshäufigkeit) beliebig lang werden. Wurde zum Beispiel für ein Benutzerobjekt cn=jdoe,ou=users,dc=example,dc=net das Attribut givenName hinzugefügt, so bekäme man in der Ergebnisliste einen Eintrag wie in Listing 10.62 gezeigt:
Listing 10.62 AccessLog-Eintrag nach dem Hinzufügen eines Attributs
dn: reqStart=20221110105346.000001Z,cn=myaccesslog objectClass: auditModify reqStart: 20221110105346.000001Z reqEnd: 20221110105346.000002Z reqType: modify reqSession: 1000 reqAuthzID: cn=admin,dc=example,dc=net reqDN: cn=jdoe,ou=users,dc=example,dc=net reqResult: 0 reqMod: givenName:+ Jane reqMod: entryCSN:= 20221110105346.112996Z#000000#000#000000 reqMod: modifiersName:= cn=admin,dc=example,dc=net reqMod: modifyTimestamp:= 20221110105346Z reqOld: entryCSN: 20221110101457.850709Z#000000#000#000000 reqOld: modifiersName: cn=admin,dc=example,dc=net reqOld: modifyTimestamp: 20221110101457Z reqEntryUUID: 63544eb0-975f-1039-9a94-7debc54f3359
Wie Sie sehen, sind die Protokolleinträge sehr ausführlich: Am 10.11.2022 um 10:53 Uhr wurde dem Attribut givenName des Benutzerobjekts cn=jdoe,ou=users,dc=example,dc=net durch den Benutzer cn=admin,dc=example,dc=net der Wert Jane hinzugefügt. Der vorige Wert war leer und stammte vom 10.11.2022 um 10:14 Uhr. Der entryCSN stellt den Zeitstempel des jeweiligen Objekts dar (siehe Tabelle 10.3).
Da im Laufe der Zeit sicher einiges an Einträgen in der Datenbank zusammenkommt, sollten Sie die Größen- und ggf. auch die Zeitbeschränkungen hinsichtlich Abfragen an die Datenbank des accesslog noch anpassen. In Listing 10.63 sehen Sie ein Beispiel, damit ein Benutzer alle Einträge der Datenbank auslesen kann.
Listing 10.63 Anpassung der Datenbank-Limits
dn: {0} dn.exact="cn=admin,dc=example,dc=net" time=unlimited size=unlimited changetype: modify add: olcLimits olcLimits: {0} dn.exact="cn=admin,dc=example,dc=net" time=unlimited size=unlimited
Wie eingangs erwähnt, sollten Sie sich Gedanken zu Umfang und Schutz der Protokollierung machen. Im Fall des Overlays accesslog lässt sich der Umfang der Protokollierung über die folgenden Parameter steuern:
olcAccessLogOps
Müssen Sie Lesezugriffe protokollieren oder genügen Änderungen?
olcAccessLogOld, olcAccessLogOldAttr
Ist es notwendig, den vorherigen Wert eines geänderten Attributs mitzuprotokollieren? Falls ja, lassen sich die zu überwachenden Objekte über die LDAP-Suchfilter eingrenzen, zum Beispiel memberOf=cn=admins,ou=groups,dc=example,dc=net sowie eine Liste von Attributen, deren alter Wert mit aufgenommen werden soll, also z.B. telephone-Number, sn oder mail angeben.
olcAccessLogPurge
Benötigen Sie die Information länger als sieben Tage?
olcAccessLogSuccess
Genügt es, lediglich fehlgeschlagene Änderungen zu protokollieren?
Zugriffsschutz: Da die Protokolle als Objekt im LDAP-Verzeichnis hinterlegt sind, können und müssen sie durch entsprechende ACLs geschützt werden. Mehr zu ACLs in Kapitel 9, «Berechtigungen mit ACLs».
10.3.3 | auditlog |
Mit dem Overlay auditlog werden im Unterschied zum accesslog ausschließlich Änderungen an Objekten in der jeweiligen OpenLDAP-Datenbank protokolliert. Weitere Zugriffe wie Such- oder Lesezugriffe werden nicht überwacht. Anders als beim accesslog werden die Ausgaben der Protokollierung mit auditlog als LDIF-Datei im Dateisystem und nicht als Objekte in der LDAP-Datenbank abgelegt. Weiterhin sind im Gegensatz zum accesslog allerdings keine detaillierteren Konfigurationen hinsichtlich der überwachten Ereignisse möglich.
Zur Vorbereitung muss erstmal ein Verzeichnis mit entsprechenden Berechtigungen erstellt werden, wie beispielsweise in Listing 10.64 gezeigt:
Listing 10.64 Verzeichnis für das AuditLog
mkdir /var/symas/ldap-auditlog chown openldap.openldap /var/symas/ldap chmod 750 /var/symas/ldap-auditlog
Als Nächstes muss der Service noch das entsprechende auditlog-Modul laden. Für die dynamische Konfiguration können Sie die LDIF-Datei aus Listing 10.65 verwenden:
Listing 10.65 LDIF-Datei zum Laden des auditlog-Moduls
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: auditlog.la
Mit einem Befehl wie
wird das Modul der Liste der zu ladenden Module hinzugefügt.
Schlussendlich müssen Sie nun noch die Protokollierung für Ihre Datenbank aktivieren. Für die Konfiguration legen Sie eine LDIF-Datei wie in Listing 10.66 aufgezeigt an und importieren diese mit ldapadd:
Listing 10.66 LDIF-Datei zum Aktivieren der Protokollierung
dn: olcOverlay=auditlog,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcAuditLogConfig olcOverlay: auditlog olcAuditlogFile: /var/symas/ldap-auditlog/auditlog.ldif
In unserem Fall wird damit das Overlay auditlog für die mdb-Datenbank aktiviert und als Ausgabedatei /var/symas/ldap-auditlog/auditlog.ldif festgelegt.
Wenn wir nun wie im Beispiel für das accesslog unserem Benutzer cn=jdoe,ou=users, dc=example,dc=net das Attribut givenName hinzufügen, dann enthält das Protokoll folgenden Eintrag:
Listing 10.67 Ausgabe im AuditLog
dn: cn=jdoe,ou=users,dc=example,dc=net changetype: modify add: givenName givenName: Jane - replace: entryCSN entryCSN: 20221110125402.973694Z#000000#000#000000 - replace: modifiersName modifiersName: cn=admin,dc=example,dc=net - replace: modifyTimestamp modifyTimestamp: 20221110125402Z -
Wie Sie sehen, werden sämtliche Änderungen an dem Objekt, die in einer Operation durchgeführt wurden, zu einem LDIF-Eintrag zusammengefasst. Durch die Änderung des Attributs givenName werden zugleich die Zeitstempel modifyTimestamp, entryCSN (siehe Tabelle 10.3) sowie der modifiersName geändert.
Der Umfang der Protokollierung selbst ist beim auditlog von vornherein auf Änderungen eingeschränkt. Um dem Datenvolumen Herr zu werden, müssen Sie auf Bordmittel wie logrotate zurückgreifen. Auch beim Schutz der Dateien vor unbefugtem Zugriff sind entsprechende Maßnahmen mit den unter Linux zur Verfügung stehenden Mitteln der Dateisystemberechtigungen zu treffen.
10.3.4 | ppolicy |
Für den Betrieb eines OpenLDAP-Verzeichnisses, welches zur Authentifizierung von Benutzern dient, ist die Einführung von Kennwortrichtlinien (Password Policies) zu Kennwortlänge, -alter, -komplexität etc. unerlässlich. Dafür dient das ppolicy-Overlay.
Folgende Einschränkungen bzw. Vorgaben lassen sich einrichten:
Warnung vor Ablauf des Kennworts
Anzahl möglicher Anmeldungen nach Ablauf des Kennworts
Anzahl eindeutiger Kennworte zur Vermeidung von Wiederholungen
Dauer einer möglichen Kontensperre nach Fehlversuchen
Anzahl möglicher Fehlversuche
Zeit, nach der die Anzahl der Fehlversuche zurückgesetzt wird
maximales und minimales Kennwortalter
Kennwortlänge
erzwungene Kennwortänderung nach Setzen des Kennwortes durch den Administrator
Zur Einführung und Nutzung von Kennwortrichtlinien sind wie gehabt zwei Schritte notwendig: das Laden des Moduls und die anschließende Erstellung von Objekten zur Konfiguration. In OpenLDAP-Versionen vor 2.5 musste zusätzlich noch das Schema erweitert werden. Dies ist nicht mehr notwendig. Für die Vorbereitung von Kennwortrichtlinien sind folgende Schritte notwendig:
Modul ppolicy laden:
Listing 10.68 Laden des ppolicy-Moduls
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: ppolicy.la
Konfiguration des Overlays ppolicy
Im nächsten Schritt erstellen Sie ein Objekt zum generellen Umgang mit Kennwortrichtlinien.
Listing 10.69 Konfiguration des ppolicy-Overlays
dn: olcOverlay=ppolicy,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcPPolicyConfig olcOverlay: ppolicy olcPPolicyDefault: cn=default,ou=policies,dc=example,dc=net olcPPolicyForwardUpdates: FALSE olcPPolicyHashCleartext: TRUE olcPPolicyUseLockout: FALSE
Mit einem entsprechenden Aufruf von ldapmodify können Sie diese Änderungen in Ihre Konfiguration übernehmen.
Zu den einzelnen Parametern:
olcPPolicyDefault
Mit diesem Parameter legen Sie die Standardrichtlinie für alle Objekte in der Datenbank fest.
olcPPolicyForwardUpdates
Diesen Parameter werden Sie im Falle einer Replikation benötigen. Er aktiviert die umgehende Weiterleitung einer Kennwortänderung an den Master-Server der Replikation.
olcPPolicyHashCleartext
Diesen Wert sollten Sie immer dann setzen, wenn einige Ihrer LDAP-Clients nicht die sogenannten erweiterten Funktionen (extended operations) unterstützen und Kennwörter im Klartext übertragen. In diesem Fall würde der LDAP-Server die Kennwörter lediglich Base64-kodiert abspeichern. Setzen Sie diesen Parameter, so wird sichergestellt, dass anstelle des Kennworts der Hashwert unter Verwendung des gewählten Standard-Hash-Algorithmus gespeichert wird.
Wird zum Beispiel ein Benutzer mit dem Kennwort geheim angelegt und das Kennwort lediglich Base64-kodiert, so ergibt sich bei einer Suche mit ldapsearch:
Listing 10.70 Benutzerobjekt mit Base64-kodiertem Kennwort
dn: cn=jdoe,ou=users,dc=example,dc=net objectClass: inetOrgPerson sn: Doe cn: jdoe userPassword: Z2VoZWlt
Mit dem base64-Befehl können Sie dann das Kennwort leicht dekodieren, wie in Listing 10.71 gezeigt:
Listing 10.71 Dekodieren eines Base64-kodierten Kennworts
root@provider01:~/LDAP# echo Z2VoZWlt|base64 -d geheim
(Der Befehl base64 ist kein Supergeheimtool, sondern gehört zur Standardausstattung.)
olcPPolicyUseLockout
Ist ein Konto gesperrt und wird versucht, sich mit diesem Konto anzumelden, so wird standardmäßig lediglich die Fehlermeldung Ungültige Anmeldung zurückgegeben. Es bleibt also unklar, wieso die Anmeldung nicht möglich war. Mit diesem Parameter wird zusätzlich die Information Konto gesperrt mitgeliefert. Ob Sie diesen Parameter setzen, sollten Sie sich aber überlegen. Einem potenziellen Angreifer liefern Sie damit jedenfalls eventuell nützliche Informationen.
Damit sind Sie nun in der Lage, Kennwortrichtlinien zu erstellen. Diese werden als Objekte im Verzeichnis hinterlegt. In unserem Beispiel sollen diese Richtlinien in einem separaten Container ou=policies,dc=example,dc=net abgelegt werden. Hier ein Beispiel für eine solche Richtlinie im LDIF-Format:
Listing 10.72 Beispiel einer Kennwortrichtlinie
dn: ou=policies,dc=example,dc=net changetype: add objectClass: organizationalUnit ou: policies dn: cn=default,ou=policies,dc=example,dc=net changetype: add objectClass: pwdPolicy objectClass: person cn: default pwdAttribute: userPassword pwdAllowUserChange: TRUE pwdExpireWarning: 1440 pwdGraceAuthnLimit: 5 pwdInHistory: 5 pwdLockout: TRUE pwdFailureCountInterval: 300 pwdLockoutDuration: 3600 pwdMaxFailure: 5 pwdMaxAge: 2678400 pwdMinAge: 86400 pwdMinLength: 8 pwdCheckQuality: 1 sn: OurDefaultPolicy
Die Bedeutung der meisten Attribute lässt sich wahrscheinlich an ihrem Namen erkennen. Die in diesem Beispiel definierten Regeln legen Folgendes fest:
pwdAllowUserChange: Das Kennwort darf durch den Benutzer geändert werden.
pwdExpireWarning: 24 Stunden (1440 Minuten) vor Ablauf des Kennwortes wird gewarnt.
pwdGraceAuthnLimit: Fünfmal darf sich ein Benutzer mit einem abgelaufenen Kennwort anmelden.
pwdInHistory: Es wird eine Kennworthistorie mit fünf Einträgen geführt.
pwdLockoutDuration: Das Konto wird für eine Stunde (3600 Sekunden) . . .
pwdLockout . . . gesperrt, . . .
pwdFailureCountInterval . . . wenn innerhalb von fünf Minuten (300 Sekunden) . . .
pwdMaxFailure . . . fünfmal ein falsches Kennwort eingegeben wurde.
pwdMaxAge: Das Kennwort muss nach spätestens 31 Tagen (2678400 Sekunden) geändert werden . . .
pwdMinAge: . . . und muss mindestens einen Tag (86400 Sekunden) alt sein, bevor es geändert wird.
pwdMinLength: Das Kennwort muss mindestens acht Zeichen lang sein, mindestens ein alphanumerisches Zeichen, eine Ziffer, einen Klein- und einen Großbuchstaben sowie ein Sonderzeichen enthalten.
pwdCheckQuality: Setzen Sie dieses Attribut nicht oder setzen den Wert auf 0, so findet keine Kontrolle der Qualität des Kennwortes – wie seiner Länge – statt. Ein Wert von 1 bedeutet, dass die Qualität geprüft wird. Sollte die Prüfung nicht möglich sein, da beispielsweise das Kennwort als Hashwert gespeichert wird, so wird die Prüfung als erfolgreich gekennzeichnet, das Kennwort akzeptiert und eine Warnung ausgegeben. Bei einem Wert von 2 wird in diesem Fall das Kennwort nicht akzeptiert und eine Verletzung der Kennwortrichtlinie als Fehler zurückgegeben.
In diesem Beispiel sind noch nicht alle möglichen Parameter einer Kennwortrichtlinie aufgezählt. Mit man slapo-ppolicy können Sie sich alle weiteren möglichen Attribute anzeigen lassen.
Die Richtlinie aus Listing 10.72 wird zusammen mit der Konfiguration aus Listing 10.69 zur Standardrichtlinie für alle Benutzer innerhalb der Datenbank.
In der Praxis wird es aber häufig so sein, dass bestimmte Benutzer aus bestimmten Bereichen einer strikteren Kennwortrichtlinie unterliegen sollen. Beispiele hierfür sind zum Beispiel Systemadministratoren oder Benutzer, welche mit sensiblen Daten arbeiten. Dazu benötigen Sie zunächst ein neues pwdPolicy-Objekt mit den gewünschten Einstellungen. Den Benutzern, für welche dann diese Einstellungen gelten sollen, können Sie diese Kennwortrichtlinie über das Attribut pwdPolicySubentry zuweisen. Die Einstellungen dieser individuell zugewiesenen Richtlinie ersetzen dann diejenigen der Standardrichtlinie.
Ein Beispiel für eine striktere Richtlinie finden Sie in Listing 10.73:
Listing 10.73 Beispiel einer strikteren Kennwortrichtlinie
dn: cn=special,ou=policies,dc=example,dc=net cn: special objectClass: pwdPolicy objectClass: person pwdAttribute: userPassword pwdAllowUserChange: TRUE pwdExpireWarning: 1440 pwdGraceAuthnLimit: 5 pwdInHistory: 10 pwdLockout: TRUE pwdFailureCountInterval: 300 pwdLockoutDuration: 3600 pwdMaxFailure: 5 pwdMaxAge: 2678400 pwdMinAge: 86400 pwdMinLength: 16 pwdCheckQuality: 1 sn: OurSpecialPolicy
Hier wird also die Standardrichtlinie aus unserem Beispiel aus Listing 10.72 an zwei Stellen verschärft: Zum einen wird eine Kennworthistorie von zehn Kennwörtern geführt, zum anderen muss das Kennwort nun 16 Zeichen enthalten. In Listing 10.74 richten Sie nun einen Benutzer ein, welcher dieser Richtlinie unterliegt:
Listing 10.74 Benutzer mit einer strikteren Kennwortrichtlinie
dn: cn=specialuser,ou=users,dc=example,dc=net objectClass: inetOrgPerson sn: Special cn: specialuser userPassword: $argon2i$v=19$m=4096,t=3,p=1$TXU3aWRXbmFTY2hAbGtlMDQ$lG1I1q \ +lQDLJ503B0qmi1qz6/hF1/WI+wDQIboUMXrU pwdPolicySubentry: cn=special,ou=policies,dc=example,dc=net
Wichtig: Dieser Benutzer unterliegt nun nicht mehr der Standardrichtlinie, d. h. die spezielle Richtlinie gilt anstelle der Standardrichtlinie. Daher sollten Sie beim Anlegen neuer Kennwortrichtlinien immer auch die Einstellungen der Standardrichtlinie prüfen und ggf. übernehmen.
10.3.4.1 | Komplexere Kennwortrichtlinien |
Als Ergänzung zum Overlay ppolicy existiert noch ein weiteres Modul, mit welchem Sie weitere Komplexitätsanforderungen an die Kennworte Ihrer Benutzer stellen können: das Password Policy Module (PPM). Hinzu kommen Anforderungen wie:
eine minimale oder maximale Verwendung von Zeichenklassen wie Groß-/Kleinschreibung, Ziffern oder Sonderzeichen
den Ausschluss von bestimmten Zeichen
die Prüfung eines Kennwortes mit Cracklib
den Ausschluss von Attributwerten (oder Teilen davon) wie dem RDN
Um diese zusätzlichen Funktionen zu nutzen, müssen Sie das zusätzliche Modul im Overlay hinzufügen. Listing 10.75 zeigt Ihnen eine LDIF-Datei für diesen Zweck.
Listing 10.75 Hinzufügen von ppm zum ppolicy-Overlay
dn: olcOverlay={8}ppolicy,olcDatabase={2}mdb,cn=config changetype: modify add: olcPpolicyCheckModule olcPpolicyCheckModule: /opt/symas/lib/openldap/ppm.so
Damit ist generell das zusätzliche Modul verfügbar. Als Nächstes müssen Sie es der Kennwortrichtlinie hinzufügen. Dazu muss das Objekt um die Hilfsklasse pwdPolicyChecker erweitert sowie das Attribut pwdUsePolicyCheck auf TRUE gesetzt werden. Auch dafür sehen Sie ein Beispiel in Listing 10.76.
Listing 10.76 Erweitern einer Kennwortrichtlinie
dn: cn=default,ou=policies,dc=example,dc=net changetype: modify add: objectClass objectClass: pwdPolicyChecker - add: pwdUseCheckModule pwdUseCheckModule: TRUE
Das genügt allerdings noch nicht. Ändert nun ein Benutzer das Kennwort, so erhält er den Fehler aus Listing 10.77:
Listing 10.77 Fehler bei Kennwortänderung
Result: Constraint violation (19) Additional info: Error while checking password
Im Protokoll des slapd finden Sie zusätzlich die Meldung aus Listing 10.78:
Listing 10.78 Zusätzliche Ausgabe des slapd
ppm: No config provided in pwdCheckModuleArg
Es fehlt also noch eine Konfiguration der Richtlinie. Diese wird als kodierter Wert im Attribut pwdCheckModuleArg eingetragen. Um diese zu finden, erstellen Sie zunächst eine Datei ähnlich der in Listing 10.79:
Listing 10.79 Standardwerte für die Kennwortprüfung durch ppm
minQuality 8 checkRDN 0 checkAttributes mail forbiddenChars maxConsecutivePerClass 3 useCracklib 1 cracklibDict /var/cache/cracklib/cracklib_dict class-upperCase ABCDEFGHIJKLMNOPQRSTUVWXYZ 2 1 3 class-lowerCase abcdefghijklmnopqrstuvwxyz 2 1 3 class-digit 0123456789 1 1 0 class-special @=?,.;:-+*/ class-umlaut äöüÄÖÜß 0 1 0
Die Parameter im Einzelnen:
minQuality: welche Mindestqualität ein Kennwort erfüllen muss; mehr dazu im Anschluss an diese Liste
checkRDN: legt fest, ob eine Prüfung stattfinden soll, ob das Kennwort Teile des RDN des Benutzers enthält; ein Wert von 0 deaktiviert die Prüfung, der Wert 1 aktiviert diese
checkAttributes: hier könnten weitere Attribute stehen, deren Werte (oder Teile davon) nicht im Kennwort enthalten sein dürfen
forbiddenChars: an dieser Stelle lassen sich unerwünschte Zeichen im Kennwort festlegen
maxConsecutivePerClass 0: die maximale Anzahl aufeinanderfolgender gleicher Zeichenklassen
useCracklib: gibt an, ob Cracklib zur Prüfung des Kennwortes verwendet werden soll
cracklibDict: legt den Ort fest, an welchem Cracklib seine Dateien ablegt
class-upperCase: definiert die Klasse der Großbuchstaben
class-lowerCase: definiert die Klasse der Kleinbuchstaben
class-digit: definiert die Klasse der Ziffern
class-special: definiert eine Klasse von Sonderzeichen
class-umlaut: definiert die Klasse von Umlauten
Die Werte 0 1 0 bzw. min minforPoint max bei den Klassen haben dabei folgende Bedeutung:
min Wie viele Zeichen der Klasse müssen mindestens vorkommen?
minForPoint Wie viel „Punkte“ gibt es für das Vorkommen eines Zeichens dieser Klasse zur Berechnung der „Qualität“ des Kennworts?
max Wie viele Zeichen der Klasse dürfen höchstens vorkommen?
Mit den Einstellungen aus Listing 10.79 muss das Kennwort . . .
. . .mindestens acht „Qualitätspunkte“ erreichen
. . . keine (Teil-)Zeichenkette aus dem Wert des mail-Attributs besitzen
. . .maximal drei Zeichen einer Klasse hintereinander enthalten
. . .mindestens zwei Groß- bzw. Kleinbuchstaben, eine Ziffer und ein Sonderzeichen beinhalten
. . .maximal drei Groß- bzw. Kleinbuchstaben besitzen
Zudem bekommt das Kennwort für jedes Zeichen der Klassen upper, lower, digit, special und umlaut je einen „Qualitätspunkt“.
Folglich muss das Kennwort in diesem Fall acht Zeichen lang sein.
Wichtig: Mit der Verwendung des zusätzlichen Moduls ppm wird die vollständige „Qualitätskontrolle“ des Kennworts durch dieses Modul übernommen, auch die Kennwortlänge. Die Angaben aus dem Kennwortrichtlinienobjekt wie pwdMinLength sind damit außer Kraft gesetzt.
Speichern Sie die Datei aus Listing 10.79 z.B. unter dem Namen mypolicy ab. Das benötigte Attribut pwdCheckModuleArg für den Inhalt der künftigen Richtlinie ist ein Base64-Attribut. Daher benötigen Sie als Nächstes den Base64-kodierten Wert dieser Datei. Diesen können Sie beispielsweise mit dem Befehl base64 -w 0 mypolicy bestimmen. Das Ergebnis zeigt Listing 10.80:
Listing 10.80 Eigene Kennwortrichtinie im Base64-Format
root@provider01:~# base64 mypolicy bWluUXVhbGl0eSA4CmNoZWNrUkROIDAKY2hlY2tBdHRyaWJ1dGVzIG1haWwKZm9yYmlkZG VuQ2hhcnMgCm1heENvbnNlY3V0aXZlUGVyQ2xhc3MgMwp1c2VDcmFja2xpYiAxCmNyYWNr bGliRGljdCAvdmFyL2NhY2hlL2NyYWNrbGliL2NyYWNrbGliX2RpY3QKY2xhc3MtdXBwZX JDYXNlIEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaIDIgMSAzCmNsYXNzLWxvd2VyQ2Fz ZSBhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiAyIDEgMwpjbGFzcy1kaWdpdCAwMTIzND U2Nzg5IDEgMSAwCmNsYXNzLXNwZWNpYWwgQD0/LC47Oi0rKi8gCmNsYXNzLXVtbGF1dCDD pMO2w7zDhMOWw5zDnyAwIDEgMAo=
Dieser Base64-kodierte Wert muss nun Ihrer Kennwortrichtlinie hinzugefügt werden. Listing 10.81 zeigt Ihnen eine entsprechende LDIF-Datei als Beispiel:
Listing 10.81 Hinzufügen der kodierten Richtlinie
dn: cn=default,ou=policies,dc=example,dc=net changetype: modify add: pwdCheckModuleArg pwdCheckModuleArg:: bWluUXVhbGl0eSA4CmNoZWNrUkROIDAKY2hlY2tBdHRyaWJ1dG VzIG1haWwKZm9yYmlkZGVuQ2hhcnMgCm1heENvbnNlY3V0aXZlUGVyQ2xhc3MgMwp1c2V DcmFja2xpYiAxCmNyYWNrbGliRGljdCAvdmFyL2NhY2hlL2NyYWNrbGliL2NyYWNrbGli X2RpY3QKY2xhc3MtdXBwZXJDYXNlIEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaIDIgM SAzCmNsYXNzLWxvd2VyQ2FzZSBhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiAyIDEgMw pjbGFzcy1kaWdpdCAwMTIzNDU2Nzg5IDEgMSAwCmNsYXNzLXNwZWNpYWwgQD0/LC47Oi0 rKi8gCmNsYXNzLXVtbGF1dCDDpMO2w7zDhMOWw5zDnyAwIDEgMAo=
Wichtig: Beachten Sie zum einen die beiden Doppelpunkte beim Attribut pwdCheck-ModuleArg. Damit wird beim Anwenden der LDIF-Datei angezeigt, dass dieses Argument nicht mehr kodiert werden muss. Sie können die dann folgende Base64-kodierten Zeichenkette auch in einer Zeile hinzufügen. Wollen Sie wie in Listing 10.81 z. B. der Lesbarkeit halber in mehreren Zeilen in die LDIF-Datei einfügen, so müssen Sie jede Folgezeile mit einem Leerzeichen beginnen. Damit geben Sie an, dass die vorige Zeile fortgesetzt wird.
Um später die Richtlinie zu ändern, müssten Sie Ihre Datei den Werten für die Richtlinie anpassen, Base64-kodieren und den sich ergebenden Wert in die Eigenschaft pwdCheck-ModuleArg eintragen. Um die Richtlinie später direkt zu bearbeiten, können Sie auf das Apache Directory Studio zurückgreifen. Mit einem Doppelklick auf das Attribut pwdCheck-ModuleArg Ihrer Kennwortrichtlinie öffnet sich ein Hex-Editor wie in Bild 10.4 zu sehen.
Bild 10.4 Öffnen der Eigenschaft pwdCheckModuleArg
Klicken Sie auf ALS TEXT BEARBEITEN, so öffnet sich ein zweites Fenster. Hier können Sie dann, wie in Bild 10.5 gezeigt, die Richtlinie editieren. Durch zweimaliges Bestätigen mit OK speichern Sie die Änderungen ab.
Bild 10.5 Editieren der dekodierten Eigenschaft
10.3.5 | autoca |
Zertifikate zur Authentifizierung und Autorisierung sind in der heutigen Praxis unumgänglich. Das Overlay autoca unterstützt Sie bei der Erstellung und Verwaltung von Schlüsselpaaren und der dazugehörigen Zertifikate. Beim Start des LDAP-Servers prüft dieser in der jeweiligen Datenbank das Vorhandensein von Werten für die binären Attribute caCertificate und caPrivateKey des Root-Elements. Sind diese vorhanden, werden sie für die spätere Erstellung von Zertifikaten verwendet. Existieren die beiden Einträge noch nicht, werden sie erstellt. Somit besitzt das Verzeichnis automatisch die nötigen Angaben einer Stamm-Zertifizierungsstelle. Als DistinguishedName des Zertifikats wird standardmäßig der DistinguishedName des Objekts verwendet, für welches ein Zertifikat erstellt wird.
Die Benutzer und Server im Verzeichnis erhalten nun aber nicht direkt nach dem Start des Dienstes einen privaten Schlüssel und das dazugehörige Zertifikat. Diese werden erst in dem Moment erstellt, sobald eine Suche nach einem der beiden Attribute userCertificate und userPrivateKey für ein Objekt durchgeführt wird.
Hinweis: Die privaten Schlüssel in den binären Attributen cAPrivateKey und userPrivateKey müssen vor unbefugtem Zugriff über ACLs geschützt werden. Beide Attribute erben ihre Rechte vom Attribut pKCS8PrivateKey. Es ist daher dringend angeraten, eine ACL beispielsweise in der Form access to attrs=pKCS8PrivateKey by self ssf=128 write einzurichten.
10.3.5.1 | Einrichtung von autoca |
Zum Laden des Moduls können Sie folgende LDIF-Datei verwenden:
Listing 10.82 Laden des autoca-Moduls
dn: cn=module{0},cn=config changetype: modify add: olcModuleload olcModuleload: autoca.la
Für die Konfiguration – hier mit den Standardwerten – des Moduls finden Sie im folgenden Listing ein Beispiel:
Listing 10.83 Konfiguration des autoca-Overlays
dn: olcOverlay={0}autoca,olcDatabase={2}mdb,cn=config objectClass: olcAutoCAConfig objectClass: olcOverlayConfig olcOverlay: {0}autoca olcAutoCADays: 3652 olcAutoCAKeybits: 4096 olcAutoCAserverClass: ipHost olcAutoCAserverDays: 1826 olcAutoCAserverKeybits: 4096 olcAutoCAuserClass: person olcAutoCAuserDays: 365 olcAutoCAuserKeybits: 4096
Zu den einzelnen Parametern:
userClass <objectClass> und serverClass <objectClass>
Diese Werte definieren die Objektklassen fest, welche als Benutzer bzw. Server behandelt werden sollen.
CAKeybits <integer>, userKeybits <integer> und serverKeybits <integer>
Diese Parameter legen die Länge für den privaten Schlüssel der CA, die Benutzer bzw. Server fest. Der Standardwert ist jeweils 2048 und muss mindestens 512 betragen.
CADays <integer>, userDays <integer> und serverDays <integer>
In diesen Werten definieren Sie die Gültigkeitsdauer (in Tagen) der jeweiligen Zertifikate. Die Standardwerte lauten dabei 3652 (zehn Jahre) für das CA-Zertifikat, 365 (ein Jahr) für die Benutzer- und 1862 (fünf Jahre) für die Server-Zertifikate.
Nach dem Import der Konfiguration finden Sie im Stammobjekt die beiden neuen Attribute cACertificate und cAPrivateKey. Eine Suche mit ldapsearch nach dem Stammobjekt liefert Ihnen dann den Schlüssel und das Zertifikat wie in Listing 10.84 aufgezeigt:
Listing 10.84 Neue Attribute des Stammobjekts
provider01:~# ldapsearch -Y EXTERNAL -H ldapi:/// -b dc=example,dc=net ’(dc=example)’ -LLL dn: dc=example,dc=net objectClass: domain objectClass: dcObject objectClass: autoCA dc: example cACertificate;binary:: MIIDcDCCAligAwIBAgIJAInM7gYYSDVTMA0GCSqGSIb3DQEBCwUAMC4 xEzARBgoJkiaJk/IsZAEZDANuZXQxFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMB4XDTIzMDQxMjE1 [...] rpQciHRwXyXkXjwr07NVq6VbkasBbYf3RfbtT4lnPNIdYQ= cAPrivateKey;binary:: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDHOKan i0YpezfSdWgYDz+9g1PtCWOneTuEp27ZhmzVjAVIDUHp7JGjtzz2KH1z/PbrQZPZqXwi6MDuC7Lph [...] ZSHp/2k6PA8WXci/jM0R5JayRiZ6cQ==
Mit dem Apache Directory Studio lässt sich das Zertifikat anzeigen. In Bild 10.6 sehen Sie zunächst die beiden Attribute des Stammobjekts der Datenbank. Der private Schlüssel liegt im Format PKCS#8 vor.
Bild 10.6 CA-Attribute des Stammobjektes
Mit einem Doppelklick auf das Attribut caCertificate können Sie sich die Details des Zertifikats anzeigen lassen. In Bild 10.7 sehen Sie dazu ein Beispiel.
10.3.5.2 | Automatische Erzeugung von Schlüsselmaterial |
Wenn Sie nun eine Suche nach einem Ihrer Benutzer durchführen, wird dieser noch keinen privaten Schlüssel und kein Zertifikat besitzen, wie das Beispiel in Listing 10.85 zeigt.
Listing 10.85 Suche nach den Attributen eines Benutzers
provider01:~# ldapsearch -D cn=admin,dc=example,dc=net -H ldap://provider01 -x -w geheim -b ou=users,dc=example,dc=net "(cn=certuser)" -LLL dn: cn=certuser,ou=users,dc=example,dc=net cn: certuser sn: User objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person objectClass: top
Stellen Sie die gleiche Suche an und suchen dabei explizit nach den beiden Attributen user-Certificate und userPrivateKey, dann dauert die Suche eventuell ein bisschen länger, da der Server in diesem Moment zunächst den privaten und öffentlichen Schlüssel er- und das zugehörige Zertifikat ausstellen muss. Das Overlay reagiert auf Anfragen, welche ausschließlich diese beiden Attribute suchen und wenn diese als binary-Attribute gesucht werden. In Listing 10.86 finden Sie ein entsprechendes Beispiel. Beachten Sie dabei, dass Sie bei der Suche nach den beiden Attributen userCertificate und userPrivateKey explizit das Format binary zusätzlich mit angeben müssen.
Bild 10.7 Beispiel eines CA-Zertifikats
Listing 10.86 Suche zur Erstellung von Schlüsselmaterial
provider01:~# ldapsearch -D cn=admin,dc=example,dc=net -H ldap://provider01 -x -w geheim -b ou=users,dc=example,dc=net "(cn=certuser)" -LLL "userCertificate;binary" "userPrivateKey;binary" dn: cn=certuser,ou=users,dc=example,dc=net userCertificate;binary:: MIIEtjCCA56gAwIBAgIJAKAHqv4tenDlMA0GCSqGSIb3DQEBCwUAM C4xEzARBgoJkiaJk/IsZAEZDANuZXQxFzAVBgoJkiaJk/IsZAEZDAdleGFtcGxlMB4XDTIzMDQxMj [...] TVG79r8pKOAQD6KfsXKYA== userPrivateKey;binary:: MIIJRQIBADANBgkqhkiG9w0BAQEFAASCCS8wggkrAgEAAoICAQDsjd e51OTMaC3xNLlnRhn2pmH/2mxcseJ9Gf7iodsPjvVf7WhNflalF5xbSJrwmOmVxgT0tEDsUg9AP24 [...] 9o6cQVSxx1oMogGXQI54Q1jAKxTqasuktgZw==
Hinweis: Zum aktuellen Zeitpunkt existiert noch kein Automatismus zum Erneuern, Zurückziehen oder Löschen eines Zertifikats. Dies lässt sich nur durch manuelles Löschen der Attribute erreichen. Bei einer erneuten Suche werden dann neue Schlüssel und Zertifikate erstellt.
10.3.6 | homedir |
Mit diesem Overlay können Sie den Standort der Home-Verzeichnisse Ihrer LDAP-Benutzer den lokalen Gegebenheiten anpassen. Bei der Authentifizierung eines Benutzers der Klasse posixAccount an einem PAM-fähigen Client wird das Attribut homeDirectory ausgelesen. Das homedir-Overlay vergleicht den Wert mit den von Ihnen konfigurierten regulären Ausdrücken und ändert es gegebenenfalls. Darüber hinaus können Sie steuern, wie mit den Benutzerverzeichnissen gelöschter Benutzerobjekte verfahren werden soll.
10.3.6.1 | Einrichten des Overlays homedir |
Zum Laden des entsprechenden Moduls können Sie beispielsweise die folgende LDIF-Datei verwenden:
Listing 10.87 Laden des homedir-Overlays
dn: cn=module{0},cn=config changetype: modify add: olcModuleload olcModuleload: homedir.la
Ein Beispiel für die Konfiguration in der Benutzerdatenbank finden Sie in folgender LDIF-Datei:
Listing 10.88 Beispiel einer Konfiguration für homedir
dn: olcOverlay=homedir,olcDatabase={2}mdb,cn=config objectClass: olcOverlayConfig objectClass: olcHomeDirConfig olcOverlay: homedir olcSkeletonPath: /etc/skel olcMinimumUidNumber: 1000 olcHomedirRegexp: ^(/home/[-_/a-z0-9]+)$ /ldapuser$1 olcHomedirDeleteStyle: ARCHIVE
Zu den einzelnen Parametern:
olcSkeletonPath
Mit diesem Parameter legen Sie das Verzeichnis fest, aus welchem das neu zu erstellende Home-Verzeichnis eines Benutzers seine ersten Dateien bekommt. Die Dateien werden kopiert und anschließend die entsprechenden Rechte für den Benutzer und seine primäre Gruppe vergeben.
olcMinimumUidNumber
Um beispielsweise Systemkonten von dem Automatismus auszuschließen, sollten Sie mit diesem Parameter die Untergrenze von UIDs angeben, für welchen er greift.
olcHomedirRegexp
Mit diesem Parameter verändern Sie den eigentlich im Benutzerobjekt befindlichen Pfad für das Benutzerverzeichnis und passen es den Bedürfnissen an. Im vorliegenden Beispiel in Listing 10.88 wird allen Benutzern, deren Attribut homeDirectory dem regulären Ausdruck ^(/HOME/[-_/A-Z0-9]+)$ entspricht, ein Benutzerverzeichnis unterhalb von /LDAPUSER zugewiesen. Der Parameter $1 entspricht dabei dem ursprünglichen Wert des Benutzerverzeichnisses.
olcHomedirDeleteStyle
Hiermit legen Sie fest, wie mit einem Benutzerverzeichnis verfahren werden soll, wenn der Benutzer – oder sein Attribut homeDirectory – gelöscht wird. Sie haben dabei folgende Möglichkeiten:
IGNORE : Das Benutzerverzeichnis bleibt erhalten.
DELETE : Das Benutzerverzeichnis wird gelöscht.
ARCHIVE: Das Benutzerverzeichnis wird in einem Tarball archiviert.
10.3.7 | otp |
Um zukünftig die Sicherheit einer IT-Umgebung zu gewährleisten, kommt man um eine Multi-Faktor-Authentifizierung nicht herum, also um eine mehrstufige Anmeldung. Eine Möglichkeit der Implementierung einer MFA-Lösung bietet Ihnen das Overlay otp, welches die Authentifizierung eines LDAP-Benutzers um ein One-Time-Password erweitert.
10.3.7.1 | Serverseitige Einrichtung von otp |
Zunächst muss natürlich wieder einmal das entsprechende Modul geladen werden. Eine mögliche LDIF-Datei finden Sie in Listing 10.89.
Listing 10.89 Laden des otp-Moduls
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: otp.la
Damit Sie das Overlay für Ihre Benutzer verwenden können, muss es nun für die Datenbank eingerichtet werden. Listing 10.90 zeigt Ihnen dafür ein Beispiel.
Listing 10.90 Beispielkonfiguration für das olc-Overlay
dn: olcOverlay=otp,olcDatabase={2}mdb,cn=config objectClass: olcOverlayConfig olcOverlay: otp
10.3.7.2 | Definition der Vorgaben für die OTP-Authentifizierung |
Im Folgenden richten Sie die Vorgaben für eine mehrstufige Anmeldung ein. Die Parameter dafür können Sie dabei wie in Listing 10.91 in einer OU festlegen und später vom Benutzer aus auf diese verweisen. Dazu muss die entsprechende OU um die Klasse oathTOTP-Params erweitert werden.
Listing 10.91 Vorgaben für die OTP-Anmeldung
dn: ou=users,dc=example,dc=net changetype: modify add: objectClass objectClass: oathTOTPParams - add: oathOTPLength oathOTPLength: 6 - add: oathHMACAlgorithm oathHMACAlgorithm: 1.2.840.113549.2.7 - add: oathTOTPTimeStepPeriod oathTOTPTimeStepPeriod: 30 - add: oathTOTPTimeStepWindow oathTOTPTimeStepWindow: 3
Zu den einzelnen Parametern:
oathOTPLength
Hiermit legen Sie die Länge des OTP-Tokens für den zweiten Faktor fest.
oathHMACAlgorithm
Tragen Sie hier ein, welchen Hash-Algorithmus (HMAC=Hash Message Authentication Code) Sie verwenden wollen. Zur Wahl stehen SHA1, SHA224, SHA256, SHA384 und SHA512. Für den Parameter verwenden Sie als Wert die jeweilige OID aus Tabelle 10.2, wie sie gemäß RFC8018 definiert ist.
Tabelle 10.2 Liste der OIDs der zu verwendenden Hashalgorithmen
SHA1 |
1.2.840.113549.2.7 |
SHA224 |
1.2.840.113549.2.8 |
SHA256 |
1.2.840.113549.2.9 |
SHA384 |
1.2.840.113549.2.10 |
SHA512 |
1.2.840.113549.2.11 |
oathTOTPTimeStepPeriod
Legen Sie mit diesem Parameter die Zeit (in Sekunden) für die Erstellung eines Tokens fest.
oathTOTPTimeStepWindow
Mit diesem Parameter definieren Sie die Anzahl von TimeStep-Perioden, in welcher eine Tokenprüfung stattfindet. In unserem Beispiel hat der Benutzer also 3*30=90 Sekunden Zeit von der Erstellung des Tokens bis zum Ablauf, bevor ein neues Token erstellt wird.
Weitere Parameter finden Sie in den Manuals von slapo-otp.
10.3.7.3 | Einrichten von OTP für die Benutzer per Skript |
Als Letztes sind nun noch Änderungen am Benutzerobjekt für ein OTP durchzuführen. Dieser benötigt unter anderem einen individuellen Key, aufgrund dessen in der Folge jeweils das Einmalkennwort generiert werden kann. Wir haben ein Skript zusammengestellt, welches unter Angabe des Benutzer-DN und einer E-Mail-Adresse alle notwendigen Änderungen für einen Benutzer durchführt. Am Ende wird zudem noch ein QR-Code generiert, welchen der Benutzer in einer Authenticator-App verwenden kann, um zukünftig seinen TOTP-Code zu erzeugen. Dieser Code wird bei einer Anmeldung direkt an das Kennwort angefügt, sodass in unserem Beispiel dem Kennwort geheim zukünftig sechs Ziffern angefügt werden müssen. Speichern Sie das Skript aus Listing 10.92 z.B. als CREATE2FS.SH ab.
Listing 10.92 Skript zur Erweiterung eines Benutzers zur Verwendung von TOTP
#!/bin/bash # # Benutzer-DN und Email-Adresse werden benoetigt if [ $# -ne 2 ] then echo "User-DN and User-Mail is needed" echo "usage: $0 userdn user@mail" exit 1 fi # Setzen der verwendeten Variablen BASE_DN="dc=example,dc=net" USER_DN=$1 USER_MAIL=$2 USER_OU="ou=users,dc=example,dc=net" LDAP_SERVER=ldap://provider01.example.net USE_LDAPI=1 # set to "0" if userlogin is prefered USE_TLS=1 # if TLS should not be used set to "0" LDAP_ADMIN="cn=admin,dc=example,dc=net" LDAP_ADMIN_PW="geheim" TOPT_ISSUER=stka USER_NAME="" PATH_FOR_SHARED_KEY="/root/sharedkey" USER_SHARED_KEY="" QR_TEXT="" SALT_LENGTH=20 if [ ! -d $PATH_FOR_SHARED_KEY ] then mkdir $PATH_FOR_SHARED_KEY fi if [ "$USE_TLS" -eq 1 ] then ACTIVATE_TLS="-ZZ" else ACTIVATE_TLS="" fi # zur Generierung des QR-Codes wird qrencode genutzt if [ ! -f "/usr/bin/qrencode" ] then echo "qrencode is not installed!" exit 2 fi USER_NAME=$(echo "$USER_DN" | cut -d "," -f 1) # Benutzer vorhanden? if [ $USE_LDAPI -eq 1 ] then USER_DN_IN_DB=$(ldapsearch -Q -Y EXTERNAL -LLL -H ldapi:/// \ -b $BASE_DN $USER_NAME dn 2>/dev/null | cut -d" " -f2) else USER_DN_IN_DB=$(ldapsearch -xLLL "$ACTIVATE_TLS" -D "$LDAP_ADMIN" \ -w "$LDAP_ADMIN_PW" -H "$LDAP_SERVER" -b $BASE_DN ’($USER_NAME)’ dn\ 2>/dev/null | cut -d " " -f 2) fi if [ "${USER_DN,,}" != "${USER_DN_IN_DB,,}" ] then echo "User $USER_DN not found in database" exit 4 fi USER_OU=${USER_OU,,} # Erstellen des Benutzer-Keys USER_SHARED_KEY="${PATH_FOR_SHARED_KEY}/${USER_NAME}-sharedkey.data" touch $USER_SHARED_KEY chmod 600 $USER_SHARED_KEY openssl rand $SALT_LENGTH > $USER_SHARED_KEY USER_SHARED_KEY_BASE32=$(base32 $USER_SHARED_KEY) echo $USER_SHARED_KEY_BASE32 > ${PATH_FOR_SHARED_KEY}/${USER_NAME}-sharedkey.b64 # LDIF-Datei um den Benutzer zu aendern while read LINE do echo $LINE >> $PATH_FOR_SHARED_KEY/${USER_NAME}-totp.ldif done << EOT dn: $USER_DN changetype: modify add: objectClass objectClass: oathTOTPToken - add: oathTOTPParams oathTOTPParams: $USER_OU - add: oathSecret oathSecret:< file://$USER_SHARED_KEY - add: objectClass objectClass: oathTOTPUser - add: oathTOTPToken oathTOTPToken: $USER_DN EOT if [ $USE_LDAPI -eq 1 ] then ldapmodify -Q -Y EXTERNAL -H ldapi:/// \ -f $PATH_FOR_SHARED_KEY/${USER_NAME}-totp.ldif else ldapmodify -x "$ACTIVATE_TLS" -D "$LDAP_ADMIN" -w "$LDAP_ADMIN_PW" \ -H "$LDAP_SERVER" -f $PATH_FOR_SHARED_KEY/${USER_NAME}-totp.ldif fi # Erstellen des QR-Codes QR_TEXT="otpauth://totp/$LDAP_SERVER:$USER_MAIL?secret=${USER_SHARED_KEY_BASE32}&issuer=${TOTP_ISSUER}&period=30&digits=6&algorithm=SHA1" echo $QR_TEXT | qrencode -s9 -o $PATH_FOR_SHARED_KEY/${USER_MAIL}.png # Informationen ausgeben echo "Der Key für den Benutzer $USER_DN lautet $USER_SHARED_KEY_BASE32" echo "Sie finden den Key in binärem Format unter $USER_SHARED_KEY" echo "Der QR-Code wurde in der Datei ${USER_MAIL}.png abgespeichert"
Nehmen wir einen neuen Benutzer wie cn=otpuser,ou=users,dc=example,dc=net. Rufen Sie dieses Skript dann wie folgt auf:
Listing 10.93 Aufruf des Skriptes zur Erstellung der OTP-Informationen
create2fa.sh cn=otpuser,ou=users,dc=example,dc=net otpuser@example.net
so erzeugt das Skript den Key für den Benutzer, erstellt eine LDIF-Datei zur Erweiterung und Änderung des Benutzers, importiert diese und generiert einen passenden QR-Code. In Listing 10.94 sehen Sie die Ausgaben des Skripts:
Listing 10.94 Ausgabe des Skriptes
modifying entry "cn=otpuser,ou=users,dc=example,dc=net" Der Key für den Benutzer cn=otpuser,ou=users,dc=example,dc=net lautet 5TOTOWPTFKTIBQB4HO5KU5SJCPGZM3AV Sie finden den Key in binärem Format unter /root/sharedkey/cn=otpuser-sharedkey.data Der QR-Code wurde in der Datei otpuser@example.net.png abgespeichert.
Den QR-Code bzw. das Bild mit dem QR-Code kann der Benutzer nun zum Beispiel mit einer Authenticator-App am Handy einlesen. Der dann dort generierte sechsstellige Code muss nun bei der Authentifizierung dem Kennwort hinzugefügt werden.
10.3.7.4 | Einrichten von OTP für die Benutzer über LAM SelfService |
Mit der LAM Pro Version haben Sie die Möglichkeit, ein SelfService-Portal für die Benutzer einzurichten. Über dieses Portal können Sie den Benutzern diverse Möglichkeiten verschaffen, die eigenen Informationen selber zu editieren. Im Falle von OTP können die Benutzer die Einrichtung des zweiten Faktors auch selber übernehmen.
Zunächst einmal müssen Sie den SelfService einrichten. Dazu müssen Sie ein entsprechendes PROFIL anlegen. Klicken Sie dazu auf der Startseite des LAM oben rechts auf LAM EINSTELLUNGEN und im folgenden Fenster auf SELFSERVICE BEARBEITEN. Als Nächstes wählen Sie SELFSERVICE-PROFILE VERWALTEN aus und erstellen ein neues Profil, beispielsweise unter dem Namen Benutzerportal. Klicken Sie HINZUFÜGEN und geben Sie das Master-Kennwort ein. Nun sollten Sie ein Bild ähnlich wie das in Bild 10.8 sehen. Tragen Sie hier nun die entsprechenden Werte ein. Als LDAP USER genügt hierbei ein Benutzerobjekt mit reinem Lesezugriff auf die LDAP-Datenbank. Dieser dient lediglich zur Suche nach dem Benutzer, der sich am Portal anmelden möchte. Achten Sie beim LDAP SUCHATTRIBUT darauf, dass dies für Ihre Benutzer auch gesetzt ist, da dies das Attribut ist, welches das Portal als Anmeldenamen verwendet.
Bild 10.8 Erstellen eines SelfService-Profils
Auf dem Karteireiter SEITENLAYOUT fügen Sie nun unter FELD HINZUFÜGEN das zusätzliche EINGABEFELD NEUEN TOKEN REGISTRIEREN aus der Gruppe OPENLDAP TOTP hinzu, wie in Bild 10.9 zu sehen ist. Das Ergebnis sollte ähnlich wie in Bild 10.10 aussehen.
Bild 10.9 Anpassen der SelfService-Seite
Als Letztes wechseln Sie noch auf den Karteireiter MODULEINSTELLUNGEN. Im Abschnitt OPENLDAP TOTP tragen Sie hier den DistinguishedName des Objekts ein, in welchem die OTP PARAMETER konfiguriert sind. In unserem Beispiel ist dies die organisatorische Einheit ou=users,dc=example,dc=net, wie Sie in Bild 10.11 sehen. Speichern Sie das neue Profil mit einem Klick auf SPEICHERN ab. Die URL des neu erstellten Portals lautet in unserem Beispiel
http://lam.example.net/lam/templates/selfService/selfServiceLogin.php?name=Benutzerportal&scope=user
Hier kann sich ein Benutzer nun mit seinem Kennwort anmelden und unter PERSÖNLICHE DATEN mit einem Klick auf QR-CODE GENERIEREN die Zwei-Faktor-Authentifizierung über ein TOTP aktivieren und zeitgleich einen QR-Code zur Verwendung in einer Authenticator App generieren (siehe Bild 10.12).
Bild 10.10 Angepasste SelfService-Seite
Bild 10.11 Konfiguration des TOTP-Moduls
Bild 10.12 Konfiguration des TOTP-Moduls
10.3.8 | remoteauth |
Es kann Situationen geben, in welchen Sie ein OpenLDAP-Verzeichnis für eine Anwendung nutzen wollen, allerdings für die Authentifizierung ein separates LDAP-Verzeichnis wie ActiveDirectory nutzen möchten. Dies kann auch nur einen Teil der Benutzer betreffen, wenn diese aus anderen Bereichen oder externen Unternehmen stammen.
Um die Anmeldung für den Benutzer transparent zu gestalten, können Sie das Overlay remoteauth verwenden. Der Client führt in dem Fall seine SimpleBind-Operation an sein OpenLDAP-Verzeichnis durch. Dieses sendet dann seinerseits eine entsprechende Bind-Anfrage an ein separates LDAP-Verzeichnis und schickt die Rückmeldung anschließend zurück an den Client. Ob eine solche Pass-Through-Operation durchgeführt werden muss, entscheidet der OpenLDAP-Server anhand des (Nicht-)Vorhandenseins eines Wertes im Attribut userPassword des Benutzers. Ist ein Wert vorhanden, führt der OpenLDAP-Server die Authentifizierung selbst durch. Ist der Wert leer, so leitet der Server die Anfrage weiter.
10.3.8.1 | Einrichtung von remoteauth |
Zunächst benötigen wir wie gehabt das entsprechende Modul. Dies können Sie z.B. mit folgender LDIF-Datei laden:
Listing 10.95 Laden des remoteauth-Moduls
moduleload syncprov dn: cn=module{0},cn=config changetype: modify add: olcModuleload olcModuleload: remoteauth.la
Als Nächstes erfolgt die Konfiguration des Overlays für Ihre Datenbank. Hierzu legen Sie eine LDIF-Datei ähnlich der in Listing 10.96 an und importieren diese:
Listing 10.96 Konfiguration des Overlays remoteauth
dn: olcOverlay=remoteauth,olcDatabase={2}mdb,cn=config objectClass: olcOverlayConfig objectClass: olcRemoteAuthCfg olcOverlay: remoteauth olcRemoteAuthDNAttribute: seeAlso olcRemoteAuthDomainAttribute: o olcRemoteAuthDefaultDomain: remote olcRemoteAuthMapping: consulting provider01.consulting.de olcRemoteAuthMapping: remote provider01.remote.net
Die vollständige Liste der Parameter:
olcRemoteAuthMapping
Für Umgebungen ohne Windows-Domänen stellen Sie hier eine Verbindung zwischen Domänennamen und einer Liste von Hosts her, welche für die Authentifizierung in dieser Domäne verwendet werden sollen. Das Attribut enthält neben dem Namen der Domäne
den FQDN eines Servers, wie provider01.remote.net
eine LDAP-URI, wie ldap://provider01.remote.net
den lokalen Pfad auf dem LDAP-Server zu einer Datei mit einer Liste von FQDNs, wie file:///opt/symas/etc/openldap/remote/remote.net.hosts
olcRemoteAuthDefaultRealm
Hier können Sie den FQDN eines Servers eintragen, welcher Verwendung findet, wenn eine Domäne eines Benutzers unter olcRemoteAuthMapping nicht aufgeführt ist.
olcRemoteAuthDNAttribute
Hier legen Sie fest, in welchem Attribut sich die Bind-Informationen eines Benutzers im entfernten LDAP-Verzeichnis befinden. Ein Beispiel wäre das Attribut seeAlso.
olcRemoteAuthDomainAttribute
Dieser Wert enthält das Attribut eines Benutzers, welches den Domänennamen für die entfernte Anmeldung festlegt.
olcRemoteAuthDefaultDomain
Besitzt das Attribut, welches Sie mit olcRemoteAuthDomainAttribute festgelegt haben, bei einem Benutzer keinen Wert, so legen Sie hier die Standard-Domäne fest, die verwendet werden soll.
olcRemoteAuthStore
Falls das Kennwort des Benutzers aus dem entfernten Verzeichnis im lokalen Benutzerobjekt zwischengespeichert werden soll, setzen Sie diesen Wert auf on, andererseits auf off.
olcRemoteAuthRetryCount
Standardmäßig versucht der lokale LDAP-Server dreimal, eine Verbindung zum externen Verzeichnis aufzunehmen. Möchten Sie einen anderen Wert verwenden, dann ist dies der Ort dafür.
olcRemoteAuthTLS
Hier legen Sie die TLS-Parameter für remoteauth fest. Für die Details werfen Sie bitte einen Blick ins Kapitel 4 «Einrichten von TLS».
olcRemoteAuthTLSPeerkeyHash
Hier können Sie die Zuordnungen zwischen einem entfernten Server und dem Hashwert seines öffentlichen Schlüssels festlegen.
In unserem Beispiel wird also beim Fehlen des Kennworts eines Benutzers der Wert des Attributs o ausgelesen, um ggf. den Namen der entfernten (Anmelde-)Domäne herauszufinden, in welcher sich das Benutzerobjekt befindet. Ist in diesem Attribut des Benutzers kein Wert eingetragen, wird remote als Domänenname verwendet. Als Anmeldename wird der Wert des Attributs seeAlso des Benutzers genutzt. Für die entfernte Anmeldung an der Domäne consulting wird der FQDN provider01.consulting.de verwendet, für remote der Server provider01.remote.net.
Nehmen wir einen Benutzer cn=berater, welcher im lokalen Verzeichnis kein Kennwort besitzt. In Bild 10.13 sehen Sie die verwendeten Attribute des Benutzers.
Bild 10.13 Attribute eines Benutzers ohne lokales Kennwort
Testet man nun die Anmeldung beispielsweise mit ldapwhoami, so zeigt Listing 10.97 die erfolgreiche Anmeldung:
Listing 10.97 Erfolgreiche Pass-Through-Authentifizierung
root@provider01:~# ldapwhoami -D cn=berater,ou=users,dc=example,dc=net -W\ -H ldap://provider01.example.net \ Enter LDAP Password: dn:cn=berater,ou=users,dc=example,dc=net
10.3.9 | syncprov |
Hier greifen wir nun vor auf das Kapitel 12, «Replikation des OpenLDAP-Baums». Die Bezeichnung des Overlays syncprov steht an dieser Stelle für SYNChronization PROVider .Mit dem Aktivieren dieses Moduls für eine Datenbank stellen Sie die nötigen Informationen bereit, welche für die Replikation dieser Datenbank mit anderen LDAP-Servern benötigt werden. Das Overlay bzw. die zusätzlichen Informationen, welche dieses Overlay liefert, stellen sicher, dass alle an der Replikation beteiligten Server einer Datenbank stets den aktuellen Stand besitzen. Wozu die Replikation gut ist, wie sie eingerichtet wird, was es zu beachten gilt etc., da sei an dieser Stelle Lehrer Bömmel aus dem Buch Die Feuerzangenbowle von Heinrich Spoerl zitiert: „Dat krieje mer später.“.
Das syncprov-Overlay erstellt ein neues Attribut namens contextCSN für das Wurzelobjekt einer Datenbank. Eine Change Sequence Number gibt den aktuellen Zeitstempel eines Objekts an. Dieser besitzt die Form: YYYYmmddHHMMSSz.uuuuuu#<Zähler>#<ServerID> #000000. Dabei stehen die Felder für die in Tabelle 10.3 aufgelisteten Werte:
Tabelle 10.3 Aufbau einer Change Sequence Number
YYYY |
Jahreszahl (0001-9999) |
mm |
Monat (01-12) |
dd |
Tag (01-31) |
HH |
Stunde (00-23) |
MM |
Minute (00-59) |
SS |
Sekunde (00-59) |
z |
der Buchstabe ’z’ zu Kennzeichnung der Zeitzone UTC |
uuuuuu |
Mikrosekunde (000000-999999) |
<Zähler> |
hexadezimaler Zähler der Änderungen zu dem vorher angegebenen Zeitpunkt |
<ServerID> |
eindeutige hexadezimale Kennung jedes an der Replikation beteiligten Servers (OpenLDAP 2.2 und 2.3 ließen hier auch zweistellige IDs zu, was in OpenLDAP 2.4 noch unterstützt wird) |
000000 |
Wären mehrere Änderungen pro modify-Operation möglich, ließen sich diese an dieser Stelle durchnummerieren. In OpenLDAP ist dieser Wert momentan immer auf 000000, da jede Operation nur eine Änderung enthält. |
Für jede Datenbank (oder genauer: jeden Teil des DIT), welche später auf andere LDAP-Server repliziert werden soll, muss das syncprov-Overlay aktiviert werden. Die Server können dann die contextCSN ihrer Kopie der Datenbank mit denen der anderen Kopien vergleichen und feststellen, ob sie noch aktuell sind oder ob ihre lokale Kopie eine Aktualisierung benötigt. Aber darauf gehen wir wie gesagt später noch genauer ein.
Schauen wir uns nun die nötigen Änderungen für die dynamische Konfiguration an. Zunächst muss wieder das Objekt cn=module{0},cn=config um einen weiteren Eintrag zum Laden eines Moduls erweitert werden. Im Anschluss legen Sie das Konfigurationsobjekt für das Overlay unterhalb des Datenbankobjekts an. Die Listings 10.98 und 10.99 geben Ihnen Beispiele für entsprechende LDIF-Dateien.
Laden des Moduls
Listing 10.98 Laden des syncprov-Moduls
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: syncprov.la
Konfiguration des Overlays:
Listing 10.99 Konfiguration des syncprov-Overlays
dn: olcOverlay=syncprov,olcDatabase={2}mdb,cn=config changetype: add objectClass: olcSyncProvConfig objectClass: olcOverlayConfig olcOverlay: syncprov olcSpCheckPoint: 1 5 olcSpSessionlog: 100 olcSpNoPresent: FALSE olcSpReloadHint: FALSE
Die Parameter im Einzelnen:
olcSpCheckPoint <op> <min>
Nach <op> Operationen oder maximal <min>Minuten soll das Attribut contextCSN aktualisiert werden.
olcSpSessionlog <op>
führt ein Protokoll im Hauptspeicher mit maximal <op> Einträgen von Änderungen an bestehenden Objekten.
olcSpNoPresent
Ein Wert, auf den wir später bei der Replikation noch eingehen werden. Setzen Sie diesen, so wird die Present-Phase der Replikation übersprungen. Dies ist lediglich bei Datenbanken mit Protokollen (wie beim accesslog) sinnvoll.
olcSpReloadHint
Dies ist ebenfalls ein Boolescher Parameter, auf den wir später noch eingehen werden. Bei einer Delta-Synchronisation mit aktuelleren OpenLDAP-Versionen (neuer als 2.3.11) sollte dieser Parameter genutzt werden.
Nach Konfiguration wird für die Wurzelelemente einer Datenbank dann das erwähnte Attribut contextCSN geführt. Listing 10.100 zeigt Ihnen, wie Sie sich den contextCSN ausgeben lassen können:
Listing 10.100 Beispiel einer contextCSN
root@provider01:~# ldapsearch -D "cn=admin,dc=example,dc=net" -W -b "dc=example,dc=net" -s base contextCSN -LLL dn: dc=example,dc=net contextCSN: 20221110170734.401442Z#000000#000#000000
Mit diesem Rüstzeug können Sie nun eine Replikation zwischen zwei oder mehr LDAP-Servern einrichten.
10.3.10 | variant |
Als Letztes in in der Liste der neuen Overlays möchten wir Ihnen hier noch das Overlay variant vorstellen. Das Overlay erlaubt es, dass Werte von Attributen in mehreren Objekten genutzt werden können. So können Sie zum Beispiel die Mobilfunknummer des Administrators als Eintrag in der Firmen-OU einbinden. Immer wenn sich dann die Telefonnummer des Administrators ändert, ändert sich auch der Eintrag in der Firmen-OU. Wer jetzt sagt: „Das kenne ich doch schon vom Overlay collect “, hat fast recht, aber nur fast. Denn das Overlay kann etwas mehr. Bei der Verwendung von collect wird immer dasselbe Attribut bei der Quelle und dem Ziel verwendet. Das ist bei variant anders, hier können Quell- und Zielattribut unterschiedliche Attribute sein. So können Sie die Mobilnummer des Administrators im Attribut mobil beim Administrator speichern, im Objekt der Firmen-OU speichern Sie die Nummer aber unter telephonenumber.
Eine weitere Möglichkeit, den Inhalt eines Attributs bei vielen anderen Objekten zu nutzen, ist die Verwendung von regulären Ausdrücken (regex), um mal bei der Telefonnummer zu bleiben. Sie können so die Telefonnummer einer Abteilung in das Objekt der Abteilung eintragen und dann über einen regex auf alle Mitarbeiter der Abteilung automatisch verteilen. Wenn Sie das für alle Abteilungen einrichten und ein Benutzer wechselt in eine andere Abteilung, wird sich die Telefonnummer anpassen, wenn Sie den Benutzer in die entsprechende OU der neuen Abteilung verschieben.
10.3.10.1 | Einrichten mit einfachen Werten |
Bevor Sie die ersten Attribute verteilen, benötigen Sie erst das Modul und das Overlay in der Datenbank mit Ihren Benutzern. In Listing 10.101 sehen Sie die LDIF-Datei für das Laden des Moduls und der Einrichtung für das Overlay:
Listing 10.101 Laden des Overlays variant
dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: variant.la dn: olcOverlay={2}variant,olcDatabase={2}mdb,cn=config objectClass: olcVariantConfig olcVariantPassReplication: TRUE
Hinweis: Wir haben hier die Nummer 2 für die Nummer des Overlays vergeben, denn alle weiteren Einträge für Quell- und Zielattribute müssen immer direkt unterhalb des Overlay abgelegt werden. An welcher Stelle in der Liste der Overlays Sie das Overlay variant eintragen, spielt aber keine Rolle.
Erst nachdem Sie das Modul geladen und das Overlay in der Datenbank bekannt gemacht haben, können Sie die ersten Attribute einrichten. In Listing 10.102 sehen Sie das Listing für die Einrichtung ohne regex:
Listing 10.102 Einrichtung ohne Regex
dn: name=global-addr,olcOverlay={2}variant,olcDatabase={2}mdb,cn=config objectClass: olcVariantVariant olcVariantEntry: dc=example,dc=net dn: olcVariantVariantAttribute=postaladdress,name={0}global-addr,olcOverlay={2}variant,olcDatabase={2}mdb,cn=config objectClass: olcVariantAttribute olcVariantVariantAttribute: postaladdress olcVariantAlternativeAttribute: postaladdress olcVariantAlternativeEntry: ou=firma,dc=example,dc=net dn: name=company-phone,name={0}global-addr,olcOverlay={2}variant,olcDatabase={2}mdb,cn=config objectClass: olcVariantAttribute olcVariantVariantAttribute: telephonenumber olcVariantAlternativeAttribute: mobile olcVariantAlternativeEntry: cn=verw-al,ou=users,ou=verwaltung,ou=firma,dc=example,dc=net
Was passiert hier?:
dn: name=global-addr,olcOverlay=2variant,olcDatabase=2mdb,cn=config
In diesem Objekt legen Sie das Ziel fest, in dem der Wert des nachfolgenden Attributs genutzt wird. Hier soll in dc=example,dc=net dieselbe Postanschrift genutzt werden wie in der ou=firma,dc=example,dc=net.
dn: olcVariantVariantAttribute=postaladdress,name=0global-addr,olcOverlay=2variant, olcDatabase=2mdb,cn=config
Hier legen Sie fest, dass das Attribut postaladdress genutzt wird. Wobei hier sowohl bei der Quelle ou=firma,dc=example,dc=net als auch beim Ziel dc=example,dc=net dasselbe Attribut postaladdress genutzt wird.
dn: name=company-phone,name=0global-addr,olcOverlay=2variant,olcDatabase= 2mdb,cn=config
Das Prinzip ist hier identisch mit dem vorherigen Beispiel, nur dass jetzt für Quelle und Ziel unterschiedliche Attribute genutzt werden. Der Wert, der im Attribut mobile des Benutzers cn=verw-al,ou=users,ou=verwaltung,ou=firma,dc=example,dc=net steht, wird im Attribut telephonenumber von dc=example,dc=net eingetragen.
Wie Sie an dem Beispiel sehen, können Sie die Attribute eines Objekts aus Attributen aus beliebig vielen Attributen anderer Objekte mit Werten füllen. Wichtig ist nur, jedes Attribut darf nur einmal genutzt werden. Sie können zum Beispiel keine zwei Telefonnummern von unterschiedlichen Benutzern in dasselbe Objekt einfügen.
10.3.10.2 | Einrichtung mit regex |
Kommen wir jetzt zur zweiten Möglichkeit. Da werden reguläre Ausdrücke genutzt, um verschiedenen Objekten den Wert eines Attributs eines Objektes zuzuweisen. Im Beispiel wollen wir erreichen, dass alle Mitarbeiter der Verwaltung immer die Telefonnummer der ou=Verwaltung,ou=firma,dc=example,dc=net besitzen. Sehen Sie dazu die LDIF-Datei aus Listing 10.103:
Listing 10.103 Einrichtung mit regex
dn: name={1}verw-tel,olcOverlay={2}variant,olcDatabase={2}mdb,cn=config objectClass: olcVariantRegex olcVariantEntryRegex: cn=(.+),ou=users,ou=verwaltung,ou=firma,dc=example,dc=net dn: olcVariantVariantAttribute=telephoneNumber,name={1}verw-tel,olcOverlay={2}variant,olcDatabase={2}mdb,cn=config objectClass: olcVariantAttributePattern olcVariantVariantAttribute: telephoneNumber olcVariantAlternativeAttribute: telephoneNumber olcVariantAlternativeEntryPattern: ou=Verwaltung,ou=firma,dc=example,dc=net
Mit dem ersten Objekt name=1verw-tel,olcOverlay=2variant,olcDatabase=2mdb,cn=config legen Sie das Ziel fest. In unserem Beispiel alle Benutzer der Abteilung Verwaltung. Mit dem zweiten Objekt legen Sie fest, welches das Quell- bzw. das Zielattribut ist und von welchem Objekt der Wert übertragen werden soll. Wir verwenden hier im Beispiel sowohl für das Quell- als auch das Zielattribut telephoneNumber fest. Die Quelle ist ou=Verwaltung,ou=firma,dc=example,dc=net. Ändert sich die Telefonnummer der Abteilung, wird auch gleich die Telefonnummer der Mitarbeiter geändert.
Dass sich Telefonnummern für Abteilungen ändern, kommt bestimmt nicht so häufig vor, aber wenn Sie alle Abteilungen genau so einrichten und dann ein Mitarbeiter die Abteilung wechselt und Sie verschieben sein Objekt, wird auch die entsprechende Telefonnummer geändert.
Auch für die Verwendung von regex gilt: Ein Attribut darf immer nur einmal genutzt werden.
Hinweis: Noch ein nicht ganz unwichtiger Hinweis: Versuchen Sie, ein mit variant beschriebenes Attribut im Zielobjekt zu löschen, wird das mit dem Fehler Constraint Violation quittiert.
Setzen Sie das Overlay variant gezielt ein, kann Ihnen das sehr viel Arbeit ersparen, da durch eine Änderung viele Anpassungen automatisch durchgeführt werden.