OpenLDAP speichert
Benutzerdaten in einer hierarchischen Datenbank, dem sogenannten
Directory Information Tree
(DIT).
Pfade heißen Distinguished Name
(DN)
und werden vom Blatt zur Wurzel notiert, zum Beispiel
uid=phrank,ou=users,dc=illusioni,dc=de
.
Jedem Eintrag sind eine oder mehrere Objektklassen zugeordnet,
die festlegen, welche Name-Wert-Paare er enthalten kann oder muss.
Das Schema definiert die verfügbaren Objektklassen.
Es werden sowohl Pakete für den Daemon und die zugehörigen Werkzeuge installiert als auch für die Authentifizierung gegen Kerberos und die NSS-Integration.
apt install slapd ldap-utils libsasl2-modules-gssapi-mit libnss-ldap nslcd
Der empfohlene Unterbau ist die
LMDB,
eine moderne Name-Wert-Datenbank. Die Rohdaten liegen unter
/var/lib/ldap/data.mdb
.
Um in den folgenden Abschnitten Tipparbeit zu sparen,
merken wir uns die Eckdaten in Umgebungsvariablen.
domain=illusioni.de realm=ILLUSIONI.DE base="dc=illusioni,dc=de" bind="-D cn=admin,$base -w Password" backend="olcDatabase={1}mdb,cn=config"
Damit Clients den
LDAP-Server
finden, hinterlegen wir die Daten in einer Konfigurationsdatei.
Da alle Dienste auf dem selben Rechner laufen, kommunizieren sie per
ldapi
über den lokalen Sockel
/var/run/slapd/ldapi
.
/etc/ldap/ldap.confBASE dc=illusioni,dc=de URI ldapi:/// SASL_MECH GSSAPI
ANONYMOUS | Ohne Authentifizierung |
EXTERNAL | Systembenutzer |
PLAIN | Passwort im Klartext |
GSSAPI | Kerberos |
CRAM-MD5 | Aufforderung-Antwort-Verfahren |
DIGEST-MD5 | …mit Integritätssicherung |
SCRAM | …in Modern |
OTP | Einmalkennwort |
Da der Daemon Benutzer auch via Kerberos authentifizieren soll, braucht er eine Schlüsseldatei. Diese kann allerdings erst später erzeugt werden, sobald Kerberos fertig eingerichtet ist.
echo "export KRB5_KTNAME=/etc/krb5/slapd.keytab" >> /etc/default/slapd
Der Verzeichnisdienst hat einen eigenen Administrator
mit uneingeschränkten Rechten, der meistens admin
heißt.
Dieses Konto sollte man ausschließlich für die Verwaltung verwenden,
aber niemals als Zugang für Daemonen.
ldapmodify -Y EXTERNAL << . dn: $backend replace: olcRootDn olcRootDn: cn=admin,$base - replace: olcRootPW olcRootPW: $(slappasswd -h {SSHA} -s Password) .
Die Zugriffskontrollliste wird von oben nach ausgewertet. Standardmäßig dürfen authentifizierte Benutzer alles lesen (außer Passwörter) und ihr eigenes Passwort ändern.
ldapsearch -Y EXTERNAL -b "$backend" olcAccess dn: $backend olcAccess: {0}to attrs=userPassword by self write by anonymous auth by * none olcAccess: {1}to attrs=shadowLastChange by self write by * read olcAccess: {2}to * by * read
Wir geben nun dem Replikationsdienst vollen Schreibzugriff. Der KDC-Server bekommt Lesezugriff und der Admin-Server Schreibzugriff auf den Kerberos-Teilbaum. Angemeldete Benutzer dürfen ihr Passwort, ihre Shell und ihren Namen selbst ändern.
ldapmodify -Y EXTERNAL << . dn: $backend changetype: modify replace: olcAccess olcAccess: {0}to * by dn="cn=repl,ou=daemons,$base" write by * break olcAccess: {1}to dn.subtree="cn=kerberos,$base" by dn="cn=adm,ou=daemons,$base" write by dn="cn=kdc,ou=daemons,$base" read by * none olcAccess: {2}to attrs=userPassword by self write by anonymous auth by * none olcAccess: {3}to attrs=shadowLastChange,loginShell,gecos by self write by * read olcAccess: {4}to * by * read .
Die GSSAPI bildet aus den Anmeldaten etwas eigenwillige DNs in der Form
uid=User,cn=www.illusioni.de,cn=gssapi,cn=auth
die man mit Hilfe eines regulären Ausdrucks an die eigene Systematik anpassen kann.
ldapadd -Y EXTERNAL << . dn: cn=config olcAuthzRegexp: uid=([^,]+),cn=[a-z.]*$domain,cn=gssapi,cn=auth uid=\$1,ou=users,$base olcSaslRealm: $realm .
Ein kleiner Test zeigt, ob die Umwandlung klappt.
slapauth -v -M GSSAPI -R $realm User ID: <phrank> check succeeded authcID: <uid=phrank,ou=users,dc=illusioni,dc=de>
Damit Passwörter und Daten nicht im Klartext das Netzwerk
passieren, verschlüsseln wir die Verbindung mit
TLS.
Dazu erzeugen wir einen Satz Diffie-Hellmann-Parameter für den
Schlüsselaustausch und unsere Zertifizierungsstelle stellt ein
Serverzertifikat aus.
Das kopieren wir nach /etc/ssl
und schränken den
Lesezugriff auf Mitglieder der Gruppe ssl-cert
ein.
openssl dhparam -out /etc/ssl/dh1024.pem 1024 chmod g+r /etc/ssl/$HOSTNAME.{key,crt} chgrp ssl-cert /etc/ssl/$HOSTNAME.{key,crt} adduser openldap ssl-cert
Als nächstes teilen wir dem Server die Pfade zu Schlüsseln und Zertifikaten mit.
ldapmodify -Y EXTERNAL << . dn: cn=config changetype: modify add: olcTLSDHParamFile olcTLSDHParamFile: /etc/ssl/dh1024.pem - add: olcTLSCACertificateFile olcTLSCACertificateFile: /etc/ssl/ca.crt - add: olcTLSCertificateFile olcTLSCertificateFile: /etc/ssl/$HOSTNAME.crt - add: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/ssl/$HOSTNAME.key .
Verschlüsselung erzwingen.
ldapmodify -Y EXTERNAL << . dn: olcDatabase={1}mdb,cn=config changeType: modify add: olcSecurity olcSecurity: tls=1
Standardmäßig sind nur die Objektklassen indiziert.
ldapsearch -Y EXTERNAL -b "$backend" olcDbIndex olcDbIndex: objectClass eq
Um spätere Anfragen zu beschleunigen und lästige Meldungen im Systemprotokoll zu vermeiden, erzeugen wir Suchbäume für viele weitere Attribute.
ldapmodify -Y EXTERNAL << . dn: $backend changetype: modify replace: olcDbIndex olcDbIndex: objectClass eq olcDbIndex: entryCSN eq olcDbIndex: cn pres,sub,eq olcDbIndex: uid pres,sub,eq olcDbIndex: sn pres,sub,eq olcDbIndex: displayName pres,sub,eq olcDbIndex: default sub olcDbIndex: uidNumber eq olcDbIndex: gidNumber eq olcDbIndex: dc eq olcDbIndex: member eq olcDbIndex: mail,givenName eq,subinitial olcDbIndex: rfc822MailMember,memberUid eq olcDbIndex: krbPrincipalName eq,pres,sub olcDbIndex: krbPwdPolicyReference eq .
LDAP erlaubt ausgefeilte Architekturen zur Lastverteilung und Ausfallsicherheit. Dieser Abschnitt beschreibt nur die Spiegelung des Datenbestandes zwischen zwei gleichberechtigten Servern, den sogenannten Mirror Mode. Alle beteiligten Knoten werden gleich konfiguriert, außer einer eindeutige Identifikation und der jeweiligen Adresse des Partner-Knotens.
id=1;host=durmstrang;peer=ilvermorny;replpw=Password \
ldapmodify -Y EXTERNAL << .
# Replikations-Modul laden
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: syncprov
# Replikations-Anbieter konfigurieren
dn: olcOverlay=syncprov,$backend
changeType: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
olcSpCheckpoint: 100 10
olcSpSessionLog: 100
# Server-ID eindeutig festlegen
dn: cn=config
changeType: modify
add: olcServerID
olcServerID: $id
# Replikation aktivieren
dn: $backend
changeType: modify
add: olcSyncrepl
olcSyncrepl: rid=001
provider=ldap://$peer
bindmethod=simple
binddn=cn=repl,ou=daemons,$base
credentials=$replpw
searchbase=$base
schemachecking=on
type=refreshAndPersist
retry="60 +"
starttls=yes
tls_cacert=/etc/ssl/ca.crt
tls_cert=/etc/ssl/$HOSTNAME.crt
tls_key=/etc/ssl/$HOSTNAME.key
-
add: olcMirrorMode
olcMirrorMode: TRUE
.
Alle Schritte bis hierher muss man auf allen an der Replikation beteiligten Rechnern durchführen. Die Konfiguration selbst wird nicht repliziert, nur die Daten, die wir in den folgenden Abschnitten füllen.
Zuerst ergänzen wir das Schema um Objektklassen für Domänen-Namen und Elektropost-Adressen.
ldapadd -Y EXTERNAL -f /etc/ldap/schema/misc.ldif
Dann legen wir Organisationseinheiten für virtuelle Domänen, Elektropost-Verteiler, Daemonen, Gruppen und Benutzer an.
for orga in domains aliases groups users daemons; do ldapadd $bind << . dn: ou=$orga,$base objectClass: organizationalUnit ou: daemons . done
Es ist heute üblich, auf einem Host die Webseiten und Postfächer für mehrere Domänen zu betreiben.
vdomain=Domain ldapadd $bind << . dn: dc=$vdomain,ou=domains,dc=illusioni,dc=de objectClass: dNSDomain dc: $vdomain . done
Weiterleitungen werden statt in /etc/aliases
im Verzeichnis gespeichert.
for name in hostmaster postmaster webmaster; do ldapadd $bind << . dn: cn=$name,ou=aliases,$base objectClass: nisMailAlias cn: $name cn: $name@$domain rfc822MailMember: root@$domain . done
Als nächstes erzeugen wir die Konten für den Replikationsdienst, den NSS, das KDC, den Kerberos Admin-Server, Dovecot, Postfix und weitere Dienste, die Daten aus dem Verzeichnis lesen müssen.
for daemon in repl nss kdc adm dovecot postfix apache; do ldapadd $bind << . dn: cn=$daemon,ou=daemons,$base objectClass: simpleSecurityObject objectClass: organizationalRole cn: $daemon description: Syncrepl user for mirrormode operation userPassword: $(slappasswd -h {SSHA} -s Password) . done
Schließlich legen wir Gruppen und Benutzer an.
uid=Uid;user=User;first=FirstName;last=LastName ldapadd $bind << . dn: cn=$user,ou=groups,$base objectClass: posixGroup cn: $user gidNumber: $uid dn: uid=$user,ou=users,$base objectClass: person objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: posixAccount objectClass: shadowAccount uid: $user cn: $first $last sn: $last givenName: $first mail: $user@$domain uidNumber: $uid gidNumber: $uid homeDirectory: /home/$user loginShell: /bin/bash .
Jeder Benutzer kann sein Passwort selbst ändern:
ldappasswd $bind "uid=User,ou=users,$base" -S
Und um einen Benutzer zu löschen:
ldapdelete $bind uid=User,ou=users,$base
Eine Liste aller Benutzer erhält man mit folgender Suche:
ldapsearch $bind "uid=*" cn
Zum Abschluss wird der NSS so konfiguriert, dass er Benutzer und Gruppen zuerst in der Passwortdatei und dann per Verzeichnisdienst sucht.
/etc/nsswitch.confpasswd: files ldap group: files ldap shadow: files ldap
Der NSLCD greift mit einem eigenen Konto lesend auf Benutzer und Gruppen hat. Er reduziert die Last, indem er Antworten zwischenspeichert.
/etc/nslcd.confuid nslcd gid nslcd uri ldapi:/// base dc=illusioni,dc=de ldap_version 3 binddn cn=nss,ou=daemons,dc=illusioni,dc=de bindpw Password ssl start_tls tls_cacertfile /etc/ssl/ca.crt
Nun findet das System auch Benutzer, die nicht in
/etc/passwd
angelegt sind.
getent passwd phrank phrank:x:1001:1001:Frank Hoffmann:/home/phrank:/bin/bash
Identität
ldapwhoami SASL/GSSAPI authentication started SASL username: phrank@ILLUSIONI.DE SASL SSF: 56 SASL data security layer installed. dn:uid=phrank,ou=users,dc=illusioni,dc=de