8.6 LDAP
In modernen Rechnernetzen und vor allem in heterogenen Umgebungen wird auch oft das Lightweight Directory Access Protocol (LDAP) eingesetzt. LDAP ist wie NIS ein Verzeichnisdienst, der jedoch nicht auf RPC basiert. Im Vergleich zu einer normalen relationalen SQL-Datenbank hat LDAP folgende Vorteile:
- Optimiert auf Lesen
- LDAP ist für den lesenden Zugriff optimiert. Mit anderen Worten kann das Schreiben von Daten relativ lange dauern.
- Erweiterte Suchfunktionen
- Um den lesenden Zugriff auf die Daten weiter zu optimieren, stellt LDAP verschiedene, sehr flexible Suchfunktionen zur Verfügung.
- Erweiterbare Datenstrukuren
- LDAP erlaubt es, seine zugrunde liegenden Datenstrukturen – sogenannte Schemata - zu erweiteren und so den Bedürfnissen des Dienstbetreibers gerecht zu werden.
- Standardkompatibilität
- LDAP ist ein in verschiedenen RFCs spezifiziertes Protokoll, wodurch die Interoperabilität zwischen verschiedenen Implementierungen gewährleistet wird. <Hier besteht auch ein Gegensatz zu SQL: Zwar ist die SQL-Syntax auf verschiedenen Datenbaken fast gleich, jedoch gibt es Unterschiede bei komplexen Details wie Stored Procedures etc.>
- Verteilte Daten
- Die Daten eines LDAP-Baums können im Netzwerk verteilt gespeichert werden. LDAP nutzt außerdem verschiedenste Replizierungstechniken, um die Daten im Netzwerk zu verteilen und vor allem konsistent zu halten. Außerdem ist LDAP so sehr gut skalierbar.
Flexible Datenbank
LDAP eignet sich nun aber nicht nur zur Speicherung von Benutzerdaten. Aufgrund der flexiblen Struktur und der Ausrichtung auf statische, selten veränderte Daten können jegliche Informationen in einem LDAP-Baum <Ein LDAP-Verzeichnisdienst ist hierarchisch aufgebaut und besitzt somit eine Baumstrukur: eine Wurzel, einige Verzweigungen und viele Blätter.> gespeichert werden. Eine häufige Anwendung sind zum Beispiel Telefonlisten – es bietet sich an, auch weitere benutzerdefinierte Informationen in einer LDAP-Datenbank zu speichern, wenn man sie schon zur Benutzerverwaltung nutzt – oder auch eine Übersicht über verschiedene Rechner.
Ein paar Beispiele für häufig in LDAP-Datenbanken gespeicherte Daten sind:
- Benutzer
- Gruppen
- IP-Dienste und -Protokolle
- NIS-Netzwerkgruppen
- Boot-Informationen
- Mountpunkte für Dateisysteme
- IP-Hosts und -Netzwerke
- RFC-822-konforme Mailaliase
8.6.1 So funktioniert es
Bevor wir eine Beispielkonfiguration zur Benutzerverwaltung betrachten, wollen wir zuerst die Funktionsweise von LDAP anhand der OpenLDAP-Implementierung erläutern. OpenLDAP ist auf Linux und BSD standardmäßig verfügbar und kann auch auf anderen Unix-Systemen eingerichtet werden.
Ein eindeutiger Name
Ein Eintrag (engl. »entry«) in einem LDAP-Verzeichnis besteht aus Attributen (engl. »attributes«) und wird durch einen eindeutigen Namen (engl. »distinguished name«, dn) identifiziert.
cn=Sebastian,ou=members,dc=doomed-reality,dc=org
Listing 8.31 Beispiel für den dn eines Eintrags
Welche Attribute ein Eintrag haben kann, wird von dessen Objektklasse(n) bestimmt.
Diese Objektklassen sind wiederum in Schemata definiert. Dort ist festgelegt, wie die Attribute einer Objektklasse heißen, welche Werte zulässig sind und ob das Attribut unbedingt notwendig oder optional ist. Jeder Eintrag in der Datenbank besteht dann aus den Attributen der Klassen dieses Eintrags.
Die Attribute eines Eintrags besitzen einen bestimmten Namen und entsprechend einen oder auch mehrere Werte. So steht zum Beispiel der Attributname »cn« als Abkürzung für »common name« und erlaubt eine normale Zeichenkette – im Regelfall den Namen einer Person – als Argument.
Im Gegensatz dazu steht »mail« für »email-address« und erlaubt eine Mailadresse der Form johannes.ploetner@gmx.de. Aber auch binäre Daten wie die Bilddaten eines Benutzers für das Feld »jpegPhoto« sind möglich.
8.6.2 Einen LDAP-Server konfigurieren
Die Konfiguration eines LDAP-Servers beginnt mit der Definition der Wurzel des Verzeichnisbaums. Diese »base dn« wird als »dc« (engl. »domain component«) bezeichnet und setzt sich im Normalfall aus den Komponenten der Domain des zu verwaltenden Rechnernetzes zusammen. In der Konfigurationsdatei des OpenLDAP-Servers, der /etc/ldap/slapd.conf, sieht die Angabe dieses Suffixes wie folgt aus:
… # Beispiel für die Domain doomed-reality.org suffix "dc=doomed-reality,dc=org" …
Listing 8.32 Konfiguration der Wurzel des LDAP-Verzeichnisbaums
Attribute definieren
Weiterhin wichtig für die Konfiguration eines LDAP-Servers sind die verwendeten Schemata. Die in den Schema-Dateien definierten Objektklassen beinhalten schließlich die möglichen und notwendigen Attribute für eine Objektklasse.
Diese Schemata bindet man über eine include-Anweisung in derselben Konfigurationsdatei ein:
… # Schema and objectClass definitions include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/nis.schema include /etc/ldap/schema/inetorgperson.schema include /etc/ldap/schema/misc.schema …
Listing 8.33 Einbindung der Schemata
Diese Schemata kann man nun beliebig erweitern und auch eigene Definitionen hier einbinden. Wir werden später ein Beispiel betrachten, bei dem wir eine Datei »samba.schema« einbinden, um so einem Samba-Server zu erlauben, Benutzerdaten auf unserem LDAP-Server zu speichern. Mit diesen Benutzerdaten können sich dann Anwender auf Windows-PCs einloggen und sich über Samba an einer NT-Domäne anmelden. Samba selbst prüft dann die Gültigkeit des Benutzername/Passwort-Paares über LDAP.
Man darf dabei jedoch nicht vergessen, dass ein LDAP-Server in erster Linie eine Datenbank ist. Daher bietet der Server nur ein Interface – eben das Lightweight Directory Access Protocol – zum Zugriff auf die Daten.
Zugreifen müssen entsprechende Programme nun jedoch selbst: Ein E-Mail-Client könnte zum Beispiel ein Adressbuch auf LDAP-Basis bereitstellen. Dazu bräuchte er nur die Attribute von Einträgen der Objektklasse »inetOrgPerson« (wie zum Beispiel das Attribut »mail« und das Attribut »cn«, das bei Personen den vollen Namen beinhaltet) auszulesen und über ein komfortables Interface bereitzustellen.
Dagegen könnte ein Login-Dienst wie SSH oder der normale Unix-Login das vom Benutzer eingegebene Passwort mit dem im »userPassword« gespeicherten Hashwert vergleichen und so entscheiden können, ob das Passwort richtig und der Login damit erfolgreich war.
Zugriffsrechte definieren
Um entsprechende Zugriffe zu kontrollieren, braucht man natürlich noch ein Rechtesystem, das Zugriffe auf Datensätze zulässt oder verweigert. Die Zugriffsrechte auf einzelne Datensätze und Funktionen werden ebenfalls in der /etc/ldap/slapd.conf konfiguriert:
access to attrs=userPassword by dn="cn=admin,dc=doomed-reality,dc=org" write by anonymous auth by self write by * none access to * by dn="cn=admin,dc=doomed-reality,dc=org" write by * read
Listing 8.34 Beispiel für die Zugriffskontrolle
Der erste Block definiert hier den Zugriff auf das Attribut »userPassword«: Der Benutzer »cn=admin,dc=doomed-reality,dc=org« hat als Administrator Schreibrechte auf dieses Attribut. Im Gegensatz dazu hat ein anonymer, also noch nicht authentifizierter Nutzer das Recht, sich anzumelden. Ein User (»self«) darf sein eigenes Passwort noch ändern, alle anderen Zugriffe sind jedoch verboten.
Als Nächstes wird der Zugriff auf alle anderen Elemente definiert: Wieder darf admin schreiben und der Rest der Welt nur lesen.
Natürlich gibt es zur Konfiguration eines LDAP-Servers noch viel mehr zu sagen. Gerade in größeren Netzwerken möchte man die anfallende Last vielleicht auf mehrere Server verteilen und daher den Datenbestand entweder replizieren oder erst zer- und dann verteilen. Prinzipiell kann man mit OpenLDAP und anderen LDAP-Implementierungen noch viel mehr machen, jedoch gehen diese Features deutlich über den Umfang dieses Linux-Buches hinaus. Für ein kleines Setup sollten die hier vermittelten Informationen jedoch bereits ausreichen.
8.6.3 Einträge hinzufügen, verändern und löschen
Für LDAP gibt es nun die verschiedensten Benutzerschnittstellen. Vorstellen wollen wir Ihnen zwei: die ldap-utils für die Kommandozeile und das Webinterface phpldapadmin. Das Webinterface ist dabei die intuitivere Variante der Bedienung: An der linken Seite kann man den Verzeichnisbaum durchsuchen und in jeder Ebene neue Elemente hinzufügen oder vorhandene Elemente zum Editieren oder Löschen aufrufen.
Abbildung 8.2 Das Webinterface phpldapadmin
LDAP-Verzeichnis organisieren
Die Bedienung ist dabei selbsterklärend, sofern man das Prinzip von LDAP halbwegs verstanden hat. Möchte man nämlich einen neuen Eintrag in den Verzeichnisbaum einfügen, so wird man zuerst nach der Objektklasse des neuen Objekts gefragt.
Möchte man seine Daten dabei in verschiedene »Verzeichnisse« gliedern, so wird man auf der ersten Ebene meist eine »organisational unit« (ou) anlegen wollen. Als Nächstes wird man nach den für die Objektklasse unbedingt notwendigen Attributen gefragt. Bei einer ou ist dies nur deren Name, bei der Objektklasse »posixAccount« sind das jedoch die wichtigen bekannten Daten wie der Benutzername, die UID/GID, das Homeverzeichnis, die Shell ...
Das LDAP- Datenformat
Die Kommandozeilentools wie ldapmodify oder ldapadd bieten diese Komfortabilität nicht. Dort gibt man die Daten eines neuen Datensatzes im sogenannten LDIF-Format (»LDAP Data Interchange Format«) an, einem einfachen für Menschen lesbaren Textformat. Vergisst man ein notwendiges Attribut für einen neuen Eintrag, so wird dieser eben nicht eingefügt werden können.
dn: uid=cdp_xe,ou=Mitglieder,dc=doomed-reality,dc=org uid: cdp_xe givenName: Steffen sn: Wendzel cn: Steffen Wendzel userPassword: {SHA}s3SUjNlV4lEhEY4W4Uya7ut0sxE= loginShell: /bin/bash uidNumber: 2001 gidNumber: 100 homeDirectory: /home/cdp_xe shadowMin: –1 shadowMax: 999999 shadowWarning: 7 shadowInactive: –1 shadowExpire: –1 shadowFlag: 0 objectClass: top objectClass: person objectClass: posixAccount objectClass: shadowAccount objectClass: inetOrgPerson
Listing 8.35 Ein vollständiges LDIF-Beispiel für einen Benutzereintrag
Bekannte Eigenschaften
Im obigen Beispiel kann man sehr gut sehen, dass für einen Eintrag der eindeutige Name (»dn«) gleichzeitig seinen Platz im Netz festlegt: Auf dem Server dc=doomed-reality,dc=org ist der Benutzer uid= cdp_xe unterhalb des Knotens ou=Mitglieder platziert. Des Weiteren ist ebenfalls sehr gut zu erkennen, dass der Eintrag mehreren Objektklassen angehört, deren Attribute ebenfalls mit sinnvollen Werten <Im Falle eines Benutzereintrags kennen Sie diese Felder natürlich bereits aus der /etc/passwd und der /etc/shadow. Dabei wird auch bei LDAP das Passwort nicht im Klartext, sondern verschlüsselt abgespeichert.> belegt sind.
Speichert man diese Werte in einer Datei, so kann man mittels des Programms ldapadd den Datensatz auf dem Server wie folgt speichern:
# ldapadd -x -w pass -D "cn=admin,dc=..." -f new.ldif
adding new entry "uid=cdp_xe,ou=Mitglieder, dc=...org"
Listing 8.36 Einen Benutzer mit ldapadd hinzufügen
Dieser Aufruf loggt sich mit der Benutzerkennung »cn=admin,dc= doomed-reality,dc=org« und dem Passwort »pass« auf dem lokalen Server ohne eine geschützte Verbindung ein (»-x«, kann je nach Konfiguration auch weggelassen werden). Die einzufügenden Daten finden sich schließlich in der Datei new.ldif.
Einträge verändern
Möchte man nun Einträge verändern, wird man das Programm ldapmodify benutzen. Intern ist ldapadd im Übrigen auch nur ein Frontend zu ldapmodify mit dem Parameter -a. Zu unserem bekannten und einfachen LDIF-Format kommt nun noch die Aktion hinzu, die durch das changetype:-Attribut definiert wird. Es gibt an, ob man Einträge hinzufügen <Diese Aktion wird beim Aufruf des Programms über ldapadd automatisch angenommen.> (»add«), verändern (»modify«) oder löschen (»delete«) will. Beim Ändern muss man zusätzlich über das replace:-Schlüsselwort das zu ändernde Attribut angeben:
dn: uid=doomed,dc=doomed-reality,dc=org changetype: modify replace: uidNumber uidNumber: 1000 - add: mail mail: johannes.ploetner@gmx.de - delete: jpegPhoto -
Listing 8.37 Änderungen an einem Eintrag
In diesem Beispiel wird, wie unschwer zu erkennen ist, das Attribut »uidNumber« auf den Wert 1000 verändert, das Attribut »mail« mit dem entsprechenden Wert hinzugefügt und das Attribut »jpegPhoto« gelöscht. Die Änderung macht man nun ganz analog zu ldapadd wirksam:
# ldapmodify -x -w pass -D "cn=admin,dc=...,dc=org"
-f test.ldif
modifying entry "uid=doomed,ou=Mitglieder,dc=...=org"
Listing 8.38 Die Änderungen durchführen
Man muss sich also wieder auf dem Server einloggen und die Datei mit den Änderungen hochspielen. Als eine kurze Einführung in die Administration eines LDAP-Servers soll dies erst einmal genügen. Schließlich wollen wir in diesem Kapitel den Fokus auf die Benutzerverwaltung legen.
8.6.4 Die Benutzerverwaltung mit LDAP
Wir haben also gesehen, was ein LDAP-Server überhaupt ist, wie die Grundlagen der Konfiguration aussehen und zwei Beispiele für dessen Administration vorgestellt. Ein wichtiger Punkt fehlt in unserer Betrachtung jedoch noch: Wie muss man ein Clientsystem konfigurieren, sodass es zur Authentifizierung nicht nur die lokalen /etc/passwd- und /etc/shadow-Dateien, sondern auch einen LDAP-Server nutzt?
PAM ...
Die Antwort hierfür lautet PAM (»Pluggable Authentication Module«). Eigentlich alle neueren Login-Dienste setzen auf PAM als Interface zur Verifikation von Benutzerauthentifizierungen auf. Vereinfacht gesagt nimmt PAM das eingegebene Passwort und nutzt intern verschiedenste Datenbanken und Dienste, um den Login zu bestätigen.
Mit pam_ldap.so <Je nach Linux-Distribution muss man eventuell noch libnss-ldap und libpam-ldap nachinstallieren. Die entsprechenden Pakete finden sich, sofern benötigt, auf der Installations-CD der Distribution.> steht auch ein Plugin für den Support von LDAP-Servern bereit, sodass ein Login über diesen Dienst einfach zu konfigurieren ist.
Die /etc/nsswitch.conf
Als Erstes braucht man jedoch eine Möglichkeit, die unterschiedlichen Varianten zur Authentifizierung festzulegen und schließlich zu differenzieren, in welcher Reihenfolge diese abgearbeitet werden sollen. Diesen Zweck erfüllt die /etc/nsswitch.conf, die nicht nur für die Benutzerverwaltung den Zugriff auf bestimmte Daten über traditionelle Unix-Dateien, sondern auch verschiedene Netzwerkdienste koordiniert.
Möchte man bei einem Login zuerst die normalen Unix-Dateien und dann erst den LDAP-Server fragen, so sollte man die Datei wie folgt ändern:
passwd: files ldap group: files ldap shadow: files ldap …
Listing 8.39 Die angepasste /etc/nsswitch.conf
Damit fügt man offensichtlich Support für LDAP hinzu, der dann aktiv wird, falls ein Benutzername nicht in einer der normalen Dateien gefunden wurde. Oft findet man in der /etc/nsswitch.conf anstatt des files-Schlüsselworts das Wort compat: Dieses dient nur dazu, Benutzernamens die mit einem + beginnens wie früher üblich über NIS abzuwickeln – jedoch wird man in einem Netzwerk kaum LDAP und NIS parallel einsetzen, weswegen man ruhig auch files anstatt compat schreiben kann.
Diese Konfiguration regelt jedoch nur den Zugriff auf die Benutzerdaten über die Standardbibliothek glibc:
# getent passwd root:x:0:0:root:/root:/bin/bash … cdp:x:2001:100:Steffen Wendzel:/home/cdp:/bin/bash
Listing 8.40 Alle bekannten Benutzer mit getent ausgeben
…und die glibc
So kann man sich zum Beispiel mit dem Befehl getent alle bekannten Benutzer anzeigen lassen. Nach der Änderung an der /etc/nsswitch.conf zeigt das Programm nicht nur alle Benutzer aus der /etc/passwd, sondern zusätzlich auch noch die auf dem LDAP-Server eingetragenen an. Die Login-Dienste via PAM müssen jedoch extra konfiguriert werden.
Die Konfiguration von PAM
Für jeden Dienst, der die PAM-Funktionalität in Anspruch nimmt, ist in der Regel eine eigene Konfigurationsdatei mit dem Namen des Dienstes im /etc/pam.d-Verzeichnis angelegt. Dort kann man dann verschiedene Einstellungen zu den unterschiedlichen Aktionen »auth«, »account«, »password« und »session« vornehmen.
Verschiedene Dienstklassen
Die Unterschiede sind dabei nicht besonderes relevant: auth beschreibt zum Beispiel die Funktion, die Identität bestimmter Benutzer sicherzustellen, und ist damit sehr eng mit dem passwort-Dienst verbunden. Über account-Dienste kann überprüft werden, ob zum Beispiel das Passwort eines Benutzers abgelaufen ist oder ob dieser Berechtigungen für einen bestimmten Dienst hat. Analog ist der session-Dienst zu sehen, der bestimmte Sitzungsdienste wie das Mounten des Homeverzeichnisses umfasst.
Natürlich muss man nicht jede Datei editieren, die sich in diesem Verzeichnis befindet. Die meisten binden nur die folgenden Standardkonfigurationsdateien ein, die wie folgt zu editieren sind:
- common-auth
auth sufficient pam_ldap.so auth required pam_unix.so nullok use_first_passListing 8.41 Die /etc/pam.d/common-auth
- common-account
account sufficient pam_ldap.so account required pam_unix.so use_first_passListing 8.42 Die /etc/pam.d/common-account
- common-session
session sufficient pam_ldap.so session required pam_unix.so use_first_passListing 8.43 Die /etc/pam.d/common-session
- common-password
password sufficient pam_ldap.so password required pam_unix.so use_first_passListing 8.44 Die /etc/pam.d/common-password
Automatisches Homeverzeichnis
Das Problem bei neuen LDAP-Benutzern ist meist, dass sie auf den einzelnen Maschinen noch kein Homeverzeichnis haben. Jedoch hilft PAM auch in diesem Fall, da über eine entsprechende session-Direktive automatisch ein Homeverzeichnis angelegt wird, wenn sich ein wohnungsloser Benutzer einloggt:
session required pam_mkhomedir.so skel=/etc/skel umask=0022
Listing 8.45 Automatisch ein Homeverzeichnis anlegen
Mit diesen Änderungen ist unser einfaches LDAP-Setup schon komplett. Für weitere und ausführlichere Informationen sei an dieser Stelle auf das Internet (zum Beispiel unter www.openldap.org) und ganze Bücher verwiesen, die über LDAP geschrieben wurden.