Das Problem
Montag morgen. Nextcloud zeigt 502 Bad Gateway. Die Ursache ist schnell gefunden: Der CIFS-Mount auf srv-r2d2 hängt. Kein Wunder – der Fileserver versucht noch, sich bei dc-vader zu authentifizieren. Der wurde aber am Wochenende demoted.
root@srv-r2d2:~# mount | grep cifs
//srv-r2d2.darkside.local/daten on /mnt/daten type cifs (sec=krb5)
root@srv-r2d2:~# ls /mnt/daten
ls: cannot access '/mnt/daten': Host is down
Der Nextcloud-Container auf srv-chewbacca (192.168.66.48) bindet diesen Mount via NFS ein. Kein Mount, kein Dateizugriff, 502.
Erste Reaktion: “Klar, der Memberserver muss nur den neuen DC kennen.” Klingt simpel. Ist es nicht.
Die Diagnose
UCR zeigt auf den Toten
root@srv-r2d2:~# ucr get ldap/server/name
dc-vader.darkside.local
root@srv-r2d2:~# ucr get kerberos/kdc
dc-vader.darkside.local
root@srv-r2d2:~# ucr get nameserver1
192.168.66.1
Alle UCR-Variablen zeigen noch auf dc-vader. Der ist aber nicht mehr da.
AD-Join OK, SMB trotzdem kaputt
root@srv-r2d2:~# net ads testjoin
Join is OK
root@srv-r2d2:~# net ads info
LDAP server: 192.168.66.2
LDAP server name: dc-yoda.darkside.local
Realm: DARKSIDE.LOCAL
Kerberos und AD sehen dc-yoda korrekt – DNS liefert den neuen DC. Aber:
root@srv-r2d2:~# smbclient -k //srv-r2d2.darkside.local/daten -c ls
session setup failed: NT_STATUS_ACCESS_DENIED
LDAP-Machine-Bind schlaegt fehl
root@srv-r2d2:~# ldapsearch -x -H ldaps://dc-yoda.darkside.local:7636 \
-D "$(ucr get ldap/hostdn)" -y /etc/machine.secret \
-b "dc=darkside,dc=local" "(cn=srv-r2d2)"
ldap_bind: Invalid credentials (49)
Additional info: 80090308: LdapErr: DSID-0C09044E, comment: AcceptSecurityContext error, data 52e
Error 52e = falsches Passwort. Aber /etc/machine.secret wurde nicht geaendert. Das Problem: Der Memberserver hat ein Machine-Passwort im UCS-LDAP, und nach dem Demote des alten DCs stimmt das nicht mehr mit dem ueberein, was dc-yoda kennt.
Der erste Versuch: net ads join
Die offensichtliche Loesung:
root@srv-r2d2:~# net ads join -U luke.skywalker
Enter luke.skywalker's password:
Using short domain name -- DARKSIDE
Joined 'SRV-R2D2' to dns domain 'darkside.local'
Sieht gut aus. Kerberos funktioniert jetzt:
root@srv-r2d2:~# kinit luke.skywalker@DARKSIDE.LOCAL
Password for luke.skywalker@DARKSIDE.LOCAL:
root@srv-r2d2:~# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: luke.skywalker@DARKSIDE.LOCAL
Aber SMB?
root@srv-r2d2:~# smbclient -k //srv-r2d2.darkside.local/daten -c ls
session setup failed: NT_STATUS_ACCESS_DENIED
Immer noch ACCESS_DENIED. Der LDAP-Machine-Bind scheitert weiterhin mit 52e.
Warum? net ads join repariert nur die Samba AD-Seite (Kerberos, Machine-Account im AD). Es aktualisiert aber nicht den UCS-LDAP – und dort haengt die Machine-Authentifizierung des Memberservers.
Das ist dasselbe Dual-Directory-Problem wie beim DC-Shadow-Context: Samba AD und UCS-LDAP sind zwei getrennte Welten.
Die echte Loesung: univention-join
Der Memberserver muss sich komplett neu bei dc-yoda registrieren – mit univention-join. Aber der Weg dahin ist gepflastert mit TLS-Fallen, besonders wenn du Step-CA statt der UCS-CA nutzt.
Vorbereitung: UCR auf neuen DC umstellen
root@srv-r2d2:~# ucr set \
ldap/server/name=dc-yoda.darkside.local \
ldap/server/ip=192.168.66.2 \
ldap/master=dc-yoda.darkside.local \
kerberos/kdc=dc-yoda.darkside.local \
nameserver1=192.168.66.2
Huerden auf dem Weg
1. SSH Host Key Mismatch
root@srv-r2d2:~# univention-join -dcname dc-yoda.darkside.local \
-dcaccount luke.skywalker
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
univention-join verbindet sich per SSH zum DC. Wenn du den DC neu aufgesetzt hast (nicht promoted, sondern frisch installiert), hat er einen neuen Host Key. Der alte Key von dc-vader liegt noch in known_hosts – aber auch wenn dc-yoda den gleichen Hostnamen-Eintrag hat, kann der Key von einer frueheren Installation stammen.
ssh-keygen -R dc-yoda.darkside.local
ssh-keygen -R 192.168.66.2
2. SSL Certificate Verify Failed
root@srv-r2d2:~# univention-join -dcname dc-yoda.darkside.local \
-dcaccount luke.skywalker
...
SSL error: certificate verify failed (self signed certificate in certificate chain)
Du nutzt Step-CA (“Rebellion Internal CA”) statt der UCS-eigenen CA. UCS erwartet aber seine eigene CA unter /etc/univention/ssl/ucsCA/CAcert.pem.
# Step-CA Root-Zertifikat als UCS-CA hinterlegen
cp /usr/local/share/ca-certificates/rebellion-internal-ca.crt \
/etc/univention/ssl/ucsCA/CAcert.pem
# System-Trust aktualisieren
update-ca-certificates
3. ldap.conf TLS_CACERT hardcoded auf UCS-CA
Selbst nach dem Austausch der CA-Datei kann es scheitern. Der Grund:
root@srv-r2d2:~# grep TLS_CACERT /etc/ldap/ldap.conf
TLS_CACERT /etc/univention/ssl/ucsCA/CAcert.pem
Das ist OK wenn du Schritt 2 gemacht hast. Aber Achtung: Manche UCS-Versionen haben zusaetzlich eine TLS_REQCERT demand Zeile. Falls dein Step-CA-Zertifikat einen anderen CN/SAN hat als der DC-Hostname:
# Temporaer zum Testen (NICHT dauerhaft!)
# TLS_REQCERT allow
# Besser: Sicherstellen dass das Zertifikat den FQDN enthaelt
openssl s_client -connect dc-yoda.darkside.local:7636 </dev/null 2>/dev/null | \
openssl x509 -noout -text | grep -A1 "Subject Alternative Name"
4. Passwort-Datei: echo vs printf
univention-join kann ein Passwort aus einer Datei lesen. Klassischer Fehler:
# FALSCH - echo haengt ein \n an
echo "geheim123" > /tmp/join-pw.txt
# RICHTIG - printf ohne Newline
printf '%s' "geheim123" > /tmp/join-pw.txt
# Kontrolle
xxd /tmp/join-pw.txt | tail -1
# Darf NICHT mit 0a enden
Das trailing Newline fuehrt zu Invalid credentials und du suchst stundenlang am falschen Ende.
5. Join Script 20: AddressSanitizer Bug
root@srv-r2d2:~# univention-join -dcname dc-yoda.darkside.local \
-dcaccount luke.skywalker
...
Running join script 20univention-directory-listener...
==12345==ERROR: AddressSanitizer: heap-buffer-overflow
SUMMARY: AddressSanitizer: heap-buffer-overflow ...
Das ist ein bekannter UCS-Bug in bestimmten Versionen. Der AddressSanitizer in univention-directory-listener crasht, aber der eigentliche Join ist zu dem Zeitpunkt bereits abgeschlossen.
# Pruefen ob der Join trotzdem erfolgreich war
univention-check-join-status
# "Joined successfully"
# Falls das Script haengt: Ctrl+C und pruefen
cat /var/univention-join/status
Du kannst das fehlgeschlagene Join-Script spaeter einzeln nachholen:
univention-run-join-scripts --force --run-scripts 20univention-directory-listener
Der eigentliche Join
Wenn alle TLS-Huerden beseitigt sind:
root@srv-r2d2:~# univention-join -dcname dc-yoda.darkside.local \
-dcaccount luke.skywalker -dcpwd /tmp/join-pw.txt
* Running pre-join hooks ...
* Checking connection to dc-yoda.darkside.local ...
* Setting up SSL ...
* Running join scripts ...
20univention-directory-listener ... [AddressSanitizer, ignoriert]
26univention-samba ... done
30univention-pam ... done
...
* Join successful
Die Ueberraschung: UCR-Revert
Du hast vor dem Join brav die UCR-Variablen auf dc-yoda umgestellt. Du hast den Join erfolgreich durchgefuehrt. Du lehnst dich zurueck. Und dann:
root@srv-r2d2:~# ucr get ldap/server/name
dc-vader.darkside.local
Was?! univention-join hat die UCR-Variablen zurueckgesetzt! Der Join-Prozess liest die “offizielle” Konfiguration aus dem LDAP und schreibt sie in die UCR. Wenn der alte DC noch als ldap/server/name im LDAP-Directory steht (weil niemand ihn dort entfernt hat), wird er froehlich wieder eingetragen.
# Nach dem Join: UCR ERNEUT korrigieren
ucr set \
ldap/server/name=dc-yoda.darkside.local \
ldap/server/ip=192.168.66.2 \
ldap/master=dc-yoda.darkside.local \
kerberos/kdc=dc-yoda.darkside.local \
nameserver1=192.168.66.2
# Und diesmal auch im LDAP aufraeumen
# Auf dc-yoda: alten DC-Eintrag entfernen/aktualisieren
ssh root@dc-yoda.darkside.local 'udm computers/domaincontroller_master list'
Trockener Kommentar: univention-join ist wie ein Azubi, der die Akten alphabetisch umsortiert, nachdem du sie chronologisch geordnet hast. Technisch korrekt, praktisch kontraproduktiv.
Bonus: slapd TLS-Chain mit Step-CA
Falls dein dc-yoda ein TLS-Zertifikat von der “Rebellion Internal CA” (Step-CA) hat, stolperst du ueber ein weiteres Problem: slapd sendet nur das Leaf-Zertifikat, nicht die Intermediate-Chain.
# Was der Client sieht
openssl s_client -connect dc-yoda.darkside.local:7636 -showcerts </dev/null 2>/dev/null
# Nur 1 Zertifikat in der Ausgabe -- das Leaf
# Was der Client braucht
# Root-CA -> Intermediate -> Leaf (vollstaendige Chain)
Der Client kann das Leaf-Zertifikat nicht verifizieren, weil ihm die Intermediate fehlt. Die Loesung: CAcert.pem muss die gesamte Chain enthalten.
# Auf dc-yoda: Combined Bundle erstellen
cat /etc/step-ca/certs/intermediate_ca.crt \
/etc/step-ca/certs/root_ca.crt \
> /etc/univention/ssl/ucsCA/CAcert.pem
# slapd-Zertifikat muss ebenfalls die Chain enthalten
cat /etc/univention/ssl/dc-yoda.darkside.local/cert.pem \
/etc/step-ca/certs/intermediate_ca.crt \
> /etc/univention/ssl/dc-yoda.darkside.local/cert-chain.pem
# slapd-Konfiguration anpassen
ucr set ldap/server/tls/certificate=/etc/univention/ssl/dc-yoda.darkside.local/cert-chain.pem
systemctl restart slapd
Danach pruefen:
openssl s_client -connect dc-yoda.darkside.local:7636 -showcerts </dev/null 2>/dev/null | \
grep -c "BEGIN CERTIFICATE"
# Erwartet: 2 oder 3 (Leaf + Intermediate, optional Root)
Lessons Learned
1. net ads join != univention-join
net ads join repariert nur die Samba AD/Kerberos-Seite. Fuer UCS-Memberserver brauchst du univention-join, weil dieser auch den UCS-LDAP (Machine-Account, Policies, UCR) aktualisiert.
2. Step-CA mit UCS ist ein Minenfeld
UCS erwartet seine eigene CA ueberall. Wenn du Step-CA nutzt, musst du an mindestens drei Stellen eingreifen: CAcert.pem, ldap.conf und die slapd-Chain.
3. univention-join revertiert UCR-Variablen
Nach dem Join IMMER pruefen ob die UCR-Variablen noch korrekt sind. Der Join liest die “offizielle” Konfiguration aus dem LDAP – und die kann veraltet sein.
4. printf, nicht echo
Passwort-Dateien mit echo erzeugen ist ein Klassiker-Fehler. Das trailing Newline ist unsichtbar und fuehrt zu stundenlangem Debugging.
5. AddressSanitizer in Join-Scripts ist ein UCS-Bug
Nicht dein Problem. Pruefen ob der Join trotzdem erfolgreich war, fehlgeschlagene Scripts spaeter einzeln nachholen.
6. CIFS-Mounts nach DC-Wechsel neu aufbauen
umount -l /mnt/daten
mount -a
# oder spezifisch
mount -t cifs //srv-r2d2.darkside.local/daten /mnt/daten -o sec=krb5
Checkliste: Nach DC-Demote auf Memberservern
- [ ] DNS pruefen: `dig dc-yoda.darkside.local` loest korrekt auf?
- [ ] UCR umstellen: ldap/server/name, ldap/master, kerberos/kdc, nameserver1
- [ ] SSH known_hosts bereinigen: `ssh-keygen -R <alter-dc>`
- [ ] TLS pruefen: Step-CA in /etc/univention/ssl/ucsCA/CAcert.pem?
- [ ] TLS_CACERT in /etc/ldap/ldap.conf korrekt?
- [ ] Passwort-Datei: `xxd` pruefen, kein trailing 0x0a?
- [ ] `univention-join -dcname <neuer-dc> -dcaccount <admin>`
- [ ] Nach Join: UCR-Variablen ERNEUT pruefen (Revert!)
- [ ] `univention-check-join-status` -> "Joined successfully"
- [ ] Fehlgeschlagene Join-Scripts nachholen
- [ ] LDAP-Machine-Bind testen: `ldapsearch -D "$(ucr get ldap/hostdn)" -y /etc/machine.secret`
- [ ] SMB-Zugriff testen: `smbclient -k //srv-r2d2.darkside.local/daten -c ls`
- [ ] CIFS-Mounts neu einhaengen: `umount -l && mount -a`
- [ ] Abhaengige Dienste pruefen (Nextcloud, Docker-Container auf srv-chewbacca)
- [ ] Im LDAP alten DC-Eintrag entfernen (sonst revertiert der naechste Join wieder)
Getestet mit UCS 5.0 Memberserver, Samba 4.18, Step-CA 0.27. Die Kombination aus DC-Demote + Step-CA + Memberserver-Rejoin ist in der Univention-Dokumentation nicht beschrieben. Jetzt schon.