diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a80ceda --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Runtime-Daten nicht committen +docker-data/dms/mail-data/ +docker-data/dms/mail-state/ +docker-data/dms/mail-logs/ + +# SSL Private Key nicht committen +docker-data/dms/ssl/key.pem diff --git a/DOKU-Mailserver-Setup.txt b/DOKU-Mailserver-Setup.txt new file mode 100644 index 0000000..4faf0a5 --- /dev/null +++ b/DOKU-Mailserver-Setup.txt @@ -0,0 +1,204 @@ +================================================================================ + Docker-Mailserver mit Active Directory LDAPS - Dokumentation + ByteTrail GmbH | FH Burgenland SS 2026 | Team 3 VZ +================================================================================ + +UMGEBUNG +-------- +- Mailserver: SRV-EXCH01.byte.trail (10.10.10.11), Docker mit docker-mailserver v15.1.0 +- Domain Controller: SRV-DC01.byte.trail (10.10.10.10), Windows Server, AD DS +- Domain: byte.trail +- 29 Benutzer + 1 Service-Account in Active Directory +- Git-Repo: https://git.lucida.ee/blackicedbear/dms.git (Branch: main) + + +UEBERSICHT: WAS WURDE GEMACHT +------------------------------ + +1. LDAPS-Zertifikat auf dem Domain Controller (AD CS) + - Active Directory Certificate Services (AD CS) als Enterprise Root CA installiert + - Rolle: Certification Authority (Enterprise Root CA) + - CA-Name: byte-SRV-DC01-CA + - LDAPS (Port 636) wird automatisch aktiviert sobald ein Zertifikat mit + CN=SRV-DC01.byte.trail ausgestellt wird + - Skript: Setup-LDAPS-Certificate.ps1 + + Warum LDAPS statt LDAP? + - Windows Security Update erzwingt LDAP Signing unabhaengig von Registry-Einstellungen + - Einfaches LDAP (Port 389) funktioniert nicht mehr zuverlaessig mit Signing-Enforcement + - LDAPS (Port 636) umgeht das Problem komplett durch TLS-Verschluesselung + +2. Active Directory Benutzer und Struktur + - Skript: Setup-ByteTrail-AD.ps1 + - 6 OUs: Geschaeftsfuehrung, Sales, Marketing, Service, Server, Gruppen + - 11 Sicherheitsgruppen (GRP-GF-*, GRP-SALES-*, GRP-MKT-*, GRP-SVC-*, GRP-ALL-EMAIL, GRP-ADMINS) + - 29 Benutzer mit E-Mail-Adressen (vorname.nachname@byte.trail) + - 1 Service-Account: svc-mailserver (fuer LDAP-Bind) + - Standardpasswort Benutzer: ByteTrail2026! + - Service-Account Passwort: Mail$3rv!ceAcc2026 + +3. Docker-Mailserver Konfiguration (mailserver.env) + - ACCOUNT_PROVISIONER=LDAP + - LDAP_SERVER_HOST=ldaps://10.10.10.10 + - LDAP_BIND_DN=CN=Mailserver Service Account,OU=Server,DC=byte,DC=trail + - LDAP_START_TLS=no (weil wir ldaps:// verwenden) + - DOVECOT_AUTH_BIND=yes (Authentifizierung per LDAP-Bind statt Passwort-Vergleich) + - DOVECOT_USER_FILTER=(&(objectClass=person)(mail=%u)) + - DOVECOT_PASS_FILTER=(&(objectClass=person)(mail=%u)) + - SSL_TYPE=manual (selbst-signiertes Zertifikat) + +4. SSL/TLS Zertifikat fuer den Mailserver + - Selbst-signiertes Zertifikat fuer mail.byte.trail + - Wird automatisch beim ersten Start durch ssl-init Container erstellt + - Wichtig: basicConstraints=CA:FALSE (Thunderbird lehnt CA-Zertifikate als + Server-Zertifikate ab) + - SAN: DNS:mail.byte.trail, DNS:byte.trail + - Gueltig fuer 10 Jahre + + +PROBLEME UND LOESUNGEN +----------------------- + +Problem 1: LDAP-Verbindung haengt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Symptom: Dovecot LDAP-Verbindung zu ldaps://10.10.10.10 haengt endlos, + keine Fehlermeldung, keine Timeout-Meldung. + +Ursache: Die globale OpenLDAP-Client-Konfiguration (/etc/ldap/ldap.conf) + hatte kein TLS_REQCERT never. Die OpenLDAP-Bibliothek hat das + selbst-signierte CA-Zertifikat des DC stillschweigend abgelehnt. + Dovecot's eigene tls_require_cert=never Einstellung reicht NICHT aus, + weil die darunterliegende OpenLDAP-Bibliothek die globale Konfiguration + fuer ldaps:// Verbindungen nutzt. + +Loesung: In /etc/ldap/ldap.conf im Container: + TLS_REQCERT never + +Problem 2: LDAP-Suche gibt "Operations error" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Symptom: ldap_search() failed: Operations error (LDAP Error Code 1) + +Ursache: Active Directory liefert standardmaessig Referrals (Verweise auf + andere Naming Contexts wie CN=Configuration, CN=Schema). + Die OpenLDAP-Client-Bibliothek kann diese Referrals nicht verarbeiten + und meldet "Operations error". + +Loesung: In /etc/ldap/ldap.conf im Container: + REFERRALS off + +Problem 3: LDAP-Authentifizierung schlaegt fehl (Password mismatch) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Symptom: doveadm auth test anna.huber@byte.trail ByteTrail2026! + -> "Password mismatch (for LDAP bind)" + +Ursache: Alle AD-Benutzer wurden mit -ChangePasswordAtLogon $true erstellt + (im Setup-Skript). Das setzt pwdLastSet=0 in AD. Solange pwdLastSet=0 + ist, scheitern LDAP-Simple-Binds mit "Invalid Credentials" (data 52e). + +Loesung: Auf dem Domain Controller fuer alle Benutzer ausfuehren: + Invoke-Command -ComputerName 10.10.10.10 -ScriptBlock { + Get-ADUser -Filter {mail -like "*@byte.trail"} | + ForEach-Object { Set-ADUser $_ -ChangePasswordAtLogon $false } + } + +Problem 4: Dovecot kennt pass_attrs/user_attrs nicht (AD-Attribute fehlen) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Symptom: "uniqueIdentifier missing", "no fields returned by the server", + "User is missing UID" + +Ursache: Docker-mailserver generiert die Dovecot-LDAP-Konfiguration mit + Standardwerten fuer OpenLDAP-Schemata: + - pass_attrs = uniqueIdentifier=user,userPassword=password + - user_attrs = mailHomeDirectory=home,mailUidNumber=uid,... + Active Directory hat diese Attribute NICHT (kein uniqueIdentifier, + kein mailHomeDirectory, kein mailUidNumber etc.). + +Loesung: In user-patches.sh werden die Attribute beim Container-Start + automatisch umgeschrieben auf: + - pass_attrs = =user=%u + (statischer Wert, da auth_bind=yes den Benutzer per LDAP-Bind + authentifiziert und kein Passwort aus LDAP lesen muss) + - user_attrs = =uid=5000,=gid=5000,=home=/var/mail/%d/%n/home/,=mail=maildir:/var/mail/%d/%n + (statische Werte fuer UID/GID des vmail-Benutzers und Maildir-Pfade) + +Problem 5: Mail-Zustellung scheitert mit "Mailbox was deleted under us" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Symptom: dovecot-lda und LMTP melden beim Speichern einer Mail: + "failed to store into mailbox 'INBOX': Mailbox was deleted under us" + +Ursache: Die /var/mail Verzeichnisse waren als Bind-Mount von Windows NTFS + eingebunden. Docker auf Windows nutzt dafuer das v9fs-Dateisystem + (Plan 9 Filesystem Protocol). v9fs unterstuetzt die POSIX-Dateioperationen + nicht korrekt, die Dovecot fuer Maildir-Operationen benoetigt + (insbesondere dotlock-Dateien und dovecot-uidvalidity). + +Loesung: In docker-compose.yml Bind-Mounts durch Docker Named Volumes ersetzen: + Vorher: - ./docker-data/dms/mail-data/:/var/mail/ + Nachher: - dms-mail-data:/var/mail/ + Docker Named Volumes nutzen ext4 statt v9fs, was alle + POSIX-Dateisystemoperationen korrekt unterstuetzt. + +Problem 6: Thunderbird "Basic Constraints" Fehler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Symptom: "Der Server verwendet ein Zertifikat mit einer Basiseinschraenkung, + die es als eine Zertifizierungsstelle identifiziert." + +Ursache: Das selbst-signierte Zertifikat wurde mit basicConstraints CA:TRUE + generiert (OpenSSL-Standard fuer -x509). Thunderbird lehnt korrekt + ab, ein CA-Zertifikat als Server-Zertifikat zu akzeptieren. + +Loesung: Zertifikat neu generieren mit expliziten Extensions: + -addext "basicConstraints=critical,CA:FALSE" + -addext "keyUsage=digitalSignature,keyEncipherment" + -addext "extendedKeyUsage=serverAuth" + +Problem 7: Container-Restart ueberspringt user-patches.sh +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Symptom: Nach "docker restart" meldet der Container + "Skipping most setup routines" und user-patches.sh wird nicht + ausgefuehrt. LDAP-Fixes gehen verloren. + +Ursache: docker-mailserver erkennt einen Restart (vs. frischen Start) + und ueberspringt Setup-Routinen inkl. user-patches.sh. + +Loesung: Statt "docker restart" immer "docker compose down && docker compose up -d" + verwenden, damit der Container frisch erstellt wird und + user-patches.sh ausgefuehrt wird. + Bei einem einfachen Restart bleiben die Aenderungen im + Container-Dateisystem erhalten (nur relevant wenn der Container + nicht geloescht wird). + + +WICHTIGE DATEIEN +---------------- +docker-compose.yml - Docker Services (ssl-init, mailserver, mssql) +mailserver.env - Mailserver-Konfiguration (LDAP, SSL, Filter) +docker-data/dms/config/user-patches.sh - Startup-Patches (LDAP TLS, Referrals, Dovecot attrs) +docker-data/dms/config/ldap-ca.pem - LDAPS CA-Zertifikat vom Domain Controller +docker-data/dms/ssl/cert.pem - Mailserver TLS-Zertifikat (selbst-signiert) +docker-data/dms/ssl/key.pem - Mailserver TLS-Schluessel +Setup-ByteTrail-AD.ps1 - AD-Setup (OUs, Gruppen, Benutzer, Service-Account) +Setup-LDAPS-Certificate.ps1 - LDAPS-Zertifikat-Setup auf dem DC + + +THUNDERBIRD-EINSTELLUNGEN +------------------------- +Server: mail.byte.trail +IMAP: Port 993, SSL/TLS +SMTP: Port 587, STARTTLS +Benutzername: anna.huber@byte.trail (oder jeder andere AD-Benutzer) +Passwort: ByteTrail2026! + +Beim ersten Verbinden muss die Sicherheitsausnahme fuer das selbst-signierte +Zertifikat bestaetigt werden. Alternativ kann das Zertifikat +(docker-data/dms/ssl/cert.pem) in Thunderbird importiert werden: +Einstellungen > Datenschutz & Sicherheit > Zertifikate verwalten > +Zertifizierungsstellen > Importieren + + +USER-PATCHES.SH - WAS WIRD BEIM START GEMACHT +---------------------------------------------- +1. /etc/ldap/ldap.conf: TLS_REQCERT never + REFERRALS off +2. LDAP CA-Zertifikat in System Trust Store installieren +3. Dovecot LDAP: tls_require_cert=never, pass_attrs und user_attrs fuer AD anpassen +4. Postfix LDAP: TLS-Zertifikatspruefung deaktivieren diff --git a/docker-compose.yml b/docker-compose.yml index 4b04fc9..b3915bb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,8 +34,8 @@ services: - "587:587" # ESMTP (explicit TLS => STARTTLS) - "993:993" # IMAP4 (implicit TLS) volumes: - - ./docker-data/dms/mail-data/:/var/mail/ - - ./docker-data/dms/mail-state/:/var/mail-state/ + - dms-mail-data:/var/mail/ + - dms-mail-state:/var/mail-state/ - ./docker-data/dms/mail-logs/:/var/log/mail/ - ./docker-data/dms/config/:/tmp/docker-mailserver/ - ./docker-data/dms/ssl/:/tmp/dms-ssl/:ro @@ -68,4 +68,6 @@ services: - mssql_data:/var/opt/mssql volumes: + dms-mail-data: + dms-mail-state: mssql_data: diff --git a/docker-data/dms/config/ldap-ca.pem b/docker-data/dms/config/ldap-ca.pem new file mode 100644 index 0000000..c02e405 Binary files /dev/null and b/docker-data/dms/config/ldap-ca.pem differ diff --git a/docker-data/dms/config/user-patches.sh b/docker-data/dms/config/user-patches.sh new file mode 100644 index 0000000..8aa9925 --- /dev/null +++ b/docker-data/dms/config/user-patches.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# Custom patches for docker-mailserver +# Wird bei jedem Container-Start ausgefuehrt +# Fixes fuer Active Directory LDAPS-Authentifizierung + +echo "=== user-patches.sh: Starte Anpassungen ===" + +# 1. Globale OpenLDAP Client-Konfiguration +cat > /etc/ldap/ldap.conf <<'EOF' +TLS_REQCERT never +REFERRALS off +EOF +echo "[OK] /etc/ldap/ldap.conf: TLS_REQCERT never + REFERRALS off" + +# 2. LDAP CA-Zertifikat in den System Trust Store kopieren +if [ -f /tmp/docker-mailserver/ldap-ca.pem ]; then + cp /tmp/docker-mailserver/ldap-ca.pem /usr/local/share/ca-certificates/ldap-ca.crt + update-ca-certificates 2>/dev/null + echo "[OK] LDAP CA-Zertifikat installiert" +fi + +# 3. Dovecot LDAP config fuer Active Directory anpassen +if [ -f /etc/dovecot/dovecot-ldap.conf.ext ]; then + # TLS-Zertifikatspruefung deaktivieren + sed -i 's/^tls_require_cert =.*/tls_require_cert = never/' /etc/dovecot/dovecot-ldap.conf.ext + if ! grep -q '^tls_require_cert' /etc/dovecot/dovecot-ldap.conf.ext; then + echo 'tls_require_cert = never' >> /etc/dovecot/dovecot-ldap.conf.ext + fi + + # pass_attrs: AD hat kein uniqueIdentifier/userPassword - nutze statische Werte mit auth_bind + sed -i 's|^pass_attrs.*=.*uniqueIdentifier=user,userPassword=password|pass_attrs = =user=%u|' /etc/dovecot/dovecot-ldap.conf.ext + # Falls pass_attrs noch den alten Wert hat (verschiedene Varianten) + if grep -q 'uniqueIdentifier=user' /etc/dovecot/dovecot-ldap.conf.ext; then + sed -i 's|^pass_attrs.*=.*|pass_attrs = =user=%u|' /etc/dovecot/dovecot-ldap.conf.ext + fi + + # user_attrs: AD hat keine mailHomeDirectory/mailUidNumber etc. - statische Werte setzen + sed -i 's|^user_attrs.*=.*mailHomeDirectory=home.*|user_attrs = =uid=5000,=gid=5000,=home=/var/mail/%d/%n/home/,=mail=maildir:/var/mail/%d/%n|' /etc/dovecot/dovecot-ldap.conf.ext + # Fallback falls anderes Format + if grep -q 'mailHomeDirectory' /etc/dovecot/dovecot-ldap.conf.ext; then + sed -i 's|^user_attrs.*=.*|user_attrs = =uid=5000,=gid=5000,=home=/var/mail/%d/%n/home/,=mail=maildir:/var/mail/%d/%n|' /etc/dovecot/dovecot-ldap.conf.ext + fi + + echo "[OK] Dovecot LDAP config angepasst (tls_require_cert, pass_attrs, user_attrs)" +fi + +# 4. Postfix LDAP: TLS-Zertifikatspruefung deaktivieren +for f in /etc/postfix/ldap-*.cf; do + if [ -f "$f" ]; then + if grep -q 'tls_require_cert' "$f"; then + sed -i 's/^tls_require_cert =.*/tls_require_cert = no/' "$f" + fi + fi +done +echo "[OK] Postfix LDAP TLS config angepasst" + +echo "=== user-patches.sh: Alle Anpassungen abgeschlossen ===" diff --git a/docker-data/dms/ssl/cert.pem b/docker-data/dms/ssl/cert.pem new file mode 100644 index 0000000..8434906 --- /dev/null +++ b/docker-data/dms/ssl/cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFXjCCA0agAwIBAgIUNo3ZPo09L3u82esTpepPnxZtLRAwDQYJKoZIhvcNAQEL +BQAwGjEYMBYGA1UEAwwPbWFpbC5ieXRlLnRyYWlsMB4XDTI2MDUwODE0MzQ0OFoX +DTM2MDUwNTE0MzQ0OFowGjEYMBYGA1UEAwwPbWFpbC5ieXRlLnRyYWlsMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7xCzBbQzPoweGWJnHB/7A12LSUJK ++DZRtEVYByQl0gLFe9hAGNmzUsj+ubyUGoQwhbwy2+GQVwx0kUlBRIurtGYhZNUm +zZj3Np4ovzPMvYRynlG1SOCCjhdDmC9MQTpcNfOiHMsTNlkDPR93UW+ZkMwwPm05 +H1cibyOXDfvlMn8U5UAvSUzW9KNXMYCTXyu4iin0BLud78Gt8eXT62gdo/+keyJz +WW3W0vqndxElbvRb9tbLp2Ut95VdUtEBCdBac+qppfj1DXYsh9tNG+AOyKxFW7Nq +EIJJjYGgEGN17DV5BgqTga71F+42j9XvwG/H92at6QijOrOqyZOMI6GanJvl0SHj +2Aw8dX6QFg/DvAOKs2OTLBX3cW087w6Snf6zKSuVHcMV6fvcN5hvwPQ/eTwwIE3/ +2om0Djg1BhqcJWPfKqfreWCEwsZT3AnqDN5j24a12N1QQNGtwBtwk6srX4GIOdvd +vo8YhpIaaYekoO0AsWEvU0JtwtADtRhWNLxiMkVLhsj3QTEKpTYGVlgSF64FTXKM +2Ty5a9BJ1S3ts43ODFPkmu6P65I7ur4gcIgeFXIeAXxjQNAGAzvM9LotscuTyuNM +/NY3YQgSTOHBpS/i1+cdBbj8KsY1wvgkLsL+SIaNo2M0qMmRQY1snoqcm5/nVe5E +aXjYW8pkv2aAObcCAwEAAaOBmzCBmDAdBgNVHQ4EFgQUyj742ZIMSLDYRpjnWbY/ +mLwmdf4wHwYDVR0jBBgwFoAUyj742ZIMSLDYRpjnWbY/mLwmdf4wJgYDVR0RBB8w +HYIPbWFpbC5ieXRlLnRyYWlsggpieXRlLnRyYWlsMAwGA1UdEwEB/wQCMAAwCwYD +VR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4IC +AQCfTDcjt00TR615ef8DpOf9B4ty4nRLg4ZRjKW2OAqgL0gWY5ymg7BkTnbawHj7 +RyS3sRjqO4O+9KXxDBOou+YqpvLoEmM9lHQGPaU6CxSgt+9ef1moMP0szAyQNrTW +5buPBGg/nUQl6zT2PYuv5B5ry7yuNgYJWw+2bVveH+W41FkKSfI3dGyXXGXLRbmf +LzeBX146jkaO9cr61QauA+IwYDuWgMOu8R+VssYCU5wLbkwRU3d9qHoZD6VwJpwF +doyzAm0LfJj/0B8Zjj+84Lsx7uhQtmMeYqt4RtsQXxt9dWEap8numAfgNBOA2kaR +M0/9dYz4DP9udq+0PJmaBPGYFRAfWCweThWAEmPrm8q6JoruZZvj3vmONiL9VhpC +FUQKkq9bmQrJr+qHUm1oYOUp6eM3aDRZRnoh7UKv8DALMoGggQmorFC/3bgOhBS0 +I5RcS1Nny6sTlnMHXTM9zZYM2obWGY/r5Dr97F0s00bftPEcEMO78LJvp5cJwdqo +kQ6U1Tm+/T8Sazt5jxomA1JoC+sUhcS++5EdvEDxZY28k68TBuKLW68AsveV3FkC +4JHM7vUIk2WkXocE6txj7Y0VcpbWd95c6zyGqlrKYN1pARm7iUlQFcU79UxQLJGW +2dL16VyHbaxW1TkWja2d8dW5bvGh2i/IfwW2FaoKXBWeEg== +-----END CERTIFICATE----- diff --git a/docker-data/dms/ssl/ldap-ca.pem b/docker-data/dms/ssl/ldap-ca.pem new file mode 100644 index 0000000..c02e405 Binary files /dev/null and b/docker-data/dms/ssl/ldap-ca.pem differ diff --git a/mailserver.env b/mailserver.env index 570467f..d1d64e8 100644 --- a/mailserver.env +++ b/mailserver.env @@ -460,7 +460,7 @@ LDAP_START_TLS=no # empty => mail.example.com # Specify the `` / `` where the LDAP server is reachable via a URI like: `ldaps://mail.example.com`. # Note: You must include the desired URI scheme (`ldap://`, `ldaps://`, `ldapi://`). -LDAP_SERVER_HOST=ldap://10.10.10.10 +LDAP_SERVER_HOST=ldaps://10.10.10.10 # empty => ou=people,dc=domain,dc=com # => e.g. LDAP_SEARCH_BASE=dc=mydomain,dc=local