Openldap Replikation geht nicht: Passwörter fehlen

Vorgeschichte
Um den Umstieg von 6.2 -> 7 vorzubereiten, ist unser Mailserver ausgezogen und wohnt jetzt als die hier beschriebene Dockerlösung im Internet. Das funktioniert gut. Der hausinterne LDAP ist mit einem autossh-tunnel an die Dockerlösung angebunden und funktioniert auch stabil.

Jetzt benötige ich einen replizierten OpenLDAP: Alle 24h kappt die Telekom die DSL-Leitung. Das ist doof: kommt in diesem Moment eine Mail, ist der Ldap nicht erreichbar und die Mail wird von Postfix als „User unknown“ abgewiesen. Auch bei der Umstellung von 6.2 -> 7 ist ein funktionierender Replikant sicher eine gutes Ruhekissen.

Was ich tat
Ich habe mich an die Anleitung aus dem Wiki gehalten (https://wiki.linuxmuster.net/community/anwenderwiki:erweiterungen:ldap-replikation). Als Replikationsbenutzer, der die Replikation durchführt, habe ich den rootdn (admin) genommen. Beide sind auf Provider und Consumer identisch in Name und PW.

Ergebnis
Der Replikant (Consumer) synchronisiert erfolgreich, jedoch nicht vollständig: Die UserPasswörter fehlen.

Diskussion

  • Nach Google ist dies häufig ein ACL-Problem: Der Replikationsbenutzer darf die Passwörter nicht vom Provider lesen oder nicht in den Consumer schreiben. Das ist hier nicht der Fall, da ja der rootdn genutzt wird. Mit dem passenden ldapsearch (ldapsearch -x -H „ldap://172.17.0.1:3890“ -D „cn=admin,dc=lokal,dc=carl-bosch-oberschule,dc=de“ -w „uid=fh“) sehe ich die UserPasswords im Ergebnis.
  • Es gibt/gab einen Bug: Syncst du einmal ohne passende ACL mit einem Replikationsbenutzer der UserPasswords nicht lesen darf, wird auch bei Löschen der Datenbank das PW nicht gesynct. Das habe ich ausgeschlossen, indem ich einen neuen Server (Ubuntu Bionic) aufgesetzt habe. Hier zeigt sich dasselbe Verhalten.
    -Die Holzhammer-Methode funktioniert:

    provider: $ slapcat -l data.ldif
    provider: $scp data.ldif root@consumer:
    consumer: $ slapadd data.ldif

Wer hat eine Idee woran dies Verhalten liegt? Bei wem klappt die Replikation von LML 6.2 -> auf ein Ubuntu 20.04?

Hallo Frithjof,

hast Du mal getestet, ob das Ändern der LDAP-Einträge auf dem Zielrechnern geht? Zum Beispiel so:

Datei modify.txt:

dn: uid=testuser,ou=accounts,dc=meine-schule,dc=de
changetype: modify
replace: description
description: Test

Dann folgenden Befehl ausführen:

ldapmodify -x -W -H "ldap://localhost" -D "cn=admin,dc=meine-schule,dc=de" -f modify.txt

Das Passwort ist das rootpw aus der /etc/ldap/slapd.conf.

Und wenn das funktioniert: Derselbe Test mit dem Passwort statt mit dem Feld description.

Beste Grüße

Jörg

Hi.
Habt ihr dieses Problem bei Euch gelöst?

VG,
Michael

Hallo Jörg,
Danke für deine Idee. Das hatte ich noch nicht getan, jetzt aber. Mit folgenden Ergebnissen:

  1. Test: Server ist ein clon via slapcat; scp; slapadd. Replikation ist in der slapd.conf auskommentiert. Ich kann sowohl Description als auch userPassword ändern.

  2. Test: Datenbank gelöscht, Replikation in der slapd.conf wieder aktiviert und synchronieren lassen:

ldap_modify: Server is unwilling to perform (53)
	additional info: shadow context; no update referral

Finde ich aber in Ordnung, da ja der Server sich jetzt im „Readonly“-Modus befindet: Ich benutze ja nur eine Provider-Consumer Replikation, keine Multi-Master-Replikation.

Hier ist übrigens meine slapd.conf auf dem replizierten Server:

root@mail:/etc/ldap# cat slapd.conf 
# Schema and objectClass definitions
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/misc.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema
include         /etc/ldap/schema/samba.schema
include         /etc/ldap/schema/sophomorix.schema

pidfile         /var/run/slapd/slapd.pid

argsfile        /var/run/slapd/slapd.args

loglevel stats

modulepath	/usr/lib/ldap
moduleload	back_hdb

# The maximum number of entries that is returned for a search operation
sizelimit       unlimited

# use passwords encrypted with ssha
password-hash {SSHA}

backend		hdb

database        hdb

#LDAP Suffix 
suffix          "dc=lokal,dc=carl-bosch-oberschule,dc=de"

#LDAP Admin
rootdn          "cn=admin,dc=lokal,dc=carl-bosch-oberschule,dc=de"
rootpw          xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Where the database file are physically stored for database #1
directory       "/var/lib/ldap"

dbconfig set_cachesize 0 2097152 0

dbconfig set_lk_max_objects 1500

dbconfig set_lk_max_locks 1500
# Number of lockers
dbconfig set_lk_max_lockers 1500

# Indexing options for database #1
index   entryUUID					eq
index	objectClass,uid,uidNumber,gidNumber,memberUid	eq
index	cn,mail,surname,givenname			eq,subinitial
index	sambaSID					eq
index	sambaPrimaryGroupSID				eq
index	sambaDomainName					eq

# Save the time that the entry gets modified, for database #1
lastmod         on

# Checkpoint the BerkeleyDB database periodically in case of system
# failure and to speed slapd shutdown.
checkpoint      512 30

syncrepl rid=1
    provider=ldap://172.17.0.1:3890
    type=refreshonly
    interval=00:00:01:00
    retry="15 +"
    searchbase="dc=lokal,dc=carl-bosch-oberschule,dc=de"
    filter="(objectClass=*)"
    attrs="*,+"
    schemachecking=off
    bindmethod=simple
    binddn="cn=admin,dc=lokal,dc=carl-bosch-oberschule,dc=de"
    credentials=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

#######################################################################
#Limits Access:
access to attrs=sambaLMPassword,sambaNTPassword,sambaPwdLastSet,sambaPwdMustChange,sambaAcctFlags,userPassword	
       by dn="uid=ldapuserfueremailserver,ou=accounts,dc=lokal,dc=carl-bosch-oberschule,dc=de" peername.ip=172.20.0.2 read
       by peername.regex=172\...* auth
       by anonymous peername.ip=172.20.0.2 auth
       by anonymous ssf=56 auth
       by self peername.ip=127.0.0.1 read
       by dn="cn=admin,dc=lokal,dc=carl-bosch-oberschule,dc=de" write
       by * none 


access to *
	by * read

Ich habe dein Problem so verstanden, dass die Aliase nicht aus dem LDAP gelesen werden. Nein, das habe ich auf die lange Bank geschoben. Geklappt hat nur ein /etc/aliases Ersatz, die ich aktuell per Hand pflege. Das geht für uns, weil wir nur die kollegiumsmail benutzen.

Sie dazu meine Gedanken hier: Linuxmuster-mail für LMN 6.2

Ja, wenn man es nur für das Kollegium macht, ist es evtl noch OK mit einer manuell geführten alias Datei-- aber gedacht ist es ja anders?!?

Ich hätte gerne „Dienst E-mail Adressen“ für alle und dazu noch so gut integriert, dass es bei moodle, Nextcloud bzw direkt im Client ootb funktioniert…

Die Synchronisation zwischen Provider und Consumer funktioniert immer noch nicht: Einige Attribute wie „userPassword“ werden nicht auf den Consumer synchronisiert.

Was ich weiter getan habe:

  • Um zu testen ob es Bug zwischen den LDAP-versionen ist: Ein Dockercontainer mit ubuntu 12.04 und slapd angelegt und die Replikation mit der oben genannten slapd.conf getestet. Ich bilde mir ein, es hätte einmal funktioniert, kann es aber nicht wiederholen. Die Passwörter werden weiterhin nicht synchronisiert. Es scheint also kein Bug zu zwischen altem slapd und neuem slapd zu sein.

  • Da mir aufgefallen ist, das alle Attribute, die in der Zeile „access to attrs=sambaLMPassword,sambaNTPassword,sambaPwdLastSet,sambaPwdMustChange,sambaAcctFlags,userPassword“ genannt werden, nicht synchronisiert werden, habe ich diese Zeile im Consumer auskommentiert. (Beim Provider nicht, denn ich kann die Daten ja - wie oben beschrieben - lesen.) Dies hat keinen Effekt, die Passwörter werden nicht synchronisiert.

  • Den Consumer mit den Debugleveln Filter, ACL und Sync laufen lassen. Das gab nichts erhellendes.

  • Der Überlegung nachgegangen, dass es nach einem ACL-Problem aussieht: Alles synchronisiert, nur die sicherheitsrelevanten Passwörter nicht. Auf dem Provider habe ich mittels slapcat -n 0 die Config ausgegeben: Ich sehe nichts, was den Zugriff des rootdn verhindern sollte:

olcAccess: {0}to attrs=sambaLMPassword,sambaNTPassword,sambaPwdLastSet,sambaPw
 dMustChange,sambaAcctFlags,userPassword  
by peername.regex="10...*" auth 
by  anonymous peername.ip="10.16.1.197" auth  
by anonymous peername.ip="10.16.1.2 54" auth  
by anonymous peername.ip="10.16.1.1" auth 
 by anonymous peername.ip ="10.16.1.6" auth  
by anonymous peername.ip="10.16.1.7" auth 
 by anonymous peername.ip="10.16.1.11" auth 
by anonymous peername.ip="10.16.1.12" auth 
 by anonymous peername.ip="10.16.1.13" auth
by anonymous peername.ip="127.0.0.1"  auth  
by anonymous peername.ip="10.16.1.250" auth 
by anonymous peername.ip=" 10.31.204.1" auth
by anonymous peername.ip="10.31.214.1" auth
by anonymous  peername.ip="10.16.1.16" auth
by anonymous peername.ip="134.xxx,xxx.xxx" auth
 by anonymous peername.ip="78.xxx.xxx.xxx" auth 
by anonymous ssf=56 auth 
by  self peername.ip="127.0.0.1" write
by self ssf=56 write
 by * none

olcAccess: {1}to attrs=sambaLMPassword,sambaNTPassword,sambaPwdLastSet,sambaPw
 dMustChange,sambaAcctFlags,userPassword  by dn.base="uid=ldapuserfueremailserver,ou=accounts,dc=lokal,dc=carl-bosch-oberschule,dc=de" peername.ip="127.0.0 .1" read
olcAccess: {2}to *  by * read

-Gedanke: Die Passwörter werden vielleicht synchronisiert, aber vom Consumer nicht ausgegeben. Die Passwörter müssen meines Verständnis nach von slapcat ausgeben werden, so sie vorhanden sind. Ich begreife slapcat als Datenbankdump ohne voreingestellte Filter oder ACLs . Da die Userpasswörter nicht ausgegeben werden, sind sie auf dem Consumer nicht vorhanden.

Ich habe gerade keine Idee, warum die Attribute userPasswort usw. nicht synchronisiert werden. Wer noch Gedanken hat: Ich bin auch für Strohhalme dankbar.

Hallo Frithjof,

auch in der Ausgabe von ldapsearch sind alle diese Felder nicht
vorhanden. Du musst vermutlich auf dem Server die ACLs anpassen.

Beste Grüße

Jörg

Edit: das war ich wohl etwas voreilig: Wenn man ohne Bind-User abfragt, dann
fehlen die Passsort-Hashes. Wenn man mit dem Bind-User abfragt, dann
sind die da.

Beste Grüße

Jörg

Hallo Frithjof,

inzwischen habe ich noch ein wenig weitergeforscht, und nun klappt bei mir die Synchronisation - auch die der Passwort-Hashes. Auch als Dienst läuft nun der slapd.

Meine zwei Hauptprobleme (beim Verständnis, nicht der Technik) waren:

  1. In der Ausgabe von ldapsearch sieht man die Passworthashes etc. nur, wenn man als Bind-User den admin verwendet. Ohne Bind-User, also anonym, sieht man alle anderen Felder.

  2. Die Synchronisation ist rein differenziellund kein Abgleich. Wenn sich auf dem Server seit der letzten Synchronisation nichts geändert hat, dann wird auch nichts synchronisiert. Es werden zum Beispiel auch Objekte, die beim Consumer fehlen, nicht angelegt - außer, sie werden auf dem Server modifiziert. Man muss also:

  • Beide Server stoppen
  • Die Datenbank auf dem Consumer löschen
  • Die Datenbank manuell übertragen
  • Die Server beide starten

Als ich das mal verstanden hatte, konnte ich nachvollziehen, dass tatsächlich alles klappt. Also beispielsweise auf dem Server ein Passwort ändern, und nach dem nächsten Sync war das neue Passwort auf dem Consumer gelandet - zu sehen wie gesagt nur, wenn man ldapsearch mit Bind-User admin verwendet.

Vielleicht hilft es ja! Bei Bedarf kann ich Dir auch meine Configs schicken.

Beste Grüße

Jörg

Der Consumer „bindet“ ja mit dem rootdn an den Provider. Das muss nach meinem Verständnis immer gehen, weil er alle Rechte auf dem Server hat. Das das aus SIcherheitsüberlegungen wenig weise ist, ist mir klar. Aber wenn das schon nicht geht…

Ich schaue mir das Ergebnis mit slapcat an. Das muss meines Erachtens immer die Passwörter anzeigen, da es ein Dump der Datenbank ist.

ja. so mache ich das bei jedem Test. Vergaß ich zu erwähnen.

Welche slapd Versionen setzt du ein?
Vielen Dank für deine Mühe.

Hallo Frithjof,

in der Tat habe ich an den ACLS letztlich nichts verändert.

Bei de LMN 6.2 ist sowieso das Hauptproblem, dass jeder quasi alles
lesen kann, sogar anonym. Man muss deshalb unbedingt in der Firewall den
Zugang auf diejenigen IPs beschränken, von denen aus man den LDAP nutzt.

Meine Konfiguration maile ich Dir gleih.

Beste Grüße

Jörg

Hallo Frithjof,

und noch eine Erkenntnis: Wenn man die Datenbank komplett löscht, dann wird auch ein kompletter Pull angestoßen – slapcat und slapadd sind also nicht erforderlich.

Ich habe noch die Anleitung überarbeitet: https://wiki.linuxmuster.net/community/anwenderwiki:erweiterungen:ldap-replikation

Da steht dann auch die getestete slapd-Version (2.4.48).

Vor allem bei den Schritten am Ende von 5. kommt es genau auf die Reihenfolge an! Da habe ich mich beim Testen oft ausgetrickst.

Beste Grüße

Jörg

Trotz vieler Mühen von Jörg bin ich nicht weiter gekommen. Ich habe (und hatte auch zuvor) alle Tipps von Jörg beachtet.

Jörg hat mir netterweise sein Config-Dateien geschickt. Ich habe keine relevanten Unterschiede entdecken können.

Einen Gedankengang hatte ich noch: Könnten die Passwörter gesynct aber nicht angezeigt werden?
Ich habe mir auf dem Provider ein Passwort ausgeben lassen und nach diesem in der Datenbank gegrept:

grep -r XXXXXXXXXXXXXXXXXXXXXXXXXXXX /var/lib/ldap
Übereinstimmungen in Binärdatei ./__db.003.
Übereinstimmungen in Binärdatei ./__db.004.
Übereinstimmungen in Binärdatei ./id2entry.bdb.
Übereinstimmungen in Binärdatei ./log.0000000001.
Übereinstimmungen in Binärdatei ./log.0000000002.

Das Passwort liegt also auf dem Provider vor.
Dasselbe habe ich auf dem Consumer wiederholt:

grep -r XXXXXXXXXXXXXXXXXXXXXXXXXXXXX ./*
root@mail:/srv/docker/precise-ldap/var/lib/ldap# 

Hier gibt es also keine Übereinstimmung. Es ist also anzunehmen, dass die Passwörter auf dem Consumer tatsächlich nicht vorhanden sind.

Eine weitere Idee: Die Schema-Dateien sind unterschiedlich. Die md5-Prüfsummen sind auf Consumer und Provider identisch.

Mir gehen hier echt die Ideen aus.

Gedanke: Das rootdn-Passwort auf dem Consumer stimmt nicht mit dem auf dem Provider überein und der Provider erlaubt lesenden Zugriff auf bestimmte Attribute im Sinne eines anonymen Binds und nur diese landen in der Datenbank

  • Passwort überprüft, ist identisch.
  • Passwort verändert, der Consumer synchronisiert gar nicht mehr:
slap_client_connect: URI=ldap://172.17.0.1:3890 DN="cn=admin,dc=lokal,dc=carl-bosch-oberschule,dc=de" ldap_sasl_bind_s failed (53)

Hallo Frithjof,

versuch doch nochmal folgendes:

  1. Beide Server stoppen
  2. Auf dem Consumer:
apt purge slapd
rm -rf /var/lib/ldap
rm -rf /var/lib/slapd
rm -rf /etc/ldap/slapd.d
rm -rf /etc/ldap/schema
apt install slapd
systemctl stop slapd
  1. Jetzt holst Du Dir die beiden Schema-Dateien und die slapd.conf
  2. Bei beiden Servern den Abschnitt mit den ACLs genau so übernehmen wie in meinen Configs – Du hast da ganz viele zusätzliche Einträge
  3. Den Provider wieder starten
  4. Auf dem Consumer den Abschnitt zu syncrepl genau so übernehmen wie in meiner Config (natürlich mit den angepasten Werten). Achte auch auf das attrs="*,+" - das war in der Anleitung mal anders.
  5. Auf dem Consumer als root folgende Befehle absetzen:
systemctl stop slapd
killall slapd
rm -r /etc/ldap/slapd.d/*
slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d     (Fehlermeldung ggf. ignorieren)
chown -R openldap:openldap /etc/ldap
chown -R openldap:openldap /var/lib/ldap
rm -rf /var/lib/ldap/*
systemctl start slapd

Dann wartest Du die Synchronisation ab und testest nochmal (ldapsearch mit Bind-User admin).

Mehr fällt mir dann auch nicht mehr ein.

Beste Grüße

Jörg

Hallo Jörg,
danke für deine Zeit.

Ich habe mir ein slapd-Dockercontainer gebaut. Das Image startet ja immer frisch nach der Installation. Die Schema-Dateien ziehe ich aus dem deb-Paket bzw. mounte sie (sophomorix und samba) als volume hinein.

Ja, habe ich. Ich nehme sie testhalber raus, Kann ich jedoch erst in einer Nacht machen, wenn keiner die Systeme nutzt. Da wird das etwas dauern.

Hier übrigens mein Dockerfile. Vielleicht nutzt das noch jemanden. In diesem Fall sollte man die Zeile FROM auf ein aktuelles Ubuntu ändern.

FROM ubuntu:12.04
COPY tools/cleanup-openldap.sh  /usr/local/bin
COPY tools/clear-ldap-database.sh /usr/local/bin
COPY tools/reread-slapdconfig.sh /usr/local/bin
COPY tools/startup.sh /usr/local/bin
RUN apt-get update
RUN apt-get install -y slapd ldap-utils less
RUN mkdir -p /etc/ldap/slapd.d
RUN chown -R openldap:openldap /etc/ldap
CMD ["/usr/local/bin/startup.sh",""]

Die startup.sh:

#!/bin/bash
rm -rf /etc/ldap/slapd.d/* 
slaptest -f /etc/ldap/slapd.conf   -F /etc/ldap/slapd.d
chown -R openldap:openldap /etc/ldap/*
chown -R openldap:openldap /var/lib/ldap
chown -R openldap:openldap /etc/ldap
/usr/sbin/slapd -d  0

und hier die docker-compose.yml

version: '3'
services:
  ldap:
    build: .
    hostname: ldap
    domainname: XXXXXXXXXXXXXXXXXX.de
    container_name: ldap
    volumes:
        - ./config/ldap/slapd.conf:/etc/ldap/slapd.conf
        - ./config/ldap/schema/sophomorix.schema:/etc/ldap/schema/sophomorix.schema
        - ./config/ldap/schema/samba.schema:/etc/ldap/schema/samba.schema
        - ./var/lib/ldap:/var/lib/ldap

Hallo Frithjof,

dann versuche doch mal testweise als startup.sh:

#!/bin/bash
service slapd stop
killall slapd
rm -rf /etc/ldap/slapd.d/* 
slaptest -f /etc/ldap/slapd.conf   -F /etc/ldap/slapd.d
chown -R openldap:openldap /var/lib/ldap
chown -R openldap:openldap /etc/ldap
rm -r /var/lib/ldap/*
service slapd start

Ich nehme an, die drei anderen Skripte spielen erst mal nicht mit?
Und dann würde ich sicherheitshalber noch eine neuere Ubuntu-Version testen – ich hatte 19.10 zur Hand.

Beste Grüße

Jörg