netzwerke:ldap

LDAP (Schwerpunkt OpenLDAP)

Lightweight Directory Access Protocol (LDAP) ist ein Anwendungsprotokoll aus der Computertechnik. Es erlaubt die Abfrage und die Modifikation von Informationen eines Verzeichnisdienstes (eine im Netzwerk verteilte hierarchische Datenbank: absoluter Pfad kennzeichnet Datensatz) über das TCP/IP Netzwerk. Die aktuelle Version ist in RFC 4511 spezifiziert.

Das LDAP-Protokoll wird in vielen bekannten Verzeichnisdiensten (und Servern) benutzt:

  • Slapd (University of Michigan, Openldap)
  • Netscape Directory Server
  • Microsoft Active Directory (AD)
  • Microsoft Exchange
  • Novell Directory Services (NDS)
  • Lotus Domino
  • Sun Directory Services (SDS)
  • Lucent’s Internet Directory Server (IDS).

LDAP ist für relativ einfache Lesezugriffe optimiert. Man kann zwar mit boolschen Ausdrücken arbeiten, es findet aber keine Sortierung durch den LDAP-Server statt. D.h. die Datensätze kommen in beliebiger Reihenfolge, da die LDAP-Entwickler der Meinung sind, so etwas gehört auf dem Client implementiert (auch um die Serverlast zu minimieren).

Der LDAP-Server hat ein sog. Schema (=genormte und ggf. erweiterte Struktur), das das Format der Datensätze (Entrys) mit ihren Attributen definiert. LDAP-Entry Lizenz:public Domain

Das Schema legt die Regeln für gespeicherten Daten fest (benötigte und erlaubte Attribute) und hilt so die Daten konsistent zu halten. Dabei sollte man sich aus Kompatibilitätsgründen möglichst an vordefinierte Schemata halten bzw. bei sog. Schemaerweiterungen möglichst ein vorhandenes erweitern. Vordefinierte Objektklassen stehen in der Datei /etc/openldap/schema/core.schema .

Ein Datensatz (Entry) hat eine oder mehrere Objektklassen (Objectclass) die zum gruppieren der Informationen benutzt werden und benötigte und erlaubte Attribute festlegt. Der Datensatz ist ein Knoten im Baum (DIT: directory information unit). DIT Lizenz:public Domain

Zusätzlich können Aliase (Eintrag mit Objektklasse Alias, Attribut namens „aliasedObjectName“ die auf den DN verweist) angelegt werden.

LDAP ist flexibler als das angegraute NIS: Dieses ist formatgebunden, wenig Möglichkeiten bei den Zugriffsrechten (ACLs) und kann keine Verschlüsselung. Zudem wird autofs als NIS-Ersatz benutzt.

:!: LDAP-User-IDs (UIDs) mit gutem Abstand zu den System UIDs anlegen (falls man später noch lokale Benutzer anlegen will).

Authentifizierung kann auch von Kerberos vorgenommen werden.

LDAP kann sehr gut bei klassischen Einsatzzwecken eines Verzeichnisdienstes eingesetzt werden: Bei verteilten Daten wie Adressbücher für Anwendungen und MUAs (Thunderbird, ..), fingerd, … .

Die Integration in Programme erfolgt entweder über die Shell-Befehle (Änderungsanweisungen im LDIF-Format), Bibliotheken und native Funktionen.

Das LDIF-Format

  1. repräsentiert LDAP-Einträge in (menschenlesbarer) Textform
  2. erlaubt eine einfache Datenänderung
  3. ist nützlich für Massenänderungen: DB in LDIF, Skript drüber jagen, importieren
  4. kann Vorlagen benutzen
  5. dient zum Backup und zum Datentransfer zu anderen Systemen
dn: uid=user1,ou=People,
         dc=mycompany,dc=com
uid: user1
cn: User One
objectclass: account
objectclass: posixAccount
objectclass: top
loginshell: /bin/bash
uidnumber: 500
gidnumber: 120
homedirectory: /mnt/home/bmarshal
gecos: Brad Marshall,,,,
userpassword: {crypt}KDnOoUYN7Neac

Anmerkung zu „userpassword“ hier wird der verwendete Hash (crypt) in geschweiften Klammern angegeben. Es sind serverseitig mehrere Hash-Algorithmen möglich, die dann auch vom Server verwaltet werden und eine spätere Migration zu einem anderen Hash-Algorithmus problemlos möglich machen (ohne dass alle sofort ihre Passwörter ändern müssen).

  • ldbmcat & slapcat: ldbm Datenbank zu LDIF
  • ldif2ldbm & slapadd: LDIF zu ldbm Datenbabk

Beispiel: uid=bmarshal,ou=People,dc=mycompany,dc=com

DN distinguished name Eindeutiger Name bzw. der Pfad zu einem Objekt: uid=user1,ou=People,dc=mycompany,dc=com
RDN Relative Distinuished Name der relative Name in Verhätlnis zu einem Objekt: uid=user1
Base DN Der „Basiseinsprungspunkt“: ou=People,dc=mycompany,dc=com . Am besten den schon vorhandenen DNS-Namen benutzen.
DIT Directory Information Tree
LDIF LDAP Data Interchange Format: Format zum Datenaustausch, kann auch für den Austausch der Konfiguration benutzt werden
  • Containerobjekte sind objekte die weitere enthalten, z.B. CN, OU, O und DC.
  • Blattobjekte FIXME

Der Datensatz setzt sich aus Attributen zusammen, die wiederum Werte eines bestimmten (Daten-) Typs enthalten. Attribute haben

  1. einen Namen
  2. eine OID (siehe Tabelle)
  3. eine Syntax (Datentyp und wie die Wert verglichen können)
  4. eine Anweisung ein oder mehrere Werte zu enthalten
Attributname Bedeutung
C Country (= Land)
CN Common Name der Name des Objektes unter dem das Objekt gewöhnlich angesprochen wird
DC Domain Component
DESC Description, menschenlesbare Beschreibung
L Location, Bezeichnung eines geografischen Ortes
OID Objectidentifier, String der aus einer (von Punkten unterbrochenen) Folge von Dezimalzahlen, z.B. hat Microsoft die OID 1.2.840.113556.* und man kann sich die durch RFC 1065 reservierten OIDs 1.3.6.1 nehmen. Als Firma beispielweise die 1.3.6.1.4.1.* . Eine eigene OID benötigt man, wenn sich eigene Atrributtypen definieren möchte und man sich weltweit vernetzt (IPv6?). OIDs werden kostenlos durch die IANA vergeben.
SN Surname (=Nachnahme)
O Organisation (=Name der Organisation/Firma)
OU Organisational Unit (=Organisationseinheit, z.B. Abteilung)
ST State (=Bundesstaat)
UID user id (=Benutzername)

Siehe RFC2256 - A Summary of the X.500(96) User Schema for use with LDAPv3

FIXME

OpenLDAP läuft auf den meisten UNIX-basierten Systemen: FreeBSD, Linux, NetBSD, OpenBSD und Windows (http://lucas.bergmans.us/hacks/openldap/|Homepage des Ports). . Siehe OpenLDAP Homepage.

OpenLDAP arbeitet mit den Modulen

  • nss_ldap (für weniger sensible Daten)
  • pam_ldap (authentication und Passwortänderungen)

nss_ldap eignet sich nur für wenig sensible Daten: user-id, shell, …

Es wird in der Datei /etc/nsswitch.conf konfiguriert.

passwd: files ldap
shadow: files ldap
hosts: files dns

Eine Delegation von Unterbereichen ist möglich (man kann Teile mounten). Der Datenaustausch wird in den Formaten

  • LDIF (Einträge der Form „Attribut: Wert“ in einer Textdatei)
  • ?

Für sensible Daten wie Passwörter eignet sich eher pam_ldap.

Die Abfragen beschränken sich meist auf:

  1. ldap_simple (zum Passwortüberprüfen; ohne SASL-Schicht): Klartext (aber über TLS), der Hash wird vom Server berechnet (transparent für den Client)
  2. SASL external (beide Zertifikate: Server und Client) ohne SASL

RFC 2255 - LDAP URL Format (ersetzt RFC1959): Format für LDAP-Urls und mit Lesezugriff.

FIXME

Aufbau LDAP-URL, vereinfacht:

  1. Protokoll ldap / ldaps (verschlüsselt)
  2. Servername und Portnummer
  3. BASE-DN (Einsprungspunkt)
  4. auszulesende Attr.
  5. Suchbereich (scope)
  6. Boolscher Filterausdruck
  7. Erweiterungen

Also z.B.: ldaps://ldap.mycompany.com/dc=bar,dc=com?cn?sub?uid=user1

Komplett aus RFC 2255:

       ldapurl    = scheme "://" [hostport] ["/"
                    [dn ["?" [attributes] ["?" [scope]
                    ["?" [filter] ["?" extensions]]]]]]
       scheme     = "ldap"
       attributes = attrdesc *("," attrdesc)
       scope      = "base" / "one" / "sub"
       dn         = distinguishedName from Section 3 of [1]
       hostport   = hostport from Section 5 of RFC 1738 [5]
       attrdesc   = AttributeDescription from Section 4.1.5 of [2]
       filter     = filter from Section 4 of [4]
       extensions = extension *("," extension)
       extension  = ["!"] extype ["=" exvalue]
       extype     = token / xtoken
       exvalue    = LDAPString from section 4.1.2 of [2]
       token      = oid from section 4.1 of [3]
       xtoken     = ("X-" / "x-") token
Suchfilter
Operatoren Wirkung
& and (=und)
| or (=oder)
!
̃= approx equal (=vorraussichtl. gleich)
>= greater than or equal (=größer gleich)
less than or equal (=kleiner gleich)
* any (=alle)
Suchbereich
base beschränkt auf den Basisbereich
onelevel beschränkt auf den direkten Nachfolgelevel
sub durchsucht den kompletten Unterbaum

Zugriffsrechte lassen sich fein granular zuweisen.

access
to dn.sub="ou=, .."
by self write
by * auth 

by * auth: nur fragen FIXME

:!: Die erste zutreffende Regel gilt!

  • Datenbank-Backend (meist Berkeley DB = BDB, andere möglich: SQL etc., wenn man keinen guten Grund hat: beibehalten; An Indices und Caches denken!)
  • Anwendung
  • SASL
  • TLS
  • TCP/IP

Durch ein Replication-Logfile (Übertragung mit slurpd) ist auch ein Backupserver (Slave) möglich, das delegieren einzelner Teile bleibt ebenfalls möglich.

Damit wird die

  1. Verlässlichkeit
  2. Verfügbarkeit (durch mehrere Server, master:lesen+schreiben und slaves=Backupserver:nur-lesen; Eleminierung des „single point of failure“)
  3. Geschwindigkeit: Sowohl durch örtliche Nähe (langsame Verbindungen) als auch durch Lastverteilung (Suchanfragen)

erhöht.

Temporäre Inkonsistenzen sind ok, geschrieben wird eh nicht allzu oft.

Replikationsablauf: Verweise (Referrals)

  1. Client sendet Änderungen an den slave-Server
  2. slave-Server gibt den Verweis an den master zurück
  3. Client sendet Änderungen diesmal an den master-Server
  4. master-Server gibt das Änderungsergebnis an den Client zurück
  5. master-Server gibt die Änderungen an den slave-Server weiter

Replikationsablauf: Verketten (Chaining)

  1. Client sendet Änderungen an den slave-Server
  2. slave-Server leitet den Änderungswunsch an den master weiter
  3. master-Server gibt das Änderungsergebnis an den slave-Server zurück
  4. slave-Server schickt Ergebnis an den Client weiter
  5. master-Server gibt die Änderungen an den slave-Server weiter

Die mitgelieferten man-pages (Hileseiten)

  • man slapd.conf
  • man slapd.access
  • man slapd
  • nur ein master catalog server zu einer Zeit pro domain (noch aktuell? FIXME)
  • Da OpenLDAP (vor allem beim Server) sehr aktiv entwickelt wird, ist die Doku (vor allem die man-pages) oft hinterher (z.B. werden veraltete Funktionen beschrieben) wenn man aus dem Quellcode kompiliert. Deshalb sollte man nicht allzu oft upgraden. Wenn man eine vorkompilierte Version einer Distribution (z.B. aus Debian) benutzt, wird das Problem (hoffentlich) geringer ausfallen, da auf einer stabilen Version verblieben wird und der Paketbetreuer (maintainer) sich mehr drum kümmern sollte.
  • kryptische Fehlermeldungen
  • ACL erst „nach und nach“ machen (und testen!)
  • NICHT für viele Schreibzugriffe geeignet!
  • komplexe Abfrage und Strukturänderungen sind ein großes Problem
  • keine Transaktionen (add / modify sind aber atomar) / kein Locking
  • Backups machen und/oder Daten replizieren
  • man kann komplette Server migrieren/replizieren durch „dump“ der Konfiguration und Daten
  • Server mit persönlichen Daten vor Zugriff schützen (Slave-Server öffentlich (ro), Master-Server intern)
  • DB-Strukturen sorgfältig planen, Attribute (z.B. „memberOf:“), möglichst vordefinierte (Kompatibilität)
  • Keep it simple!
  • keine Schreibzugriff durch Applikationen

Firewalling:

  • 53 (udp/tcp) dns → AD
  • 88 (udp+udp) kerberos
  • 389 (tcp+udp) LDAP
  • 445 tcp AD GPOs
  • 464 (udp+udp) kpasswd
  • 636 (tcp) LDAP TLS
  • 3268 (tcp) Ad global catalog
  • 3269 (tcp)

SASL Bind (RFC 2829) FIXME

  • Overlays: zwischen dem Datenbank-backend und Anwendungsschicht kann man eigene Overlays einfügen die dann Anfragen modifizieren, abkürzen usw.

Beispiel: eigene eMail-Adresse mit Verfallsdatum und Signatur modifizieren:

bbmail: http://www.best-before.qipc.org