85.1.39. pepsi-setup

provision the Pepsi database, signing keys and DNS for a deployment

Handbuchabschnitt:

1

85.1.39.1.1. Name

pepsi-setup - das Schema installieren, die Konfiguration validieren, DKIM-Schlüssel erstellen und DNS-Einträge ausgeben.

85.1.39.1.2. Übersicht

pepsi-setup [GLOBAL-OPTIONS] [run [-r | –reset]]

pepsi-setup [GLOBAL-OPTIONS] schema [–backup-dir DIR] [–if-installed]

pepsi-setup [GLOBAL-OPTIONS] check

pepsi-setup [GLOBAL-OPTIONS] visualize

pepsi-setup –wizard [–force] [–expert SPEC] [–answers FILE] [–import MTA [–import-root DIR] | –no-import] [-c FILE]

pepsi-setup [GLOBAL-OPTIONS] questions

pepsi-setup [GLOBAL-OPTIONS] apply [–once] [–idle SECS]

pepsi-setup [GLOBAL-OPTIONS] apply –clear

pepsi-setup [GLOBAL-OPTIONS] bootstrap [–valid-for SECS] [–admin-url URL]

pepsi-setup [GLOBAL-OPTIONS] import [MTA] [–root DIR] [–out DIR] [–alias-style STYLE]

GLOBAL-OPTIONS umfassen –no-certbot, –no-reverse-proxy und -y/-n, um Eingabeaufforderungen nicht-interaktiv zu beantworten (siehe Globale Optionen).

85.1.39.1.3. Beschreibung

pepsi-setup ist das administrative Bootstrap-Werkzeug für eine Pepsi-Installation. In einem einzigen Aufruf:

  1. Validiert die Konfiguration. Es parst die [pepsi]- und [pepsi-ingress]-Abschnitte (einschließlich Listener) und die [stage-*]-Pipeline — prüft, dass ein [stage-init] existiert, dass jedes NEXT_STAGE/BOUNCE_STAGE auflöst und dass die Programmkonfiguration jeder Stage (einschließlich des Routings zum vorgelagerten MTA) geparst werden kann — und prüft, dass jeder Domainname wohlgeformt und jeder PUBLIC_IP-Eintrag eine gültige IP-Adresse ist. Es warnt, wenn die PUBLIC_IP einer Relay-Stage eine nicht-öffentliche Adresse ist (Loopback, RFC 1918 / Unique-Local, Link-Local oder CGNAT) — eine solche Adresse kann im Internet niemals Mail senden, sodass sie mit dem abschließenden -all ausgehende Mail aus dieser Adressfamilie an SPF scheitern lässt (verwenden Sie hinter NAT die öffentliche Egress-IP des Hosts, nicht seine LAN-Adresse) —, und wenn eine Relay-Stage überhaupt keine PUBLIC_IP setzt (der Eintrag degradiert zu einem bloßen v=spf1 -all). Es verweigert außerdem die in der Beispielkonfiguration mitgelieferte reservierte .invalid-Platzhalter-Identität: Wenn eines von HOSTNAME, ACCEPTED_DOMAINS, [pepsi] ARC_DOMAIN oder einem Stage-SERVER_NAME noch auf .invalid endet (z. B. example.invalid), stoppt es mit einem Fehler, der die beanstandeten Werte benennt, weil das Beispiel nie bearbeitet wurde — statt Schlüssel und DNS für eine Domain einzurichten, die nie Mail empfangen kann. Setzen Sie diese Felder auf Ihre echte Domain oder führen Sie pepsi-setup --wizard aus. Es warnt vor jeder in einem bekannten Abschnitt gesetzten Option, die nichts liest — eine falsch geschriebene Option nimmt stillschweigend ihren Standardwert an — und schlägt dabei den nächstliegenden echten Optionsnamen vor, sowie vor Optionen, die seit einer früheren Version umbenannt wurden (siehe „Umbenannte Optionen“ in pepsi.conf(5)). Abschnitte, die es nicht kennt, bleiben unberührt. Wenn etwas falsch ist, meldet es das Problem und beendet sich mit einem Wert ungleich null, ohne ein Schema zu installieren, einen Schlüssel zu erzeugen oder irgendetwas zu veröffentlichen. (Die Validierung ist nicht buchstäblich das Erste, was läuft: Die unten beschriebenen Schritte, die die Konfigurationsdatei reparieren — die Reverse-Proxy-Integration, die certbot-Pfade, das Herkunftsnachweis-Secret, die Telemetrie-Kennung und die MAILBOX_FS_QUOTA-Sondierung —, gehen ihr notwendigerweise voraus, weil die Validierung gegen ihr Ergebnis läuft.) Die vom Operator bearbeiteten Map-Dateien (unten) sind bewusst nicht Teil dieses Schritts, sodass ein unzusammenhängender Map-Tippfehler den Lauf nie blockieren kann. Wenn die Pipeline eine pepsi-stage-detect-language-Stage verwendet, dieses Binärprogramm aber nicht auf $PATH gefunden wird (es wird in einem eigenen großen Paket, getrennt vom Rest von Pepsi, ausgeliefert), warnt der Lauf und fährt fort — installieren Sie pepsi-stage-detect-language vor dem Start des Dienstes, sonst kann die detect-language-Stage nicht gestartet werden. Zwei weitere nicht-fatale Warnungen weisen auf wahrscheinliche Fehlkonfigurationen hin: eine pepsi-stage-block-language-Stage mit einer BLACKLIST, aber leerer WHITELIST und einem nicht-negativen THRESHOLD (was alle Mail in neutraler Sprache als Bounce zurückweist — siehe pepsi-stage-block-language(1)), und ein nicht-fortschreitender NEXT_STAGE-Zyklus (eine Kette von NEXT_STAGE-Kanten, die auf sich selbst zurückführt, sodass eine Nachricht bis MAX_LIFETIME im Kreis liefe; legitimer Wiedereintritt über BOUNCE_STAGE/RESTART_STAGE wird nicht markiert). Es warnt außerdem, wenn ein TARGETS-Eintrag eine uid unterhalb von UID_MIN aus /etc/login.defs zulässt, und zwar bei einer Stage, deren setuid-Helfer solche uids verweigert — pepsi-stage-relay-to-maildir(1), pepsi-stage-dot-forward(1) und pepsi-stage-auto-pay(1) mit WALLET_MODE = local-user —, da ein Empfänger, auf den nur dieser Eintrag passt, bei jeder Nachricht im Helfer scheitert.

    Die Einstellungen der Ende-zu-Ende-Kryptographie werden hier ebenfalls geprüft: die CRYPTO_*-Optionen von [pepsi] und der Schlüsselspeicher-Abschnitt [pepsi-crypto] (siehe pepsi.conf(5)). Einzeln gültige, gemeinsam aber falsche Kombinationen sind Fehler — CRYPTO_SMIME_SHARED_KEY = yes mit einem Elliptische-Kurven-CRYPTO_SMIME_ALGORITHM (ein EC-Schlüssel, der sowohl ECDSA als auch ECDH macht, wird von mehreren S/MIME-Clients abgelehnt), ein CRYPTO_GENERATE_RSA_BITS unterhalb von CRYPTO_MIN_RSA_BITS (die Installation erzeugte Schlüssel, die sie dann ablehnt), ein unplausibel kleines CRYPTO_MIN_RSA_BITS, ein nicht positives IDENTITY_VALIDITY_DAYS und ein KEY_WRAP_KEY_ID, das seine eigene KEY_WRAP_SECRET_<ID>-Option nicht benennen könnte. Ein [pepsi-crypto]-Abschnitt, der überhaupt etwas sagt, aber kein KEY_WRAP_SECRET hat, ist ebenfalls ein Fehler, und die Meldung nennt das @inline-secret@-Fragment, aus dem das Geheimnis hätte kommen sollen, samt seinem Eigentümer und Modus: Der @inline-secret@-Mechanismus warnt nur über ein Fragment, das er nicht lesen kann, sodass ein unlesbares andernfalls von einer nicht gesetzten Option nicht zu unterscheiden ist. Ein Geheimnis, das kürzer als 16 Zeichen ist, wird abgelehnt — es ist der eine Schlüssel, der jeden gespeicherten privaten Schlüssel öffnet. Eine Installation, die keine Ende-zu-Ende-Kryptographie betreibt, konfiguriert nichts davon und wird deswegen nicht behelligt.

    Für jede pepsi-stage-encrypt(1)-Stage prüft es außerdem die pEp-Voreinstellung (ENABLE_PEP) und die Schlüssel-Selbstbedienung. Es warnt, wenn ENABLE_PEP eingeschaltet ist, aber [pepsi-crypto] AUTO_CREATE_IDENTITY = no gilt (ein gültiges Veto des Standorts, doch dann erhält kein Absender automatisch einen Schlüssel; setzen Sie ENABLE_PEP = no, um das ausdrücklich zu machen) oder kein KEY_WRAP_SECRET konfiguriert ist (kein Absender kann einen Schlüssel erhalten); wenn RESPONSE_STAGE nicht gesetzt ist (Benutzer erfahren nicht, wenn ein neuer Schlüssel für ihre Adresse registriert wird, und die E-Mail-Schlüsselbefehle an pepsi-keys@<domain> sind abgeschaltet); und wenn [pepsi-ingress] USERNAME_MAP einen Platzhalter gewährt, wobei es diese Konten nennt: Sie dürfen als jede passende Adresse senden, können aber nie einen eigenen Schlüssel für eine davon registrieren. Es verweigert ein RESPONSE_STAGE, das keine Stage benennt, und, wenn RESPONSE_STAGE gesetzt ist, ein TEMPLATE_DIR, dem die Rückfallvorlage key-registered.en.body oder keys.en.body fehlt.

    Das Setup repariert außerdem ein verwaistes Fragment. Das Geheimnis und die @inline-secret@-Direktive, die es einzieht, sind zwei Hälften einer Aussage, die in zwei Dateien leben, und das Fragment überlebt die Konfiguration, die es referenzierte — sodass eine neu erzeugte oder handgeschriebene pepsi.conf eine Installation hinterlässt, in der secrets.d/pepsi-crypto.secret vorhanden und korrekt ist, nichts es lädt und jede Nachricht durch pepsi-stage-encrypt(1) scheitert. Keine der beiden Hälften sieht für sich falsch aus, und ein erneuter Lauf als root hilft nicht: root kann das Fragment lesen, aber die Direktive ist es, die es einzieht. Wenn das Fragment existiert und die Konfiguration es nicht referenziert, fügt das Setup die Direktive hinzu und sagt es — das rotiert nichts und schreibt kein Schlüsselmaterial, ist also selbst dann sicher, wenn das Geheimnis selbst unlesbar ist. Was es nicht wiederherstellen kann, ist eine nicht standardmäßige KEY_WRAP_KEY_ID, die zu der verlorenen Datei gehörte, sodass die Warnung die von ihr behauptete ID nennt; setzen Sie sie von Hand, wenn der Schlüssel unter einer anderen gespeichert wurde.

  2. Bereitet die vom Operator bearbeiteten Map-Dateien vor. Bei jedem Lauf durchläuft es die konfigurierten Lookup-Tabellen — die [pepsi-ingress] USERNAME_MAP und die ALIASES-Map jeder pepsi-stage-aliases-Stage. Eine Datei, die nicht existiert, wird aus einer kommentierten Starter-Vorlage (Modus 0644) erstellt, die den Zweck der Datei dokumentiert und die Syntax zeigt, sodass der Operator eine selbstdokumentierende Datei am richtigen Ort vorfindet. Eine Datei, die existiert, wird mit demselben Parser auf Syntax geprüft, den die besitzende Komponente zur Laufzeit verwendet, sodass eine fehlerhafte Zeile (oder ein Adress-/Domain-Tippfehler) mit ihrer Zeilennummer sichtbar gemacht wird. Dieser Schritt ist rein beratend: eine fehlerhafte Map oder eine Vorlage, die nicht geschrieben werden kann, wird als Warnung protokolliert und bricht den Lauf nie ab (die Laufzeit-Parser sind selbst nachsichtig, warnen und überspringen eine fehlerhafte Zeile). Im --wizard-Modus läuft dies erst nachdem pepsi.conf geschrieben wurde, sodass ein Map-Problem den Assistenten nie daran hindert, die Konfiguration zu schreiben.

  3. Integriert sich mit einem bestehenden Front-HTTP-Server. Wenn ein anderer Webserver (nginx oder Apache) bereits auf den Ports 80/443 lauscht, kann pepsi-httpd 443 nicht binden und certbot --standalone kann 80 nicht binden. Statt um die Ports zu kämpfen, erkennt pepsi-setup den Front-Server (über ss), bestätigt, dass er keinen der mta-sts.<domain>-Hostnamen bereits bedient, und (a) hält [pepsi-httpd-listener-https] socket-aktiviert, aber als Klartext-HTTP (SERVE = systemd, MODE = plain), entfernt jedes direkt bindende MODE = tls + TLS_CERT/TLS_KEY und die nun nicht mehr benötigten [pepsi-httpd-cert-*]-Abschnitte und legt ein pepsi-httpd.socket-Override (/etc/systemd/system/pepsi-httpd.socket.d/10-reverse-proxy.conf) ab, das ListenStream von 443 auf einen UNIX-Socket unter /run/pepsi/httpd.sock umbindet (SocketGroup= die Gruppe des Front-Servers: www-data unter Debian, anderswo nginx/apache/httpd), und (b) schreibt eine Reverse-Proxy-Site (pepsi-mta-sts) in die sites-available des Front-Servers (und aktiviert sie in sites-enabled; conf.d für Nicht-Debian-nginx), die TLS für diese Hostnamen terminiert und sie an den Socket weiterleitet. Der Front-Server terminiert nun TLS, sodass die Zertifikate (dieser Schritt und das SMTP-MX-Zertifikat des nächsten Schritts) über das certbot-Authenticator-Plugin dieses Servers (--nginx/--apache) statt über --standalone bezogen werden. Dieser Schritt ist eine No-Op, wenn kein Front-Server vorhanden ist, und wird mit --no-reverse-proxy vollständig übersprungen (in welchem Fall pepsi-httpd 443 direkt bindet). Er ist idempotent: Sobald die pepsi-mta-sts-Site existiert, bekräftigen erneute Läufe nur den Socket-Listener. Die Integration wird aufgeschoben (mit einer umsetzbaren Meldung in der Zusammenfassung am Ende des Laufs, wobei pepsi-httpd in seiner direkt bindenden Konfiguration bleibt), statt abzubrechen, wenn der Front-Server bereits einen der mta-sts.<domain>-Namen bedient (ein Konflikt, den Sie auflösen müssen), wenn es ein Server ist, den pepsi-setup noch nicht automatisieren kann (Caddy, lighttpd, Apache Traffic Server — verdrahten Sie den Proxy von Hand oder übergeben Sie --no-reverse-proxy), wenn er nicht als root läuft oder wenn das MTA-STS-Zertifikat selbst nicht bezogen werden kann (die Reverse-Proxy-Site verweist auf das Live-Zertifikat, sodass sie nicht geschrieben werden kann, bevor das Zertifikat existiert) — führen Sie in jedem Fall pepsi-setup run erneut aus, sobald es aufgelöst ist. Der pepsi-httpd-Dienst muss das Socket-Verzeichnis bereitstellen (die mitgelieferte systemd-Unit tut dies mit RuntimeDirectory=pepsi), und der Benutzer des Front-Servers muss den gruppengeteilten Socket erreichen können.

  4. Richtet TLS-Zertifikate ein. Für jeden Listener, der TLS terminiert — die [pepsi-ingress-listener-*]-Sockets mit MODE = tls/starttls, die TLS-[pepsi-httpd-listener-*]-Sockets und jedes [pepsi-httpd-cert-*]-SNI-Zertifikat —, der kein TLS_CERT/TLS_KEY gesetzt hat, füllt es die Optionen mit dem Standard-certbot-Layout aus (/etc/letsencrypt/live/<host>/fullchain.pem und privkey.pem) und schreibt sie an Ort und Stelle in die Konfigurationsdatei (Kommentare bleiben erhalten). Der <host> ist das [pepsi-ingress] HOSTNAME für SMTP-/HTTP-Listener und der erste SNI-Host des Zertifikatsabschnitts für [pepsi-httpd-cert-*]; Listener, die sich einen Host teilen, teilen sich ein Zertifikat.

    Das Zertifikat des HTTPS-Listeners deckt zusätzlich openpgpkey.<domain> für jede Domain in ACCEPTED_DOMAINS ab, weil dort die erweiterte Methode des Web Key Directory abgerufen wird (pepsi-httpd(1)), und – wenn [pepsi-autoconfig] die Mail-Autokonfiguration einschaltet – auch autoconfig.<domain>, also die erste URL, die ein Mailprogramm versucht. Sie werden dem Zertifikat des Listeners selbst hinzugefügt und erhalten keinen eigenen Abschnitt [pepsi-httpd-cert-*], denn dieses Zertifikat ist der Rückfall, der ausgeliefert wird, wann immer SNI auf nichts passt – ein Zertifikat deckt damit sowohl den SNI-Treffer als auch den Rückfall ab.

    Das Zertifikat der Ingress-Listener deckt jeden MX-Host ab, den eine MTA-STS-Richtlinie erlaubt – die Menge [pepsi] MTA_STS_MX über alle bedienten Domains –, und zwar aus einem Grund, der auf der HTTPS-Seite kein Gegenstück hat. RFC 8461 §4.1 verlangt, dass das Zertifikat, das ein MX vorlegt, zu dem Namen passt, den der MX-Eintrag dem Absender gegeben hat, und pepsi-ingress(1) liefert genau ein Zertifikat je Listener aus: es hält das SNI des Clients fest, wählt aber nie danach aus. Ein Host, der als mx.example.org und mail.example.net erreichbar ist, kann daher nicht mit zwei Zertifikaten antworten; er braucht ein Zertifikat, das beide Namen trägt. Wildcard-mx-Einträge (*.example.net) werden mit einer Warnung übersprungen – HTTP-01 kann eine Wildcard nicht erfüllen, und eine an certbot zu übergeben würde die ganze Anfrage scheitern lassen, einschließlich der Namen, die funktioniert hätten –, eine Installation, die eine veröffentlicht, muss dieses Zertifikat daher selbst bereitstellen.

    Dann führt pepsi-setup für jeden solchen Host certbot certonly --standalone aus (HTTP-01 über TCP/80, ohne E-Mail-Adresse registriert), wenn das Zertifikat nicht auf der Platte liegt — und wenn es doch dort liegt, liest es die Subject Alternative Names daraus und führt certbot erneut aus (--expand, gleicher --cert-name), falls sie nicht jeden der oben genannten Namen abdecken. Das zählt, weil der Namenssatz eines Zertifikats bei der ersten Ausstellung nicht festgelegt ist: eine bediente Domain hinzuzufügen, die Autokonfiguration einzuschalten oder einen neuen MX-Host zu benennen weitet ihn jeweils. Ein Zertifikat, dessen Namen nicht gelesen werden können, wird in Ruhe gelassen statt neu ausgestellt, denn „ich konnte es nicht feststellen“ darf keine ratenbegrenzte Ausstellung verbrauchen. Jeder Name wird gegen DNS geprüft und nicht nur der --cert-name des Zertifikats selbst: certbot prüft jedes -d gesondert und lässt die ganze Anfrage scheitern, wenn einer davon nicht erreichbar ist.

    Für welche Zertifikate pepsi-setup certbot antreiben darf, entscheidet ein Vergleich der konfigurierten TLS_CERT/TLS_KEY mit den Layoutpfaden, die es für diesen Host selbst geschrieben hätte. Es kann nicht „ist TLS_CERT gesetzt?“ sein, denn ein erfolgreicher erster Lauf setzt es – danach sähe jeder Listener betreiberkonfiguriert aus, und kein Zertifikat ließe sich je wieder weiten. Pfade, die dem Layout entsprechen, sind die von pepsi-setup aktuell zu haltenden; alles andere ist ein Zertifikat, das der Betreiber gewählt hat, und wird nie angefasst, und ein halb konfigurierter Abschnitt (eine der beiden Optionen gesetzt) wird der strengen Validierung überlassen, die ihn besser meldet. Ein Zertifikat, das fehlt und nicht beschafft werden kann, wird aufgeschoben statt fatal: das Setup läuft weiter (installiert das Schema, erzeugt Schlüssel, gibt DNS-Einträge aus) und führt jedes aufgeschobene Zertifikat in einer Zusammenfassung ganz am Ende auf, mit dem konkreten nächsten Schritt und der Erinnerung, pepsi-setup run erneut auszuführen, sobald das Hindernis behoben ist. Ein erneuter Lauf ist idempotent und vollendet nur das, was noch fehlt. Ein Zertifikat wird aufgeschoben, wenn --no-certbot angegeben war, certbot nicht installiert ist, pepsi-setup nicht als root läuft (es kann dann TCP/80 nicht binden), das DNS des Hosts nicht auf eine konfigurierte PUBLIC_IP auflöst (die Herausforderung würde dann scheitern) oder certbot selbst scheitert (etwa ein vorübergehender Vorfall beim ACME-Server oder eine Ratenbegrenzung – ein einfacher erneuter Lauf versucht es dann noch einmal). Der DNS-Fall unterscheidet einen Namen ohne A/AAAA-Eintrag von einem, der anderswohin auflöst (und meldet die gefundenen Adressen gegenüber den konfigurierten PUBLIC_IPs). Da die Zertifikatsdatei dann fehlt, kann der DANE/TLSA-Eintrag für diesen Host nicht berechnet werden; die DNS-Ausgabe gibt daher einen Kommentar aus, der sagt, dass der Eintrag noch fehlt und wie er bereitzustellen ist. Nur ein wirklich unbrauchbarer Aufruf ist fatal: dass die Konfigurationsdatei nicht schreibbar ist, oder – wenn an keinem Standardort eine Konfigurationsdatei existiert und kein --config angegeben wurde – dass ihr Pfad unbekannt ist, sodass die automatisch gefüllten Pfade nicht dauerhaft gespeichert werden können. Beachten Sie, dass ein Server, dessen TLS-Listener noch kein Zertifikat hat, nicht startet, bis das Zertifikat existiert.

    Verschafft den Servern Zugriff auf ihr Schlüsselmaterial. Die TLS-Server (pepsi-ingress, pepsi-httpd) laufen unter unprivilegierten Benutzern und können certbots nur für root lesbaren Baum /etc/letsencrypt/{live,archive} nicht lesen; ein Listener würde sonst mit einem nackten permission denied nicht starten. Drei Mechanismen adressieren das, angewandt bei jedem Lauf:

    systemd-Dienst-Credentials — der primäre Mechanismus überall dort, wo systemd die Server ausführt. Für jeden Server schreibt pepsi-setup /etc/systemd/system/<unit>.d/10-tls-credentials.conf und benennt darin jedes Zertifikat und jeden Schlüssel, den dieser Server liest, als LoadCredential=-Eintrag. systemd öffnet diese Dateien dann als root, wenn es die Unit startet, und übergibt dem Dienst private Kopien unter $CREDENTIALS_DIRECTORY (einem Unit-eigenen tmpfs-Verzeichnis, das nur dieser eine Dienst lesen kann), wo Pepsis TLS-Lader jeden konfigurierten Pfad nachschlägt, bevor er auf das Lesen des Pfades selbst zurückfällt — die Dateirechte spielen damit überhaupt keine Rolle mehr. Das Drop-in wird bei jedem Lauf aus der Konfiguration neu erzeugt und führt nur Dateien auf, die existieren, denn systemd weigert sich, eine Unit zu starten, deren Credential-Quelle fehlt; führen Sie pepsi-setup run erneut aus, nachdem Sie ein Zertifikat hinzugefügt, verschoben oder entfernt haben. Ändert sich das Drop-in, lädt pepsi-setup systemd neu und führt für den betroffenen Server try-restart aus (nur wenn er läuft), damit das neue Material wirksam wird.

    POSIX-ACLs und ein certbot-Deploy-Hook — der Rückfall für eine Installation, die nicht von systemd ausgeführt wird, und das Vehikel für Erneuerungen. Für jedes certbot-verwaltete Zertifikat, auf das die Konfiguration verweist, gewährt pepsi-setup diesen Dienstbenutzern Lese- und Durchlaufrechte per POSIX-ACLs (setfacl) und installiert unter /etc/letsencrypt/renewal-hooks/deploy/pepsi-cert-access.sh einen certbot-Deploy-Hook, der die Rechtevergabe bei jeder künftigen Ausstellung/Erneuerung erneut anwendet (certbot rotiert archive/<host>/privkeyN.pem, eine einmalige Vergabe würde das also nicht überdauern; die Default-ACLs des Hooks sorgen dafür, dass neu erzeugte Dateien den Zugriff erben) und die Pepsi-Server neu startet, was ein erneuertes Zertifikat überhaupt erst in Betrieb nimmt — jeder Server liest sein Material einmal beim Start, und systemd stellt Credentials beim Start der Unit bereit. Diese Hälfte ist best effort: Sie benötigt root, setfacl (das Paket acl) und ein ACL-fähiges Dateisystem — eine fehlende Voraussetzung wird mit der Abhilfe zurückgestellt, nicht als fatal behandelt. Zertifikate außerhalb von certbots Baum (vom Operator gesetzte TLS_CERT/TLS_KEY) werden nicht verwaltet, sondern nur mit einer Warnung erwähnt; deren Leserechte vergeben Sie selbst.

    Überprüfung — für alles, was kein Credential abdeckt, nimmt pepsi-setup nicht an, dass die Rechtevergabe funktioniert hat. Es forkt, wird zum Dienstbenutzer und versucht, die Datei zu öffnen; ein weiterhin unlesbares Zertifikat (eine vom Dateisystem stillschweigend ignorierte ACL, ein nur für root zugängliches übergeordnetes Verzeichnis, ein vom Operator gesetzter Pfad, für den niemand Rechte vergeben hat) wird so als zurückgestellter Schritt gemeldet, der die genaue Datei, den Benutzer und die Unit benennt — statt später als Server aufzutauchen, der den Start verweigert.

    Stellt die Erreichbarkeit von Dovecot sicher. Wenn lokale Zustellung über LMTP oder Submission-Authentifizierung über Dovecot-SASL konfiguriert ist, prüft pepsi-setup den konfigurierten Socket als der Dienstbenutzer, der sich mit ihm verbinden wird — der pepsi des Dispatchers für LMTP, pepsi-ingress für SASL. Das fängt den häufigen Fall eines Sockets ab, der zwar existiert, aber unerreichbar ist: Dovecots geteilter /run/dovecot/auth-client ist 0600 dovecot und kann von pepsi-ingress nicht geöffnet werden. Wenn ein Socket fehlt oder nicht lesbar ist und ein lokales Dovecot vorhanden ist, bietet pepsi-setup (interaktiv als root laufend) an, ``/etc/dovecot/conf.d/10-pepsi.conf`` zu installieren — einen dedizierten unix_listener im Besitz des Pepsi-Dienstbenutzers (mode = 0600, sodass die Berechtigungen des geteilten Sockets unberührt bleiben) —, validiert dann die zusammengeführte Konfiguration mit doveconf und lädt Dovecot neu. Wenn es das nicht kann (nicht root, kein Terminal zum Nachfragen, doveconf weist das Ergebnis ab oder kein lokales Dovecot), gibt es das Drop-in aus und schiebt es auf, damit Sie es von Hand ausrollen können. Pepsis Standard-SASL_PATH ist dieser private Socket, /run/dovecot/auth-client-pepsi. Diese Prüfung läuft bei jedem pepsi-setup run, nicht nur unter --wizard. -y/--yes-to-all installiert das Drop-in ohne Nachfrage; -n/--no-to-all überspringt die Installation und gibt es nur aus — beides macht den Lauf vollständig nicht-interaktiv.

  5. Prüft auf einen anderen MTA auf den SMTP-Ports. Pepsi ist selten der erste Mailserver auf einem Host — Debian zieht Postfix oder Exim als Standard-mail-transport-agent mit herein. Wenn einer von ihnen noch lauscht, kann pepsi-ingress nicht binden, und der Fehlschlag bleibt auf besonders irreführende Weise still: Unter Socket-Aktivierung ist es pepsi-ingress.socket, das fehlschlägt (systemctl status pepsi-ingress.socket meldet Result: resources), Mail wird weiterhin vom anderen Server mit dessen Alias- und Virtual-Maps zugestellt, und jede Änderung an pepsi.conf scheint daher überhaupt keine Wirkung zu haben. pepsi-setup liest die Listener-Tabelle des Kernels (/proc/net/tcp) für jeden Port, den die [pepsi-ingress-listener-*]-Abschnitte benötigen — den konfigurierten PORT bei einem SERVE = tcp-Listener und die FD_INDEX-Zuordnung der mitgelieferten Socket-Unit (0 → 25, 1 → 465, 2 → 587) bei einem SERVE = systemd-Listener — und benennt den beanstandeten Prozess (mit seiner PID), wenn der Inhaber weder systemd noch Pepsi selbst ist. Dies ist beratend: Es wird auf die Zusammenfassung am Ende des Laufs aufgeschoben, statt fatal zu sein, da ein Operator mitten in einer Migration den alten MTA bewusst noch eine Weile laufen lassen möchte. Beheben Sie es, indem Sie den anderen Server stoppen und deaktivieren (systemctl disable --now postfix) und dann pepsi-ingress.socket starten.

    Prüft, ob der Resolver DNSSEC validiert. In derselben Phase und nur dann, wenn die Konfiguration DANE verlangt, stellt pepsi-setup dem System-Resolver eine Frage, deren Antwort es kennt, und achtet auf das AD-Bit. Pepsi vertraut einem validierenden Resolver, statt DNSSEC selbst zu validieren, ein Resolver, der AD nie setzt, lässt DANE und die DANE-gestützte Schlüsselsuche daher überhaupt nichts finden, und zwar stillschweigend. Ebenfalls aufgeschoben, nicht fatal.

  6. Installiert das Datenbankschema. Jede Pepsi-Komponente teilt sich eine Datenbank (den [pepsi-postgres]-Abschnitt) und das eine pepsi-Schema; pepsi-setup ist der einzige Installer. Das Schema ist eine einzige Patch-Serie (pepsi-NNNN.sql) mit einer procedures.sql, angewendet aus [pepsi-postgres] SQL_DIR (Standardwert ${DATADIR}/sql). Die Operation ist idempotent und kann nach Upgrades erneut ausgeführt werden. Die anderen Komponenten haben keinen eigenen Befehl zur Schema-Initialisierung.

    Richtet die Datenbank-Login-Rollen ein. Jedes Pepsi-Dienstkonto bekommt eine gleichnamige PostgreSQL-Login-Rolle, über den lokalen Socket per Peer-Authentifizierung authentifiziert, und die Berechtigungen, die es auf dem pepsi-Schema braucht. Die Pipeline-Rolle pepsi (und pepsi-crypto) bekommt das ganze Schema, abzüglich der unten beschriebenen Rücknahmen; die drei Dienste, die nicht die Pipeline sind, werden dann als allerletzter Schritt auf das zurückgestutzt, was eine Prüfung ihres Codes als tatsächlich genutzt ausweist, und das Setup weigert sich abzuschließen, wenn PostgreSQL dem widerspricht:

    pepsi-ingress

    INSERT in pepsi.workqueue und pepsi.workqueue_body (plus SELECT der IDs, die workqueue_add zurückgibt, und der beiden generierten Größenspalten header_octets und octets, die die Aufnahmeprüfung der Warteschlange summiert), SELECT auf config_override und mailbox_quota, INSERT auf den beiden nur anhängbaren Logs. Sie kann keine bereits eingereihte Nachricht lesen.

    pepsi-telemetry

    Ihre eigene Tabelle pepsi.telemetry.

    pepsi-httpd

    Alles, was die Konsole, das Portal, die Listen-Website und das Archiv verwenden, auf pepsi.workqueue aber nur die Umschlag-, state- und Routing-Spalten — nie headers oder den Nachrichtentext, und sie kann den body_id einer Nachricht nicht umbiegen; auf pepsi.workqueue_body nur INSERT (die Webformulare senden Mail) und DELETE (das Löschen einer Nachricht entfernt den Nachrichtentext, den nur sie trug; der Fremdschlüssel verweigert einen Nachrichtentext, auf den eine andere Nachricht noch verweist), nie SELECT des Nachrichtentexts — und überhaupt nichts auf settings, whitelist, vacation_reply, payment_request_reply, den Secretary-Tabellen, telemetry, origin_nonce oder auto_pay_spend; die Statistik-, Kontingent-, DNS- und TLS-Report-Tabellen sowie die Lebendigkeitszeile des Telemetrie-Daemons (telemetry_client) nur lesend.

    Die Standardberechtigungen für Tabellen, die ein späterer Patch anlegt, werden pepsi-ingress und pepsi-telemetry ebenfalls entzogen. Die Begründung steht im Kapitel „Sicherheitsmodell“ des Handbuchs, und wie die Grenze getestet wird, in dessen Kapitel „Testsuite“.

    Drei weitere Rollen sind bewusst noch enger:

    pepsi-whitelist

    Bekommt SELECT, INSERT und DELETE auf pepsi.whitelist und sonst nichts, sodass ein Programm, das jeder lokale Benutzer ausführen darf (pepsi-whitelist(1), setuid installiert), weder die Nachrichtenwarteschlange noch die Statistiken noch die Signierschlüssel erreichen kann.

    pepsi-keydisc

    Die Schlüsselentdeckungsdienste (pepsi-keydisc(1)), die aus dem offenen Internet geholtes Schlüsselmaterial parsen und daher der wahrscheinlichste Prozess hier sind, in den eingebrochen wird. Das ist die engste Rolle der Installation: SELECT/INSERT/UPDATE/DELETE auf pepsi.peer_key (diesen Cache zu füllen ist ihre ganze Aufgabe, und die Konfliktregel muss einen Datensatz ersetzen können), SELECT/INSERT/UPDATE auf pepsi.key_request, EXECUTE auf den keydisc_*-Funktionen und den beiden crypto_*-Helpern, die sie aufrufen — und auf pepsi.workqueue SELECT plus ein spaltenweises UPDATE (status, timeout).

    Diese beiden Spalten sind der interessante Teil. Sie reichen genau aus, um eine an einer Adresse geparkte Nachricht von paused zurück auf pending zu bewegen, was keydisc_resolve und keydisc_sweep tun (einfache SECURITY INVOKER-Funktionen, sodass die Reichweite ausdrücklich gewährt statt geerbt werden muss). Mit einer Berechtigung auf Tabellenebene könnte dieses Konto die Empfänger oder den Nachrichtentext einer Nachricht umschreiben; mit diesen beiden Spalten kann es eine Nachricht nur aufwecken. Es hat überhaupt keinen Zugriff auf pepsi.crypto_identity.

    pepsi-crypto

    Das Konto, das das private Ende-zu-Ende-Schlüsselmaterial verwahrt. Es bekommt die gewöhnlichen Pipeline-Berechtigungen über das Schema hinweg plus die Spalte pepsi.crypto_identity.private_wrapped — und es ist die einzige Rolle, die sie bekommt.

    Um diese letzte Spalte geht es bei der ganzen Übung. Unmittelbar nach den pauschalen Berechtigungen entzieht pepsi-setup das SELECT/INSERT/UPDATE auf Tabellenebene für pepsi.crypto_identity jeder gewöhnlichen Dienstrolle — pepsi (dem Dispatcher und jedem Stage-Worker), pepsi-ingress, pepsi-httpd und pepsi-telemetry — und gewährt dieselben drei Spalte für Spalte für jede Spalte außer private_wrapped zurück. So können diese Rollen die öffentliche Hälfte einer Identität lesen, schreiben und veröffentlichen, und die Kompromittierung einer unbeteiligten Stage liefert nicht mehr, selbst mit vollem Datenbankzugriff unter dieser Rolle. (DELETE hat in PostgreSQL keine Spaltengranularität und bleibt ganz: Eine Stage, die einen Identitätsdatensatz löschen kann, kann den Dienst verweigern, aber sie kann immer noch keinen Schlüssel lesen.) Die Spaltenliste wird aus information_schema zurückgelesen statt fest verdrahtet, sodass eine später hinzugefügte Spalte automatisch abgedeckt ist und die Berechtigung gegenüber dem Schema nicht veralten kann. Wie alles andere in diesem Schritt ist es idempotent und wird bewusst bei jedem Lauf erneut angewandt, weil die pauschalen Berechtigungen das Tabellen-Privileg jedes Mal wieder hinzufügen.

    Die verpackte Spalte ist nur die halbe Verwahrung; der Schlüssel, der sie öffnet, liegt in einem secrets.d-Fragment (unten). Beachten Sie außerdem, dass die Peer-Authentifizierung von PostgreSQL sich nach der effektiven uid richtet, nicht nach der gid — sodass ein Programm, das diese Rolle sein muss, dieses Konto sein muss, was pepsi-keys(1) um jeden Datenbankaufruf herum arrangiert. Siehe pepsi-keys(1).

  7. Erzeugt Signierschlüssel. Für jede Domain, für die Pepsi autoritativ ist — die Vereinigung von [pepsi-ingress] ACCEPTED_DOMAINS, den Domains des SERVER_NAME / POSTMASTER jeder Stage, einer ausdrücklichen SIGNING_DOMAIN, der [pepsi-srs] SRS_DOMAIN einer SRS-Stage, dem festen RESPONSE_FROM einer Selbstbedienungs-Stage und der [pepsi] ARC_DOMAIN, falls gesetzt — erstellt es einen privaten RSA-2048- und einen Ed25519-DKIM-Schlüssel unter KEY_DIR, falls sie nicht bereits existieren. Bestehende Schlüssel werden nie überschrieben, und Schlüsseldateien werden mit Modus 0600 in domainweisen Verzeichnissen erstellt, die mit Modus 0700 erstellt werden.

  8. Gibt DNS-Einträge aus. Es schreibt auf die Standardausgabe, im BIND-Zonendateiformat, die für jede Domain zu veröffentlichenden Einträge: die öffentlichen DKIM-Schlüssel (<selector>._domainkey für RSA und <selector>-ed25519._domainkey für Ed25519), eine SPF-Richtlinie (v=spf1 …), gebaut aus den PUBLIC_IP-Adressen jeder Relay-Stage (vereinigt; siehe unten), eine DMARC-Richtlinie (_dmarc.<domain> TXT — siehe unten) und einen MTA-STS-Eintrag (_mta-sts.<domain> TXT, sofern nicht MTA_STS_MODE = none), damit andere Absender für unsere eingehende Post validiertes TLS verwenden. Die MTA-STS-Richtliniendatei selbst wird von pepsi-httpd(1) über HTTPS unter https://mta-sts.<domain>/.well-known/mta-sts.txt angeboten (ihre mx-Menge kommt aus [pepsi] MTA_STS_MX, mit Rückfall auf das [pepsi-ingress] HOSTNAME), pepsi-setup gibt daher nur den _mta-sts-TXT-Eintrag aus — dessen id aus der eigenen Richtlinie dieser Domain abgeleitet ist, sodass zwei Domains mit verschiedenen mx-Mengen verschiedene ids bewerben — sowie eine Erinnerung, mta-sts.<domain> auf den Server zu richten. Anders als jeder andere Eintrag hier wird der MTA-STS-Eintrag nur für die [pepsi-ingress] ACCEPTED_DOMAINS ausgegeben. DKIM, SPF und DMARC authentifizieren eine Identität, als die dieser Rechner sendet, sie decken daher die weitere Menge oben ab; MTA-STS ist ein Versprechen über eingehende Post, und nur eine angenommene Domain hat ein eingehaltenes — pepsi-httpd(1) antwortet allein für diese Hosts auf /.well-known/mta-sts.txt, und das Zertifikat (und jede Site des Front-Servers) wird allein für diese Namen beschafft. Eine Domain, die nur eine Sendeidentität ist — ein Relay-SERVER_NAME, eine ausdrückliche SIGNING_DOMAIN, die [pepsi-srs] SRS_DOMAIN —, die aber dennoch einen veröffentlichten _mta-sts-TXT-Eintrag hat, erhält stattdessen einen ; DELETE:-Kommentar: Was er bewirbt, ist eine Richtlinie, die keine Komponente anbietet, die Anfrage fällt also auf das durch, was sonst auf dieser Adresse antwortet. Ist [pepsi-tlsrpt] RUA gesetzt, wird außerdem ein TLSRPT-Eintrag ausgegeben (_smtp._tls.<domain> TXT, v=TLSRPTv1; rua=…), damit andere Absender ihre TLS-Ergebnisse zu unseren Domains an die beworbene Adresse melden (siehe pepsi-tlsrpt(1)). Lange RSA-Einträge werden automatisch in mehrere Zeichenketten aufgeteilt. Schließlich schlägt es für jeden TLS-terminierenden Ingress-Listener einen DANE/TLSA-Eintrag (RFC 7672) unter dem MX-Hostnamen vor (_<port>._tcp.<HOSTNAME> IN TLSA 3 1 1 <hash>), wobei die Zuordnungsdaten der SHA-256 des SubjectPublicKeyInfo des ausgelieferten Zertifikats sind — die Form 3 1 1 (DANE-EE / SPKI / SHA-256), sodass der Eintrag Zertifikatserneuerungen übersteht, die dasselbe Schlüsselpaar wiederverwenden. Veröffentlichen Sie diese nur in einer DNSSEC-signierten Zone; der Eintrag für Port 25 ist der, der die Zustellung zwischen MTAs authentifiziert (Submission-Ports werden als Hinweis gekennzeichnet, da Absender dort das PKIX-Zertifikat verwenden). Der Vollständigkeit halber werden entsprechende 3 1 1-TLSA-Einträge auch für die HTTPS-Listener von pepsi-httpd(1) ausgegeben (je SNI-Host, dazu das Rückfallzertifikat unter HOSTNAME), diese sind aber als OPTIONAL gekennzeichnet: HTTPS-Clients (Browser, Abholer von MTA-STS-Richtlinien) führen keine DANE-Validierung durch, die Einträge können also gefahrlos entfallen und sind nur für einen Administrator gedacht, der das Webzertifikat anpinnen will.

    Zwei weitere Blöcke betreffen die Veröffentlichung von Ende-zu-Ende-Schlüsseln (siehe pepsi-keys(1)). Erstens für jede bediente Domain, deren openpgpkey.<domain>-Host nicht bereits auflöst, eine Erinnerung, dafür einen A/AAAA-Eintrag zu veröffentlichen: Die advanced-Methode des Web Key Directory — die, die jeder aktuelle Client zuerst versucht — wird von diesem Namen abgeholt, er muss also auf den pepsi-httpd(1)-Host zeigen. Eine Domain, die bereits Schlüssel veröffentlicht, wird in der Ausgabe gekennzeichnet und im Journal beanstandet, denn für sie schlägt die erweiterte Abfrage heute fehl, statt bloß unkonfiguriert zu sein. (Die direct-Methode auf dem Apex funktioniert ohne ihn, sodass dies eine Verschlechterung ist, kein Ausfall.) Zweitens ein OPENPGPKEY- (RFC 7929) oder SMIMEA-Eintrag (RFC 8162) für jede veröffentlichte, aktive Identität im Schlüsselspeicher, unter dem gehashten Eigentümernamen des RFC (SHA-256 des lokalen Teils auf 28 Oktette gekürzt, hexadezimal — nicht der Web-Key-Directory-Hash, der z-base-32-SHA-1 des kleingeschriebenen lokalen Teils ist). Diese werden nicht gegen Live-DNS verglichen: Jeder ist ein paar hundert Bytes, dessen Eigentümername ein Hash je Identität ist, sodass Sondieren eine Abfrage je Benutzer für Einträge kostete, die der Operator geschlossen einfügt. Die Auflistung endet nach zwanzig Identitäten; verwenden Sie pepsi-keys dns <address> für eine bestimmte. Veröffentlichen Sie Schlüsseleinträge nur in einer DNSSEC-signierten Zone — in einer unsignierten ist es ein Schlüssel von wem auch immer für die Zone antworten kann.

    Ein letzter Block betrifft die Mail-Autokonfiguration. Ist [pepsi-autoconfig] eingeschaltet, wird jeder autoconfig.<domain>-Host einer bedienten Domain, der noch nicht auflöst, mit dem Hinweis aufgeführt, ihn auf den pepsi-httpd(1)-Host zu richten. Anders als beim Web-Key-Directory-Hinweis oben kommt das eher einem Totalausfall gleich als einer Verschlechterung: Ein Client versucht zuerst https://autoconfig.<domain>/mail/config-v1.1.xml, und die /.well-known/-Form am Apex — die keinen neuen Eintrag benötigt — ist im Entwurf optional, sodass ein Client, der sie nicht versucht, schlicht nichts findet.

    Der SPF-Eintrag wird aus PUBLIC_IP gebaut, das eine stage-weise Option ist, die aus jeder Relay-Stage gelesen wird — erkannt an ihrem PROGRAM (pepsi-stage-relay-to-internet(1) oder pepsi-stage-relay-to-smarthost(1)), niemals am Abschnittsnamen — und vereinigt. Eine Installation kann somit mehrere Relay-Stages haben, jede mit ihrem eigenen PUBLIC_IP (eine pepsi-stage-relay-to-internet-Stage listet die eigenen Sende-IPs dieses Hosts auf; eine pepsi-stage-relay-to-smarthost-Stage listet die Egress-IPs des Smarthosts auf, da Mail von dort aus ins Internet geht). Wenn eine Relay-Stage existiert, aber keine PUBLIC_IP setzt, ist der Eintrag ein bloßes v=spf1 -all — was allen Hosts verbietet, als Ihre Domains zu senden, und Ihre eigene ausgehende Mail bei SPF durchfallen lässt — und pepsi-setup protokolliert eine Warnung; eine reine Empfangs-Installation (keine Relay-Stage) wird nicht gewarnt. Der vereinigte Eintrag wird für jede bediente Domain identisch vorgeschlagen: korrekt, aber weit gefasst. In besonderen Konstellationen, in denen verschiedene Domains von verschiedenen Hosts senden, ist ein von Hand geschriebener domainspezifischer SPF-Eintrag, der nur die eigenen Sende-IPs jener Domain auflistet, enger und dennoch korrekt; pepsi-setup berechnet diese Gruppierung nicht automatisch und gibt einen entsprechenden Hinweis neben den vorgeschlagenen Einträgen aus.

    Ein SPF-Fall wird in der Zonenausgabe eigens benannt, statt dort bloß einen Vorschlag zu erhalten: eine Domain, die bereits zwei v=spf1-Einträge veröffentlicht. RFC 7208 §4.5 macht das zu einem dauerhaften Fehler — es gilt keine SPF-Richtlinie, statt dass der erste Eintrag gewinnt — und die Abhilfe ist, sie zusammenzuführen, sodass der vorgeschlagene Eintrag mit einem Hinweis ausgegeben wird, dass ihn hinzuzufügen, ohne die anderen zu entfernen, nichts ändert. Ein übriggebliebenes v=spf1 include:<old provider> ist das Häufigste, was eine MTA-Migration hinterlässt.

    Der DMARC-Eintrag ist der eine, den pepsi-setup nicht ableiten kann: Welche Richtlinie eine Domain will, ist eine Operatorentscheidung, keine Folge der Konfiguration. Dieser Block handelt daher davon, dass der Eintrag brauchbar ist, und er verhält sich je nach dem, was bereits veröffentlicht ist, unterschiedlich:

    • Nichts veröffentlicht. v=DMARC1; p=none wird vorgeschlagen, mit einem Kommentar, der erklärt, dass es nur überwacht und auf quarantine oder reject verschärft werden sollte, und dass rua=mailto:<address> das ist, was die Berichte eintreffen lässt, die Ihnen sagen, ob das Verschärfen sicher ist. (Pepsi verarbeitet keine eingehenden DMARC-Sammelberichte; senden Sie sie irgendwohin, wo das geschieht.)

    • Ein gültiger Eintrag. Nichts wird ausgegeben, genau wie bei den anderen Einträgen.

    • Ein Eintrag, den Empfänger ignorieren würden. Der Grund wird als Kommentar ausgegeben und als Warnung protokolliert, und es wird kein Ersatzwert angeboten. Das ist Absicht: Ein Eintrag, der nicht parst, ist immer noch eine Absichtserklärung, und ein fehlerhaftes p=reject muss dort repariert werden, wo es steht, statt durch das p=none ersetzt zu werden, das dieses Werkzeug sonst vorschlüge — einen Tippfehler zu beheben sollte die Richtlinie einer Domain nicht stillschweigend herabstufen.

    Die Gültigkeit wird streng beurteilt, Tag für Tag, gegen RFC 7489 §6.4 statt durch Suche nach Teilzeichenketten, denn ein DMARC-Eintrag scheitert stillschweigend: Nichts bounct, kein Empfänger beschwert sich, und die Domain hört einfach auf, geschützt zu sein, während alle glauben, sie sei es. Insbesondere ist ein einzelnes fehlendes ; — etwa … p=reject; aspf=s adkim=s — vollkommen gute generische Tag-Listen-Syntax (RFC 6376 §3.2 erlaubt Leerzeichen und = innerhalb eines Tag-Werts), sodass ein loser Leser das Tag aspf mit dem Wert s adkim=s sieht und es akzeptiert; nur die DMARC-spezifische Wertegrammatik lehnt es ab. Wo der beanstandete Wert etwas enthält, das wie das nächste Tag aussieht, sagt die Diagnose das beim Namen (tags are separated by ';', and there is none before 'adkim='). Die anderen gemeldeten Dinge sind ein zweiter DMARC-Eintrag unter demselben Namen (RFC 7489 §6.6.3: Empfänger verwerfen die ganze Menge), ein wiederholtes Tag (RFC 6376 §3.2, wo undefiniert ist, welcher Wert gewinnt), ein fehlendes p=-Tag und eine rua=/ruf=-Adresse ohne ihr mailto:-Schema. Alles, was pepsi-setup gültig nennt, wird in der Testsuite gegen genau den Parser gegengeprüft, den pepsi-ingress(1) auf eingehende Mail anwendet, sodass ein hier gesegneter Eintrag keiner sein kann, den ein Empfänger wegwirft; die obigen Prüfungen sind bewusst strenger als jener Parser, denn ein Eintrag kann parsen und dennoch nicht die Richtlinie sein, die sein Autor veröffentlicht hat.

    Bevor es jeden TXT-Eintrag (DKIM, SPF, DMARC, MTA-STS, TLSRPT) vorschlägt, fragt pepsi-setup zunächst Live-DNS ab (nach bestem Bemühen): Ein Eintrag, der bereits mit dem korrekten Wert veröffentlicht ist, trägt nichts zur Ausgabe bei — nicht einmal seine domainweise Abschnittsüberschrift — sodass nur die Einträge ausgegeben werden, die wirklich (neu) veröffentlicht werden müssen. Die mta-sts.<domain>-Erinnerung, einen A/AAAA-(oder CNAME-)Eintrag zu veröffentlichen, wird ebenfalls nur ausgegeben, wenn dieser Host nicht bereits auflöst, und der DANE/TLSA-Block wird nur ausgegeben, wenn ein TLS-terminierender Ingress-Listener existiert. Wenn nichts geändert werden muss, wird der ganze Zonen-Dump unterdrückt und stattdessen eine einzelne setup: DNS records checked and they are OK-Zeile protokolliert, sodass ein erneuter Lauf über eine bereits konfigurierte Zone still ist. Die Probe ist nicht fatal — wenn DNS unerreichbar ist (oder kein Resolver gebaut werden kann), wird jeder Eintrag als Änderung behandelt und ausgegeben. Der DMARC-Block ist in dieser letzten Hinsicht die Ausnahme: Ohne Antwort vom DNS gibt es nichts zu vergleichen und keinen lokalen Wert, auf den zurückzufallen wäre, sodass er still bleibt, statt einer womöglich bereits korrekten Domain zu sagen, sie solle ein p=none veröffentlichen. (Verwenden Sie den check-Unterbefehl zur Live-Überprüfung der veröffentlichten TXT-Einträge.)

    „Bereits mit dem korrekten Wert veröffentlicht“ heißt korrekt auf jedem autoritativen Nameserver der Zone, nicht nur in der Antwort des System-Resolvers. Für jeden TXT-Eintrag ermittelt pepsi-setup außerdem die NS-Menge der Zone und fragt jeden Server direkt, ohne Rekursion: Ein Secondary, der noch einen alten Schlüssel ausliefert, ein delegierter Server, der die Zone nicht mehr bedient (eine lahme Delegation), oder einer, der gar nicht antwortet, lässt Empfänger den richtigen Eintrag nur zeitweise sehen; der Eintrag wird daher mit einer ; NOTE:-Zeile ausgegeben, die jeden abweichenden Server nennt (und eine Warnung wird geloggt). Eine falsche Antwort des Resolvers, der jeder autoritative Server widerspricht, wird als veralteter Cache markiert. Wenn kein autoritativer Server erreichbar ist — ein Netz, das nur den lokalen Resolver auf Port 53 hinauslässt —, wird einmal eine Warnung geloggt, und wie bisher entscheidet allein die Antwort des Resolvers.

    Ein DKIM-Selektor-Eintrag wird so beurteilt, wie ein Verifizierer ihn liest (RFC 6376 §3.6.1), nicht allein nach seinem p=: genau ein Schlüsseleintrag unter dem Namen, v= (falls vorhanden) zuerst und DKIM1, ein k=, das den Schlüsseltyp nennt (ein Ed25519-Schlüssel ohne k=-Tag scheitert überall, da das Tag standardmäßig rsa ist), keine h=/s=-Einschränkung, die sha256/email ausschließt, kein t=y (Testmodus, in dem eine Signatur nichts zählt) und ein p= gleich dem lokalen Schlüssel. Nur die Selektoren, mit denen [pepsi] DKIM_ALGORITHMS signiert, werden ausgegeben und geprüft, dazu derjenige, den das ARC-Siegel an der ARC_DOMAIN braucht. Neben dem Ed25519-Eintrag — und als Logzeile, wenn jeder Eintrag bereits korrekt ist — vermerkt pepsi-setup, dass Gmail, Microsoft 365 und Yahoo keine Ed25519-Signaturen verifizieren und dass Googles DMARC-Aggregatberichte sie als fail führen: erwartet und harmlos, da die RSA-Signatur DMARCs ausgerichtetes Bestehen liefert, und mit DKIM_ALGORITHMS = rsa abstellbar.

    In derselben Phase prüft pepsi-setup außerdem das Reverse DNS (PTR) jeder PUBLIC_IP einer pepsi-stage-relay-to-internet-Stage — der eigenen Egress-Adressen dieses Hosts (eine PUBLIC_IP von pepsi-stage-relay-to-smarthost ist die des Smarthosts und wird daher übersprungen). Jede Adresse wird gegen den Namen beurteilt, den die besitzende Stage ankündigt, ihr SERVER_NAME (das auf das Ingress-HOSTNAME zurückfällt, wenn eine Stage keines setzt), denn das ist das Paar, das ein Empfänger vergleicht. Eine PUBLIC_IP ist nur dann korrekt, wenn ihr PTR existiert, vorwärtsbestätigt und genau diesen Host benennt; jedes andere Ergebnis ist eine Warnung:

    • kein PTR-Eintrag — ein starkes Spam-Signal bei vielen Empfängern;

    • ein PTR, der nicht vorwärtsbestätigt ist — der PTR-Hostname löst nicht (A/AAAA) auf dieselbe IP zurück auf, sodass die Rundlaufprüfung (forward-confirmed reverse DNS, FCrDNS), die viele MTAs anwenden, fehlschlägt und sie die IP behandeln, als hätte sie überhaupt keinen PTR;

    • ein generischer / dynamisch zugewiesen wirkender PTR — ein Name, der die IP einbettet oder ein Token aus einem Endkunden-Pool trägt (dynamic, dsl, pool …), was Empfänger oft bestrafen;

    • ein PTR, der einen anderen Host benennt als der ``EHLO``-Name — der Eintrag ist vollkommen wohlgeformt und vorwärtsbestätigt, er benennt nur einen anderen Host. Eine große Familie von Empfängern verweigert die Sitzung rundweg mit HELO host does not match rDNS. Das greift auch dann, wenn der ``PTR``-Name eine Ihrer eigenen ACCEPTED_DOMAINS ist: Eine Maschine, die auf mehrere Namen hört (etwa example.org im EHLO angekündigt, während ihre Adresse rückwärts auf example.net auflöst), besteht hier jede andere Prüfung und bekommt ihre Mail dennoch abgewiesen;

    • ein PTR, der überhaupt nicht nachgeschlagen werden konnte — eine nicht delegierte Reverse-Zone oder unerreichbares DNS. Die Korrektheit ließ sich nicht feststellen, und eine Adresse ohne brauchbaren PTR wird von vielen Empfängern abgewiesen oder als Müll behandelt, sodass dies gemeldet statt stillschweigend übergangen wird.

    Jede Warnung trägt eine konkrete Abhilfe. Weil das Reverse DNS einer PUBLIC_IP in der Zone des IP-Eigentümers liegt (in-addr.arpa / ip6.arpa), besteht die übliche Abhilfe darin, Ihren ISP oder Hoster zu bitten, den PTR auf den angekündigten Namen zu setzen; wenn Sie die Reverse-Zone selbst betreiben, gibt die Fehlender-PTR-Meldung den genauen … IN PTR …-Eintrag zum Veröffentlichen aus. Bei einer Namensabweichung, wo der PTR bereits eine Ihrer eigenen Domains ist, bietet die Meldung auch die andere Richtung an — den PTR-Namen als Identität dieses Hosts zu übernehmen ([pepsi-ingress] HOSTNAME und das SERVER_NAME jeder Stage, wobei MX-Eintrag und TLS-Zertifikat folgen) —, denn diese Abhilfe braucht niemandes Mitwirkung. Die beiden Namen müssen einen Host bezeichnen; sich eine Domain zu teilen genügt nicht. Die Hostnamen-Vorgabe des Assistenten stammt aus derselben PTR-Abfrage (siehe –wizard unten), sodass eine im Interview erzeugte Konfiguration von vornherein mit dem Reverse DNS übereinstimmt.

    DNS, wie das Internet es sieht. Jede obige Prüfung erfolgt von diesem Host aus, und das ist der eine Ort, an dem eine aus dem eigenen Netz bediente Zone immer gesund aussieht: Hinter NAT wird eine Anfrage von innen nach einer Reverse-Zone, deren Nameserver genau diese Maschine ist, vom LAN, vom Router oder vom Host selbst beantwortet, während das Internet an einem Router in einen Timeout läuft, der Port 25 weiterleitet, aber nicht Port 53 — oder einen Nameserver erreicht, der eine kleinere Zone bedient, als sein Elternteil delegiert, wofür Resolver, die ihre Anfragen minimieren (RFC 9156), REFUSED erhalten. Empfänger stellen dann jede Nachricht mit cannot find your reverse hostname zurück, und die lokale Prüfung sagt, der PTR sei korrekt.

    Deshalb fragt pepsi-setup erneut über die öffentlichen Resolver, die [pepsi] PUBLIC_RESOLVERS nennt (standardmäßig Google, Cloudflare und Quad9, jeweils über IPv4 und IPv6; siehe pepsi.conf(5)): den PTR jeder PUBLIC_IP, vorwärts bestätigt über denselben Resolver; die MX-Menge jeder Domain und die TXT-Einträge, die der Unterbefehl check prüft; und die Adressen des Ingress-HOSTNAME. Alle werden gefragt, weil sie sich unterscheiden — in der Adressfamilie, über die sie einen Nameserver erreichen, und darin, wie sie eine Delegation abschreiten —, und eine Zone, die nur über IPv6 erreichbar oder nur für einen minimierenden Resolver lahm ist, scheitert bei einigen von ihnen und bei anderen nicht. Ein Empfänger verwendet ebenfalls einen davon. Jeder Resolver, der einen Namen nicht auflösen kann, keinen Eintrag findet oder eine andere Antwort sieht als dieser Host (Split-Horizon-DNS), ist eine Warnung, die den Resolver nennt und — sofern er einen sendet — seinen erweiterten Fehler nach RFC 8914 (No Reachable Authority: At delegation …). Lösen sich die Nameserver der Zone zu eigenen oder privaten Adressen dieses Hosts auf, sagt die Warnung das und nennt die üblichen Ursachen: eine Portweiterleitung, die für UDP- oder TCP-Port 53 fehlt oder deaktiviert ist, eine IPv6-Firewallregel oder eine bediente Zone, die nicht die delegierte ist. Der Unterbefehl check meldet diese als [UNREACHABLE] (ein korrekter Eintrag, den das Internet nicht lesen kann) und führt die PTR-Urteile in einer eigenen Gruppe reverse DNS auf.

    Resolver, die von diesem Host aus nicht erreichbar sind, werden stillschweigend verworfen (ein Host ohne IPv6-Konnektivität verliert die IPv6-Resolver); ist keiner erreichbar, wird einmal eine Warnung protokolliert und nur die lokale Sicht geprüft. PUBLIC_RESOLVERS = none schaltet diese Prüfung ab.

    MTA-STS-Gegenprüfungen. Alles Übrige, was pepsi-setup über MTA-STS prüft, ist konstruktionsbedingt in sich stimmig: der _mta-sts-TXT-Eintrag trägt eine id, die aus der Richtlinie abgeleitet ist, und die Richtlinie ist aus der Konfiguration abgeleitet, ein Vergleich kann also nur gelingen. Zwei Dinge sind nicht aus der Konfiguration abgeleitet, und unter MTA_STS_MODE = enforce stoppt jedes davon, wenn es falsch ist, stillschweigend die gesamte eingehende Post für die Domain. Beide werden bei jedem pepsi-setup run geprüft und vom Unterbefehl check sowie von der Webkonsole gemeldet; wie die PTR-Befunde sind sie Warnungen und lassen den Lauf nie scheitern.

    • Die ``mx``-Menge der Richtlinie gegen die lebenden MX-Einträge. Eine Richtlinie ist ein Versprechen, dass Absender sich nur mit den von ihr genannten Hosts verbinden dürfen. Ein Absender löst den MX der Domain auf, findet einen Host, den die Richtlinie nicht erlaubt, und weigert sich zuzustellen – bei jedem konformen Absender gleichzeitig, ohne Symptom auf dieser Seite außer Post, die nie ankommt. Das ist der Fehlschlag, den der MTA_STS_MX-Rückfall einlädt, denn HOSTNAME ist der EHLO-Begrüßungsname und muss kein Name sein, auf den irgendein MX-Eintrag zeigt. Die Warnung benennt die Hosts auf jeder Seite und gibt die einzelne MTA_STS_MX-Zeile aus, die sie in Übereinstimmung bringen würde, je Domain qualifiziert, wenn die bedienten Domains verschiedene MX-Hosts haben, dazu die Alternative, stattdessen den MX-Eintrag zu ändern, und den Rat, bis zur Übereinstimmung auf MTA_STS_MODE = testing zurückzufallen. Ebenfalls hier gemeldet: eine Domain ohne MX-Eintrag, ein Null-MX nach RFC 7505 auf einer Domain, für die wir Post annehmen, ein MX-Ziel, das ein CNAME ist (von RFC 5321 §5.1 verboten, und Absender dürfen es ablehnen), ein Richtlinieneintrag, der auf keinen lebenden MX-Host passt (harmlos, weitet aber, womit Absender sich verbinden werden), und ein DOMAIN:HOST-Eintrag, der eine Domain benennt, die nicht in ACCEPTED_DOMAINS steht – was für überhaupt keine Richtlinie gilt und genau so aussieht wie ein Tippfehler in der Option.

    • Ob die Richtlinie abgeholt werden kann. pepsi-setup fordert https://mta-sts.<domain>/.well-known/mta-sts.txt an und vergleicht das Zurückkommende mit der Richtlinie, die diese Konfiguration definiert – semantisch, Zeilenenden und Schlüsselreihenfolge sind also keine Unterschiede. Umleitungen werden nicht verfolgt, denn RFC 8461 §3.3 verbietet einem Absender, ihnen zu folgen, und eine Richtlinie, die nur hinter einer angeboten wird, ist eine Richtlinie, die kein Absender lesen kann. Ein korrekter TXT-Eintrag vor einer Richtlinie, die niemand abholen kann, ist nicht hypothetisch: der Server ist ein unerreichbares Socket, ein falsch konfigurierter vorgelagerter Server oder ein fehlendes Zertifikat davon entfernt, dass jeder Absender stattdessen ein 502 erhält, während jede Unit active bleibt und nichts protokolliert wird – und Absender, die eine Richtlinie schon zwischengespeichert haben, setzen bis zu max_age lang weiter die alte durch, der Fehlschlag begrenzt sich also nicht einmal selbst. Ein 5xx wird gemeldet, mit dem Socket des vorgelagerten Servers als dem, was zu prüfen ist.

      Wenn der veröffentlichte Name von diesem Rechner aus nicht erreichbar ist – er löst noch nicht auf, oder das Netz lässt den Rechner seine eigene öffentliche Adresse nicht erreichen –, wird die Anfrage über die Loopback-Schnittstelle gegen diese Maschine wiederholt, wobei der veröffentlichte Name in SNI und Host bleibt, sodass das Zertifikat weiterhin gegen den Namen geprüft wird, den ein Absender benutzen würde. Dieses Ergebnis wird als lokale Sondierung gekennzeichnet, denn es sagt, was ein Absender erhalten würde, sobald mta-sts.<domain> hierher auflöst; es ist der Grund, weshalb eine rein lokale Fehlkonfiguration auch auf einem Rechner gemeldet wird, dessen DNS noch nicht veröffentlicht ist.

    Die SRS-Domain kann ihre eigenen Bounces empfangen. Wenn eine Stage pepsi-stage-srs(1) ausführt, prüft pepsi-setup, dass [pepsi-srs] SRS_DOMAIN einen MX-Eintrag hat – oder andernfalls einen A/AAAA-Eintrag, den impliziten MX aus RFC 5321 §5.1. Eine SRS-Adresse ist ein Rückweg: das Umschreiben macht diesen Rechner zum Bounce-Ziel für Post, die er nicht geschrieben hat, und der HMAC in der Adresse existiert, damit pepsi-ingress(1) einen zurückkommenden Bounce dekodieren und an den ursprünglichen Absender weiterleiten kann. Eine Domain mit keinem der beiden Einträge beendet diese Rundreise im Schweigen – das Weiterleiten funktioniert, SPF besteht beim nächsten Hop, und jeder Bounce wird von dem MTA verworfen, der ihn zurückzusenden versuchte, dem ursprünglichen Absender wird also nie gesagt, dass seine Nachricht nicht ankam. Ein Null-MX nach RFC 7505 (MX 0 .) ist dieselbe Antwort, absichtlich ausgesprochen, und ein MX-Ziel, das ein CNAME ist, wird aus demselben Grund gemeldet wie überall sonst (RFC 5321 §5.1, RFC 2181 §10.3). Die Warnung gibt den zu veröffentlichenden Eintrag aus und benennt dabei einen Host, an den die angenommenen Domains schon Post routen, und bietet die zwei Alternativen: SRS_DOMAIN auf eine Domain richten, die hier schon Post empfängt, oder die Stage weglassen, wenn nichts nach außen weitergeleitet wird. Wie die Prüfungen oben ist sie eine Warnung und lässt den Lauf nie scheitern.

    Die Prüfung existiert, weil das Versäumnis aus jedem anderen Blickwinkel unsichtbar ist. Die SRS-Domain ist eine Sende*identität, sie tritt daher der Menge bei, die DKIM-Schlüssel sowie SPF- und DMARC-Ratschläge erhält; **pepsi-setup* schlägt für keine Domain einen MX-Eintrag vor, da dies die eigene Routingentscheidung des Betreibers ist. Ein Betreiber, der alles veröffentlicht, was ihm gesagt wird, endet daher mit zwei der drei Einträge, die die Domain braucht, und nirgends sagt etwas davon.

    Die Vorwärtsbestätigung fragt nur autoritatives DNS ab und ignoriert bewusst die lokale /etc/hosts-Datei — ein Mailhost führt dort häufig seinen eigenen Namen gegen 127.0.1.1 oder eine NAT-interne Adresse auf, was einen vollkommen vorwärtsbestätigten Namen sonst unbestätigt aussehen ließe. Diese Befunde sind Zustellbarkeitswarnungen, keine Fehler: Sie lassen den Lauf nie scheitern.

  9. Verifiziert das Zahlungs-Backend (optional). Wenn ein [pepsi-payments]-Abschnitt ein GNU-Taler-Händler-Backend konfiguriert, prüft pepsi-setup es über HTTP: GET /config muss ein taler-merchant-Backend identifizieren (damit die URL korrekt ist) und GET /private/orders?limit=1 muss 200 zurückgeben (damit das MERCHANT_ACCESS_TOKEN korrekt ist). Es stellt dann sicher, dass ein pepsi-resume-Webhook existiert, der an den /resume-Endpunkt von pepsi-httpd POSTet, wann immer eine Bestellung bezahlt wird — es erstellt ihn, falls nicht vorhanden, oder protokolliert, falls ein pepsi-resume-Webhook bereits existiert, eine Warnung, wenn seine Definition von der erwarteten abweicht (er wird nie stillschweigend überschrieben). Der Webhook zielt über HTTPS auf den kürzesten konfigurierten [pepsi-httpd-cert-*]-SNI-Host und authentifiziert sich mit [pepsi-httpd] RESUME_AUTHORIZATION_TOKEN. Wenn kein Händler-Backend konfiguriert ist, wird dieser Schritt vollständig übersprungen.

  10. Erinnert an Zugangsdaten, die außerhalb des Systems ablaufen. Wenn irgendein Smarthost-MTA AUTH = oauth verwendet, validiert pepsi-setup die entsprechenden [pepsi-helper-token-refresh-<name>]-Geheimnis-Abschnitte, die es lesen kann (es läuft als root), und gibt eine Erinnerung aus, dass diese Zugriffstokens aktuell gehalten werden müssen — zum Beispiel durch Aktivieren von pepsi-helper-token-refresh(1), das nicht Teil von pepsi.target ist. Verwendet einer AUTH = gssapi, erinnert es ebenso daran, dass der Kerberos-Credential-Cache außerhalb des Systems erneuert werden muss (ein Keytab plus k5start oder Cron) und für den Worker des Dispatchers lesbar sein muss, wobei es jeden Cache-Pfad, den es sehen kann, auf Plausibilität prüft. Beide Erinnerungen gehen in das Journal (Standardfehlerausgabe), nach der Zonenausgabe, sodass sie eine umgeleitete Zonendatei nie beschädigen können.

Das gesamte Verhalten wird durch eine Konfigurationsdatei im INI-Stil gesteuert (siehe pepsi.conf(5)). Dieselbe Konfigurationsdatei wird mit den anderen Pepsi-Werkzeugen geteilt.

85.1.39.1.4. Privilegien und Eigentümerschaft

pepsi-setup kann entweder direkt als der Datenbankeigentümer ausgeführt werden (zum Beispiel su pepsi-owner -c 'pepsi-setup … run') oder als root. Wenn es als root ausgeführt wird, verwaltet es zwei verschiedene Identitäten selbst, sodass die resultierenden Objekte den richtigen Konten gehören:

  • Datenbankobjekte werden als die pepsi-owner-Rolle erstellt. Vor jeder Datenbankarbeit (Schema-Installation, Rollen-Einrichtung, Einstellungsvalidierung, Zahlungs-Backend-Prüfung) nimmt pepsi-setup die effektive Identität des pepsi-owner-Benutzers an; die PostgreSQL-Peer-Authentifizierung verbindet sich dann als die gleichnamige Rolle, sodass das pepsi-Schema, seine Tabellen, Sequenzen und Funktionen pepsi-owner gehören. Der pepsi-owner-Benutzer/die -Rolle und die Datenbank selbst müssen bereits existieren (das Debian-Paket erstellt sie; andernfalls erstellen Sie sie von Hand). Nur die effektive uid ändert sich, sodass root danach wiedererlangt wird.

  • Schlüsselmaterial wird an das pepsi-Konto übergeben. Die domainweisen DKIM-Schlüssel werden wieder als root erzeugt (Modus 0600) und dann auf den pepsi-Benutzer chownt — das Dispatcher-Konto, das ausgehende Mail signiert — sodass die Signier-Stages sie lesen können. Wenn der pepsi-Benutzer nicht existiert, ist dies eine protokollierte No-Op.

Wenn pepsi-setup nicht als root ausgeführt wird, geschieht keiner der beiden Wechsel: Es arbeitet vollständig als der aufrufende Benutzer, der daher der Datenbankeigentümer sein und KEY_DIR lesen/schreiben können muss.

Bemerkung

Die ARC-Versiegelung (durchgeführt von pepsi-stage-arc(1) auf eingehender Mail) verwendet den DKIM-Schlüssel der [pepsi] ARC_DOMAIN wieder, sodass kein separater ARC-Schlüssel oder DNS-Eintrag erzeugt wird: ARC-Verifizierer holen den öffentlichen Schlüssel der Versiegelung aus demselben DKIM-Eintrag. Wenn ARC_DOMAIN gesetzt ist, nimmt pepsi-setup sie einfach unter die Schlüssel-/DNS-Domains auf.

85.1.39.1.5. Assistent

Für eine erste Installation ersetzt –wizard das Bearbeiten von Hand durch ein kurzes interaktives Interview und schreibt eine vollständige, bereits validierte Konfigurationsdatei.

Das Interview wird als Folge nummerierter Schritte dargestellt (jeder als Step X/Y-Banner mit einer einzeiligen Beschreibung, auf einem fähigen Terminal in Farbe — setzen Sie die Umgebungsvariable NO_COLOR, um sie zu deaktivieren), die zusammengehörige Fragen gruppieren: Server identity, Existing mail system, Local delivery, Submission authentication, Trust loopback, Forwarded mail, Transport security, Content filtering, Anti-spam paywall, Account self-service und End-to-end cryptography (dazu Expert options unter –expert). Welche Schritte erscheinen (und damit Y) ergibt sich aus der gewählten Richtung und daraus, ob ein lokales Dovecot erkannt wird. Das Kapitel Der Assistent des Handbuchs zeichnet die Pipeline, die jede Richtung erzeugt, und führt auf, was jede Frage entscheidet. Wenn stdin ein echtes Terminal ist, werden Eingabeaufforderungen mit den üblichen GNU-readline-Tastenbelegungen zeilenweise bearbeitet (Home/End, Ctrl-Left/Ctrl-Right, um Wörter zu überspringen, Ctrl-A/ Ctrl-E/Ctrl-K/Ctrl-U/Ctrl-W und Up/Down, um frühere Antworten zurückzurufen); ein weitergeleitetes (nicht-terminales) stdin — wie von der Testsuite und von Skripten verwendet — fällt auf einfache Zeilenlesevorgänge zurück. Jede Antwort wird im Moment ihrer Eingabe validiert (Hostnamen und Domains müssen voll qualifiziert sein, der Postmaster eine gültige Adresse, Sende-IPs echte IP-Literale, Ports numerisch, die Zahlungsfrist eine h/m/s-Dauer und so weiter), sodass ein Fehler an seiner eigenen Eingabeaufforderung gemeldet und an Ort und Stelle korrigiert wird statt erst bei der abschließenden Validierung der gesamten Konfiguration.

Es fragt zuerst die Richtung, die der Host bedient — inbound (Mail für unsere Domains aus dem Internet empfangen und sie lokal zustellen und/oder weiterleiten), outbound (die Submissions unserer eigenen Benutzer direkt ins Internet senden) oder both (der Standardwert; nach state.local_origin mit einer Routing-Stage aufteilen) —, was die SMTP-Listener (Port 25 für eingehend, 465/587 für ausgehend) und die erscheinenden Relay-Stages bestimmt. Es fragt dann nach dem Hostnamen, der/den akzeptierten Domain(s), der Postmaster-Adresse, der/den öffentlichen Sende-IP(s) und der Datenbank-Verbindungszeichenfolge und schlägt sinnvolle Standardwerte vor (das Elternteil des Hostnamens als Domain). Die Hostnamen-Vorgabe stammt aus dem Reverse DNS: Der Assistent ermittelt die öffentlichen Adressen dieses Hosts (dieselbe Ermittlung, die unten für die Sende-IPs beschrieben ist), schlägt ihre PTR-Einträge nach und bietet den ersten Namen an, der zur Adresse zurück vorwärtsbestätigt und nicht automatisch erzeugt aussieht. Nur wenn es keinen solchen Namen gibt, fällt es auf /etc/hostname zurück. Das ist Absicht — ein empfangender Mailserver vergleicht den im EHLO angekündigten Namen mit dem PTR der Adresse, von der die Sitzung kommt, und weist ab, wenn sie nicht übereinstimmen (HELO host does not match rDNS), während /etc/hostname ein rein lokales Etikett ist, das kein Empfänger je sieht. Auf einem Host, der auf mehrere Namen hört, weichen die beiden routinemäßig ab, und das Reverse DNS liegt in der Zone des IP-Eigentümers, ist also normalerweise die Hälfte, die sich nicht ändern lässt. Wenn die angebotene Vorgabe (die Antwort eines früheren Laufs oder /etc/hostname) dem PTR widerspricht, sagt der Assistent das und nennt beide, bevor er fragt. Die Vorgabe der öffentlichen Sende-IP(s) wird automatisch ermittelt und zur Bestätigung angeboten: die veröffentlichten A/AAAA-Einträge des Hostnamens, vereinigt mit den eigenen global routbaren Schnittstellenadressen des Hosts, und — nur wenn das keine öffentliche IPv4 findet (ein NAT-Host mit privater IPv4) — die vom lokalen UPnP-Gateway über upnpc (miniupnpc) gemeldete WAN-IPv4, sofern installiert. Es werden nur öffentliche Adressen vorgeschlagen: eine private/Loopback-/Link-Local-Adresse wird nie vorbelegt (hinter NAT ist der ermittelte Wert die öffentliche Egress-IP, nicht die LAN-Adresse). Der Operator bestätigt oder bearbeitet ihn, bevor irgendetwas geschrieben wird.

Auf dem eingehenden Pfad ist die nächste Frage, ob hinter diesem Host ein bestehendes Mailsystem sitzt — Microsoft Exchange oder Microsoft 365. Ein Ja macht Pepsi zu einem transparenten Gateway: Es wird der MX und reicht alles an den Mandanten-Endpunkt weiter, sodass es keine lokalen Postfächer gibt und die untenstehenden Fragen zur lokalen Zustellung übersprungen werden. Es fragt dann nach Host und SMTP-Port dieses Endpunkts (mit dem Hinweis, dass es der mandantenspezifische Endpunkt sein muss und nicht der öffentliche MX der Domain, der dieser Host ist und eine Schleife ergäbe) und nach der IP-Adressfamilie, über die er erreicht werden soll (any/ipv4/ipv6 — Exchange Online weist Mail von einer IPv6-Adresse ohne Reverse DNS zurück, ipv4 ist daher der Notausgang, wenn IPv6-Reverse-DNS nicht delegiert ist).

Andernfalls fragt es auf dem eingehenden Pfad, welche Lokale-Zustellung-Methode(n) zu verwenden ist/sind — Maildir (pepsi-stage-relay-to-maildir) und/oder LMTP zu einem MDA (pepsi-stage-relay-to-lmtp) — und, wenn Maildir aktiviert ist, ob benutzereigene ~/.forward-Dateien beachtet werden sollen (pepsi-stage-dot-forward; der erzeugte Abschnitt leitet nur an Adressen weiter, mit ausgeschaltetem ALLOW_PIPE / ALLOW_FILE).

Weiterhin auf dem eingehenden Pfad fragt es, ob dieser Host Mail für abwesende Empfänger beantworten soll (pepsi-stage-vacation, Standardwert nein). Ja zu antworten setzt lediglich die Stage in die Pipeline — nach der Alias-Expansion und nach den Spam-Schranken, sodass eine Notiz nie im Namen eines Alias oder in Antwort auf Mail gesendet wird, die die Schranken abgewiesen hätten. Niemand wird beantwortet, bevor Urlaubszeiträume existieren, und die sind gewöhnliche Konfiguration je Adresse statt einer Assistentenantwort: Ein Benutzer kann seine eigenen per E-Mail setzen, ein Operator mit pepsi-settings set <address> vacation VACATION_RANGES …, und einen Feiertag, den alle teilen, mit pepsi-config set --scope domain:<domain> stage-vacation VACATION_RANGES …. Der erzeugte Abschnitt lässt VACATION_RANGES daher ungesetzt (mit der Syntax in einem Kommentar) und richtet RESPONSE_STAGE auf den gemeinsamen Signier-Schwanz, sodass jede Notiz signiert und weitergeleitet wird. Auf einem Host ohne lokale Zustellung — einem reinen Weiterleiter oder einem Exchange-Vorbau — setzt es außerdem VACATION_TAG = none: Den Betreff zu markieren schriebe sonst einen Header um, der von der DKIM-Signatur des Autors und vom eigenen ARC-Siegel dieses Hosts abgedeckt ist, was der nächste Hop scheitern sähe. Siehe pepsi-stage-vacation(1).

Es fragt dann nach dem vorgelagerten Smarthost (optional, wenn die lokale Zustellung oder ein Exchange-System die bedienten Domains übernimmt, andernfalls erforderlich).

Zwei Fragen entscheiden dann, wie Mail diesen Host mit einer eigenen Signatur verlässt. Die erste betrifft auf diesem Host laufende Programme — cron, mail(1), logwatch, git send-email oder eine Webanwendung —, die andernfalls für jeden Empfänger außerhalb einer bedienten Domain mit 550 5.7.1 Relaying denied abgewiesen werden.

Der Assistent fragt nicht, ob der UNIX-Domain-Submission-Socket bedient werden soll, den /usr/sbin/sendmail verwendet. pepsi-ingress bedient ihn immer und leitet ihn aus [pepsi-sendmail] SOCKET ab, sodass kein Listener-Abschnitt geschrieben wird und es nichts gibt, was man falsch beantworten könnte. Der Kernel teilt pepsi-ingress mit, welches Konto den Socket geöffnet hat, sodass ein Aufrufer immer nur als er selbst senden kann: Der Login wird genau so durch USERNAME_MAP geführt, wie es ein SASL-Benutzername würde. Siehe pepsi-sendmail(1) und SOCKET = none, um es abzuschalten.

Was es sehr wohl fragt, und zwar nur auf einem Host, der beide Richtungen bedient (die Antwort wird zu MYNETWORKS am MX-Listener auf Port 25, den nur ein eingehender Host hat, und die Frage lohnt sich nur bei einem Host, der auch Submissions einliefert), als Ja/Nein-Frage mit Vorgabe nein, ist, ob zusätzlich dem Loopback zu vertrauen ist:

TRUST_LOOPBACK

Fügt MYNETWORKS = 127.0.0.0/8 ::1/128 zum Port-25-Listener hinzu (zusammengeführt mit allen über die Experten-Optionen gesetzten Netzen, nie doppelt). Dies vertraut einer Netzwerk-Position statt einem Benutzer, sodass jeder lokale Prozess — einschließlich einer kompromittierten Webanwendung — als beliebiger Absender senden kann; und es ist auch das, was eine Nachricht, die dieser Host an sich selbst weiterleitet (eine bediente Domain, deren öffentlicher MX dieser Host ist), als frische Submission wieder eintreten und in einer Schleife kreisen lässt. Sagen Sie nur für Software ja, die darauf besteht, SMTP mit Port 25 zu sprechen, und nicht auf den Socket gerichtet werden kann.

So oder so gelten die resultierenden Nachrichten als lokal erzeugt (state.local_origin) und werden daher vom ausgehenden Pfad DKIM-signiert.

Auf dem eingehenden Pfad fragt es, ob die von diesem Host weitergeleitete Mail DKIM-signiert werden soll (Standardwert: ja): ein Alias, der nach außen expandiert, ein ~/.forward, das auf einen anderen Anbieter zeigt, oder der gesamte reine Relay-Pfad. Diese Nachrichten verlassen den Host über das eingehende Ende, das die ausgehende [stage-dkim-sign] nie berührt, sodass sie ohne dies mit unserem SRS-Umschlag, aber mit dkim=none von uns beim nächsten Hop ankommen. Ein Ja erzeugt eine zweite Signier-Stage, [stage-dkim-sign-relay], zwischen der SRS-Umschreibung und dem Ziel, mit einem auf die primäre bediente Domain festgelegten SIGNING_DOMAIN. Diese Festlegung ist beabsichtigt: Das Signieren ist fail-closed, und die Domain des Autors gehört jemand anderem — die Signierdomain aus einem fremden From: abzuleiten würde jede weitergeleitete Nachricht mangels Schlüssel scheitern lassen. Die eigene Identität des Hosts — die ARC-Versiegelungsdomain ([pepsi] ARC_DOMAIN), jedes Relay-/Bounce-SERVER_NAME und das Rückfall-Listener-Zertifikat — ist durchgehend der konfigurierte Hostname, unterschieden von den akzeptierten Empfängerdomains (die SRS, MTA-STS und die TLS-Report-Adressen begrenzen).

Die Art, wie diese Listener ihre Ports binden, hängt vom Host ab. Wenn das System von systemd verwaltet wird (erkannt am Vorhandensein von /run/systemd/system), schreibt der Assistent socket-aktivierte Listener (SERVE = systemd mit einem FD_INDEX pro Listener), sodass die privilegierten Ports von .socket-Units gebunden und vom unprivilegierten Dienst geerbt werden; andernfalls fällt er auf direkte Bindungen zurück (SERVE = tcp mit BIND_TO / PORT). Die Ingress-Listener erhalten immer FD_INDEX 0 für Port 25, 1 für 465 und 2 für 587, passend zum mitgelieferten pepsi-ingress.socket, das alle drei auflistet, gleich welche Richtung der Host bedient. Bei Socket-Aktivierung müssen Sie die passenden .socket-Units installieren (ein pepsi-ingress.socket, das ListenStream=25, 465 und 587 in dieser Reihenfolge auflistet, und ein pepsi-httpd.socket für Port 443); der Assistent gibt nach dem Schreiben eine Erinnerung aus.

Zwei Transportsicherheitsfragen folgen. Auf dem eingehenden Pfad fragt es, ob eine MTA-STS-Richtlinie bereitgestellt werden soll (Standardwert ja): Wenn aktiviert, setzt es MTA_STS_MODE = enforce und fügt einen [pepsi-httpd-cert-*]-Abschnitt für den mta-sts.<domain>-Richtlinienhost jeder akzeptierten Domain hinzu (über HTTPS von pepsi-httpd bereitgestellt), dessen Zertifikat pepsi-setup wie jedes andere über certbot einrichtet — Sie müssen das DNS jedes mta-sts.<domain>-Namens auf den Server richten, damit die Richtlinie erreichbar ist. Nach den Hosts, die die Richtlinie zulässt, wird nicht gefragt: Sie werden aus den aktuellen MX-Einträgen der bedienten Domains gelesen und als [pepsi] MTA_STS_MX geschrieben (weggelassen, wenn noch kein MX-Eintrag existiert, sodass die Richtlinie auf HOSTNAME zurückfällt; siehe MTA-STS cross-checks oben). Es fragt dann, ob SMTP-TLS-Reports gesendet werden sollen (TLSRPT, RFC 8460; Standardwert ja), was den [pepsi-tlsrpt]-Abschnitt ausgibt.

Derselbe Schritt schließt mit der einen Frage, die überhaupt nicht diese Installation betrifft: ob anonyme Telemetrie zur Funktionsnutzung mit dem Pepsi-Projekt geteilt werden soll ([pepsi] SHARE_TELEMETRY, Standardwert nein). Sie ist Opt-in, die Eingabeaufforderung erklärt daher vor dem Fragen, was gesendet würde — eine zufällige 256-Bit-SYSTEM_ID und Zählungen darüber, welche Pepsi-Funktionen dieser Host genutzt hat, nie Adressen, Nachrichtendaten, Hostnamen oder IP-Adressen —, und wer sich mit der Eingabetaste durch das ganze Interview drückt, teilt somit nichts. Ein Nein deaktiviert den gesamten Pfad: Es wird keine Kennung erzeugt, das Setup startet den Daemon nie, und einer, den der Operator gestartet hat, wird in den Ruhezustand versetzt. Siehe pepsi-telemetry-client(1).

Die pepsi-httpd-Abschnitte werden immer geschrieben, was auch immer sonst abgelehnt wird: HTTPS auf Port 443 mit dem Host-Zertifikat, das die SMTP-Listener verwenden (das die MTA-STS-Richtlinie ausliefert, wenn diese an ist), und die administrative Konsole auf /run/pepsi/admin.sock für die Gruppe pepsi-admin. pepsi.target startet den Server und seinen Socket auf jedem Host, sodass eine Konfiguration ohne Listener ihn fehlschlagen und neu starten ließe.

Ein kurzes Funktionsmenü folgt, nur dort gefragt, wo es für die gewählte Richtung zutrifft: ob Mail nach erkannter Sprache blockiert werden soll (und, falls nicht, ob dennoch Bounce-Nachrichten lokalisiert werden sollen, was die Spracherkennung aktiviert). Wenn die Erkennung aktiviert ist, gibt es zuerst die vollständige Liste der unterstützten ISO-639-1-Codes aus und fragt, welche Sprachen der Detektor erkennen soll, wobei es * (der Standardwert) für jede vom Detektor unterstützte Sprache akzeptiert und jeden nicht unterstützten Code an Ort und Stelle ablehnt (statt erst bei der abschließenden Validierung). Nur eine erkannte Sprache kann dann erlaubt oder blockiert werden, sodass es, wenn die Blockierung an ist, als Nächstes nach einer einzigen kombinierten Sprachrichtlinie in einer +allow/-block-Syntax fragt — z. B. erlaubt +en +fr -ja -zh Englisch und Französisch, während es Japanisch und Chinesisch blockiert, und ein einzelnes -*-(oder +*-)Wildcard deckt jede andere erkannte Sprache ab (sodass +en +fr -* nur Englisch und Französisch erlaubt). Das Literal none kann aufgeführt werden, um das Schicksal nicht erkannter Mail zu entscheiden. Diese eine Antwort wird in die WHITELIST- und BLACKLIST-Optionen der Stage aufgeteilt. Es fragt dann, ob unbekannte Absender um Bestätigung per Antwort gebeten werden sollen (SECRETARY, pepsi-stage-secretary(1), Standardwert nein), und nach der GNU-Taler-Anti-Spam-Bezahlschranke (die auch die Whitelist der Korrespondenten einschaltet, sodass bekannte Kontakte die Zahlungsaufforderung überspringen). Wenn die Bezahlschranke aktiviert ist, fragt der Assistent zuerst nach der Händler-Backend-URL und verifiziert sie sofort über HTTP (GET /config muss ein taler-merchant-Backend identifizieren) und liest die vom Backend unterstützten Währungen zurück — der Preis muss in einer von ihnen angegeben werden, sodass die URL bekannt sein muss, bevor nach dem Preis gefragt wird. Es fragt dann nach dem Zugangs-Credential: entweder ein fertiges Zugriffstoken (erkannt an seinem secret-token:-Präfix und gegen das Backend verifiziert) oder das Instanz-Passwort, das der Assistent über POST /private/token gegen ein Zugriffstoken mit Geltungsbereich eintauscht (wobei er den Geltungsbereich all anfordert, sodass das Token auch den pepsi-resume-Webhook verwalten kann). Schließlich fragt es nach dem Preis pro Nachricht als leerzeichengetrennte Liste von Taler-Beträgen (z. B. EUR:1 CHF:1 KUDOS:10), gegen die Währungen des Backends validiert; jeder Betrag wird zu einer Wahlmöglichkeit im erzeugten v1-Order-ORDER_CHOICES, sodass der Zahler eine Währung wählen kann. Wenn sowohl die Bezahlschranke als auch Confirm-to-Send aus sind und der Host auch einen ausgehenden Pfad hat, fragt der Assistent stattdessen, ob lediglich eine Whitelist der Korrespondenten aus ausgehender Mail gelernt werden soll.

Auf dem ausgehenden Pfad stellt ein Selbstbedienungs-Schritt danach bis zu zwei unabhängige Ja/Nein-Fragen, beide mit dem Standardwert nein: ob Kontoinhaber ihre eigenen Einstellungen je Adresse per E-Mail bearbeiten dürfen (pepsi-stage-edit-settings(1)) — nur auf einem Host gefragt, der beide Richtungen bedient, denn jede Stage, die ein Kontoinhaber bearbeiten darf, ist eine eingehende — und ob sie ihre eigene GNU-Taler-Wallet per E-Mail bedienen dürfen — Guthaben, Aufladung und Peer-to-Peer-Zahlungen, bedient von demselben pepsi-stage-auto-pay(1), das eingehende Zahlungsforderungen bezahlt.

Der letzte Schritt, gestellt gleich welche Richtung gewählt wurde, ist die Ende-zu-Ende-Kryptografie (Standardwert nein): ob dieses Gateway Mail selbst ver- und entschlüsseln soll (OpenPGP und S/MIME), sodass Benutzer kein Client-Plugin brauchen. Ein Ja stellt pepsi-stage-encrypt(1) und pepsi-stage-decrypt(1) in die Pipeline; nichts wird verschlüsselt, bevor der Schlüssel eines Empfängers bekannt ist, und Schlüssel kommen aus der Suche (pepsi-keydisc(1)), aus pepsi-keys(1) oder aus der Mail, die Korrespondenten uns senden. Auf dem eingehenden Pfad fragt es danach, ob die Schlüssel der Korrespondenten aus dieser Mail gelernt werden sollen (Autocrypt, Standardwert ja), was pepsi-stage-autocrypt-learn(1) hinzufügt, und ob das, was das Gateway entschlüsselt hat, vor dem Ablegen erneut für den eigenen Mail-Client-Schlüssel des Benutzers verschlüsselt werden soll (REENCRYPT, Standardwert ja), was pepsi-stage-reencrypt(1) vor der lokalen Zustellung hinzufügt. Auf dem ausgehenden Pfad fragt es, ob die automatische Verschlüsselung im pEp-Stil aktiviert werden soll (PEP, Standardwert ja): Jeder Absender an einer bedienten Domain erhält bei seiner ersten Nachricht einen OpenPGP-Schlüssel, der in einem Autocrypt:-Header angekündigt wird, und Mail wird innerhalb der Verschlüsselung signiert. Es nennt die Kosten, bevor es fragt – die eifrige Schlüsselerzeugung legt für jeden, der Mail sendet, einen verpackten privaten Schlüssel in die Datenbank und seinen öffentlichen Schlüssel in das Web Key Directory, ob er Verschlüsselung jemals nutzt oder nicht – und schreibt die Antwort ausdrücklich, ENABLE_PEP = yes oder ENABLE_PEP = no, in [stage-encrypt] in pepsi.conf, wo sie wirkt (keine config.d-Datei setzt sie). Bei Zustimmung fragt es, ob der Schlüssel des Absenders zusätzlich als Datei angehängt werden soll (ATTACH_KEYS_AS_FILES, Standardwert nein), was nur geschrieben wird, wenn es gewählt wurde. Die Verschlüsselungs-Stage erhält immer RESPONSE_STAGE = dkim-sign, sodass die Benachrichtigungen über registrierte Schlüssel und die Antworten auf die E-Mail-Schlüsselbefehle wie jede andere ausgehende Mail signiert und weitergeleitet werden. Das Browser-Einrichtungsinterview stellt dieselben Fragen. Der Schlüsselspeicher, die Schlüsselsuche und der Schlüsselverpackungsschlüssel werden vom Rest der Einrichtung unabhängig von der Antwort eingerichtet.

SRS wird auf jedem eingehenden Pfad automatisch verdrahtet, gleich welches Weiterleitungsziel, mit einem erzeugten Secret; nur seine SRS_DOMAIN wird erfragt (im selben Schritt wie die Frage zum Signieren weitergeleiteter Mail, mit der primären bedienten Domain als Standardwert).

85.1.39.1.5.1. Auf diesem Host gefundene Mailfilter (Milter)

Auf einem Host, der Mail empfängt, durchsucht der Assistent ihn nach Milter-Daemons und bietet jeden gefundenen als pepsi-stage-milter-Stage an (siehe pepsi-stage-milter(1)). Er installiert nie einen und startet oder sperrt den Daemon nie ein: Wie unter sendmail und Postfix behält der Filter sein eigenes Paket, seine Unit und sein Benutzerkonto, und Pepsi ist nur ein Client. Der Suchlauf wird auf einem rein ausgehenden Host übersprungen, wo es keinen eingehenden Pfad gibt, auf dem ein Filter zu platzieren wäre, und jeder gefundene Filter wird auf dem eingehenden Pfad platziert. Ein Filter für eingelieferte Mail wird von Hand konfiguriert oder — auf einem Host, der auch empfängt — aus einem importierten non_smtpd_milters übernommen.

Sieben Filter werden erkannt: milter-greylist, milter-regex, clamav-milter, spamass-milter, rspamd (über seinen rspamd_proxy-Milter-Worker), mimedefang und amavisd-milter.

Jeder wird in drei Stufen gesucht, und ein Filter wird nur angeboten, wenn alle drei gelingen:

  1. Installiert — sein Binärprogramm liegt auf $PATH oder in den üblichen sbin-Verzeichnissen, oder es existiert eine systemd-Unit-Datei dafür.

  2. Lauscht irgendwo — ein Socket wird aus der eigenen Konfigurationsdatei des Filters gelesen (MilterSocket in clamav-milter.conf, socket in greylist.conf, ein SOCKET= oder ein -p-Flag in einem /etc/default-Fragment, Rspamds bind_socket), dann aus dem ExecStart seiner Unit, dann aus den Pfaden, die seine Distribution mitliefert.

  3. Antwortet — das Setup führt eine echte Milter-Optionsaushandlung mit jedem Kandidaten-Socket vollständig durch und nimmt den ersten, der gelingt.

Der Handschlag ist es, was das Angebot vertrauenswürdig macht: Ein installiertes Paket beweist nichts über einen gestoppten Daemon, und eine falsche Vermutung in den Pfadlisten kostet nichts, denn ein Socket, der nicht antwortet, wird schlicht nie angeboten. Er klärt auch, was der Filter tun darf. ALLOW_ACTIONS muss jede Aktion gewähren, die ein Filter verlangt, sonst weist pepsi-stage-milter die Nachricht konstruktionsbedingt ab, und der Filter nennt diese Menge während der Aushandlung — also bietet das Setup alles an, bloß um die Antwort zu hören, und schreibt genau das aus, was verlangt wurde, und nichts mehr. Einem Filter, der nur inspiziert, wird none gewährt; MIMEDefang werden die Umschlagaktionen genau dann gewährt, wenn die eigene Perl-Richtlinie des Standorts sie verwendet.

Jeder angenommene Filter wird zu einer Stage, platziert nach dem, was er tut, statt nach der Reihenfolge, in der er gefunden wurde: zuerst Richtlinie und Greylisting, dann Virenscan, dann Spam-Bewertung, dann die Allzweck-Frameworks — und alle nach [stage-decrypt] (sodass ein Filter Klartext sieht) und vor den Stages für weiße Liste, Bezahlschranke und Autocrypt (sodass diese auf das verzweigen können, was ein Filter markiert hat). Aus einem MTA-Import übernommene Filter haben keinen bekannten Zweck und laufen daher nach all diesen, unter Beibehaltung der relativen Reihenfolge, in der jener MTA sie ausführte.

Abgewiesene Mail wird verworfen statt gebounct. Pepsi führt Filter nach der Warteschlange aus, sodass ein REJECT für eine Nachricht gilt, die pepsi-ingress bereits mit 250 beantwortet hat: Es kann die SMTP-Sitzung nicht so abweisen, wie der Filter es unter einem MTA tat, und ein Bounce sendete Rückstreuung an die Adresse, die gefälschter Spam nannte. Das REJECT_STAGE jedes erkannten Filters zeigt daher auf eine erzeugte [stage-discard-rejected] (ein pepsi-stage-discard mit DISPOSITION = failure, BOUNCE = no); das Urteil wird weiterhin in state.milter und im Journal festgehalten. REJECT_STAGE = bounce zu setzen stellt die Benachrichtigung wieder her, und der erzeugte Abschnitt sagt das. Ein Filter, der aus einem MTA-Import kam, behält bounce, denn dem Absender Bescheid zu geben ist das übernommene Verhalten.

Ein erkannter Filter wird angeboten, aber nicht vorgeschlagen: milter-greylist steht standardmäßig auf nein. Greylisting funktioniert, indem die Zustellung innerhalb der Sitzung abgewiesen wird und darauf gewettet wird, dass ein echter MTA es erneut versucht, wo eine Spam-Maschine es nicht tut — und nach der Warteschlange gibt es keine Sitzung abzuweisen, und Pepsi selbst ist das, was es erneut versucht, sodass das Triplett verfällt und die Nachricht zugestellt wird, was auch immer sie gesendet hat. Die spamblockierende Wirkung ist null, und nur die Verzögerung bei jedem neuen Korrespondenten bleibt. Es wird dennoch angeboten, denn ein Standort betreibt milter-greylist womöglich wegen anderer Richtlinien, die sein Regelsatz trägt.

Filter, deren Aufgabe Pepsi bereits erledigt, werden nicht angeboten: opendkim, openarc, opendmarc, SPF-Richtliniendaemons und postsrsd. Einen davon neben Pepsi zu betreiben bedeutet, dass zwei Komponenten dieselbe Nachricht signieren oder beurteilen. Sie werden nicht stillschweigend übersprungen — wird einer gefunden, sagt der Suchlauf das und nennt die Pepsi-Funktion, die ihn ersetzt, sodass ein Suchlauf, der nichts anzubieten fand, von einem unterscheidbar ist, der nicht lief. Die Spam-Klassifikation liegt bewusst nicht in dieser Kategorie: Pepsi hat eigene Meinungen über Spam, aber es sind andere Meinungen als die eines Bayes-Bewerters, und ein Operator mag vernünftigerweise beide wollen.

Jede Antwort wird unter ihrem eigenen MILTER_*-Schlüssel (MILTER_CLAMAV, MILTER_RSPAMD, …) in [pepsi-wizard] gemerkt. Nur Filter, die dieser Lauf tatsächlich gefunden hat, werden dort geschrieben; ein erneuter Lauf sucht erneut.

Die erzeugte Konfiguration wird vor dem Schreiben durch genau dieselben Prüfungen wie run validiert, sodass der Assistent nie eine Datei erzeugt, die später nicht geladen werden könnte. Wenn die Validierung doch fehlschlägt, gibt der Assistent den beanstandeten Fehler aus und führt das Interview erneut durch, wobei Ihre vorherigen Antworten als Standardwerte vorausgefüllt sind, sodass Sie die fehlerhafte(n) Option(en) korrigieren können, ohne alles erneut einzugeben. Die Interview-Antworten werden in einem [pepsi-wizard]-Abschnitt am Ende der Datei festgehalten (Geheimnisse — das Smarthost-Passwort, das Händler-Zugriffstoken und der erzeugte SRS-Schlüssel — werden dort nicht gespeichert); ein erneuter Lauf von –wizard importiert sie als die neuen Standardwerte.

Weil die Hauptkonfiguration weltweit lesbar geschrieben wird (Modus 0644, sodass die unprivilegierten Stage-Konten sie lesen können), belässt der Assistent keine Geheimnisse darin. Jedes Geheimnis, das er sonst inline schreiben würde — das SRS-SECRET, die Smarthost-/LMTP-PASSWORDs, das Händler-MERCHANT_ACCESS_TOKEN und das pepsi-httpd-RESUME_AUTHORIZATION_TOKEN — wird in ein eingeschränktes secrets.d/*.secret-Fragment neben der Konfiguration verschoben und von dort mit einer @inline-secret@-Direktive referenziert (siehe pepsi.conf(5)). Die erzeugten (der SRS-Schlüssel, das /resume-Token) werden aus dem bestehenden Fragment zurückgelesen und wiederverwendet, sodass ein erneuter Lauf des Assistenten sie nie stillschweigend rotiert (was bereits in Bearbeitung befindliche SRS-Absender oder den installierten Zahlungs-Webhook ungültig machen würde).

85.1.39.1.5.2. Geheimnis-Abfragen

Die Geheimnisse, die Sie eingeben — die Smarthost- und LMTP-Passwörter, das Händler-Zugriffstoken — werden nie angezeigt und nie in [pepsi-wizard] geschrieben. Bei einem erneuten Lauf werden sie aus ihrem secrets.d-Fragment zurückgelesen, sodass die Eingabeaufforderung [***] zeigt und Enter das gespeicherte Geheimnis beibehält:

Smarthost password [***]:

Drei Antworten sind möglich:

Enter

Behält das Gespeicherte bei. Wenn das Fragment existiert, dieser Prozess es aber nicht lesen darf (es gehört dem Dienstkonto und der Assistent läuft unprivilegiert), wird das Fragment völlig unangetastet gelassen und die Konfiguration zeigt weiterhin darauf — das Geheimnis bleibt erhalten, ohne dass der Assistent es je zu sehen bekommt.

ein Wert

Ersetzt das gespeicherte Geheimnis durch das, was Sie eingegeben haben.

Enter zweimal

Lässt das Geheimnis vorerst ungesetzt. Dies wird nur angeboten, wenn nichts gespeichert ist, und nur auf einem Terminal; der Assistent schreibt die Konfiguration dann ohne diese Option, gibt Abschnitt, Option und Datei aus, in die sie einzutragen ist, und hinterlässt im Fragment eine auskommentierte Zeile, die sie benennt. Die Dienste werden nicht funktionieren, bis Sie sie ausfüllen und pepsi-setup run ausführen.

Für einen Smarthost, der sich authentifiziert, bietet der Assistent anschließend an, die Zugangsdaten zu prüfen, indem er eine Sitzung zum Relay öffnet und sich authentifiziert — genau das, was eine Zustellung tut, nur ohne die Nachricht —, sodass ein vertipptes Passwort auffällt, solange Sie noch da sind, um es zu korrigieren, statt als Mail, die still zu fließen aufhört:

Check these credentials against smtp.relay.example:587 now [Y/n]:

Wenn das Relay sie ablehnt, bietet der Assistent an, das Passwort erneut entgegenzunehmen; wenn es überhaupt nicht erreichbar ist (Firewall, DNS, der Host ist ausgefallen), sagt er das und drängt Sie nicht dazu, ein möglicherweise völlig korrektes Passwort neu einzutippen. Die Prüfung entfällt vollständig, wenn stdin kein Terminal ist: Ein unbeaufsichtigter Lauf darf nicht davon abhängen, dass das Netz erreichbar ist. Jede Direktive wird nach der letzten Option des Abschnitts geschrieben, den sie speist, weil eine Direktive ihren Abschnitt für den Parser beendet (siehe pepsi.conf(5)). Die Fragmente werden gesichert (Modus und Eigentümerschaft), sobald sie geschrieben werden, und erneut durch run; siehe den run-Befehl unten. Der Assistent lädt danach die gerade geschriebene Datei neu und validiert diese, sodass nie eine Konfiguration zurückbleibt, die er selbst nicht parsen kann. Nach dem Schreiben bietet der Assistent an, die vollständige Einrichtung (run) sofort auszuführen.

Wenn die Zieldatei bereits existiert und einen [pepsi-wizard]-Abschnitt enthält, werden ihre Antworten als Standardwerte importiert. Existiert sie ohne einen, warnt der Assistent, dass er keine vorherigen Antworten importieren kann, und fragt vor dem Überschreiben um Bestätigung; –force überschreibt ohne Nachfrage.

Bemerkung

Die Anti-Spam-Bezahlschranke setzt voraus, dass ihre Nachrichtenvorlagen (z. B. payment-request.en.body) unter [pepsi] TEMPLATE_DIR installiert sind (Standardwert ${DATADIR}/templates, also /usr/share/pepsi/templates bei einer Installation mit --prefix=/usr); make install legt sie dort ab. Weil der Assistent gegen die Live-Umgebung validiert, meldet das Aktivieren der Bezahlschranke vor der Installation der Vorlagen einen klaren Fehler, statt eine Konfiguration zu schreiben, die zur Laufzeit scheitern würde.

85.1.39.1.5.3. Ohne Terminal antworten

–answers FILE führt das gesamte Interview aus einem JSON-Objekt von Fragen-Bezeichner auf Wert aus, ohne etwas zu fragen. Es ist keine zweite Implementierung des Assistenten: Dasselbe interview() läuft, mit jeder Eingabeaufforderung auf die gelieferte Antwort kurzgeschlossen (oder, wo es keine gibt, auf die eigene Vorgabe des Assistenten, genau wie ein Druck auf Enter). Die Verzweigungsstruktur, die Validierung je Feld und das Rendern sind daher die interaktiven.

Die Bezeichner sind das, was pepsi-setup questions ausgibt, und es sind dieselben Schlüssel, die der erzeugte [pepsi-wizard]-Abschnitt hin- und zurückführt — sodass eine von einem früheren Lauf geschriebene Konfiguration selbst eine gültige Antwortdatei ist, sobald dieser Abschnitt in JSON verwandelt wird. Die Experten-Optionen (–expert und alles, was eine MTA-Migration gefunden hat) teilen sich diesen Namensraum und werden hier ebenfalls angenommen, validiert durch dieselbe Prüfung, die die --expert-Eingabeaufforderung anwendet; das Browser-Interview weist sie bewusst ab, denn eine Option, nach der nichts fragt, ist keine, die ein Webformular setzen sollte. Ein unbekannter Bezeichner ist ein Fehler, der den Schlüssel nennt, statt einer stillschweigend verworfenen Zeile, denn eine Antwort, die stillschweigend ignoriert wird, sieht genau so aus wie eine, die angenommen wurde und keine Wirkung hatte.

Geheimnisse können in der Datei auftauchen (SMARTHOST_PASSWORD, LMTP_PASSWORD, MERCHANT_ACCESS_TOKEN); sie werden wie jedes andere in secrets.d-Fragmente verschoben, sodass die Datei selbst wie ein Berechtigungsnachweis behandelt und anschließend gelöscht werden sollte. Ein bereits in einem Fragment gespeichertes Geheimnis wird weitergetragen, wenn die Antwortdatei es nicht erwähnt, und das ist es, was einen skriptgesteuerten erneuten Lauf zerstörungsfrei macht.

Beispiel:

cat > answers.json <<'EOF'
{
  "DIRECTION": "both",
  "HOSTNAME": "mx.example.com",
  "DOMAINS": "example.com",
  "POSTMASTER": "postmaster@example.com",
  "PUBLIC_IPS": "203.0.113.7",
  "LOCAL_METHODS": "maildir",
  "MTA_STS": "yes"
}
EOF
pepsi-setup --wizard --answers answers.json -c /etc/pepsi/pepsi.conf

85.1.39.1.6. Migration von einem anderen MTA

Niemand installiert einen Mailserver auf einer leeren Maschine. Wenn –wizard am Zielpfad keine Konfiguration findet, sucht es nach dem Mailserver, den der Host heute betreibt — Postfix, Exim, Sendmail, qmail oder Stalwart — und bietet an, dessen Einstellungen als Standardantworten des Interviews zu importieren. Wenn mehrere konfiguriert sind, präsentiert es ein nummeriertes Menü; –import MTA wählt einen ohne Nachfrage und –no-import überspringt die Suche vollständig. Die automatische Erkennung entfällt, wenn stdin kein Terminal ist, sodass ein skriptgesteuerter –wizard-Lauf weiterhin die Konfiguration erzeugt, die seine Antworten beschreiben, statt einer, die von dem geprägt ist, was auf der Maschine übrig geblieben ist.

Nichts wird stillschweigend importiert. Jeder importierte Wert wird zum [default] seiner Frage, den der Operator bestätigt oder korrigiert, und alles, was nicht übernommen werden konnte, wird in einem Migrationsbericht gesammelt, der neben der Konfiguration als import-report.txt geschrieben wird (und vor dem Start des Interviews auch als einzeilige Zusammenfassung ausgegeben wird). Der Bericht gruppiert seine Befunde in vier Kategorien:

FAILED

Eine Datei konnte nicht gelesen oder geparst werden; aus ihr wurde nichts importiert.

UNSUPPORTED

Verstanden, aber Pepsi hat keine Entsprechung — eine header_checks-Tabelle, ein Alias, der an ein Kommando zustellt. Der Eintrag benennt, was Pepsi stattdessen bietet, sofern es etwas bietet.

APPROXIMATED

Mit anderer Semantik importiert; eine mbox-Zustellung, die zu Maildir wird, ein auf volle Stunden gerundetes maximal_queue_lifetime, ein aus MYNETWORKS entferntes Loopback-Netz.

UNKNOWN

Eine Direktive, die der Importer nicht kennt und daher nicht migriert hat. Gemeldet, damit eine nicht erkannte Einstellung sichtbar statt unsichtbar ist.

Ein Import kann den Lauf nie scheitern lassen: eine unlesbare Datei, eine korrupte Zeile oder eine Direktive aus einem Fork, von dem niemand je gehört hat, erzeugt eine Warnung, und der Rest der Konfiguration wird trotzdem importiert.

85.1.39.1.6.1. Routing-Tabellen

/etc/aliases, /etc/postfix/virtual, Sendmails virtusertable, qmails .qmail-*-Dateien und ihre Entsprechungen werden in eine Pepsi-Alias-Map umgewandelt (siehe pepsi-stage-aliases(1)), die neben der Konfiguration als aliases geschrieben wird, und eine Submission-Identitätstabelle (Postfix‘ smtpd_sender_login_maps und Verwandte) in username.map (siehe USERNAME_MAP in pepsi-ingress(1)). Eine bestehende Datei wird nie überschrieben: Die umgewandelte Tabelle landet stattdessen in aliases.imported, damit der Operator sie zusammenführt.

Pepsi-Alias-Schlüssel tragen eine Domain (local@domain, @domain oder einen *-Glob), während /etc/aliases-Schlüssel bloße Local-Parts sind, daher fragt der Assistent, wie sie zu qualifizieren sind (–alias-style beim import-Befehl):

per-domain

Eine Zeile je Alias und akzeptierter Domain — exakt, und der Standardwert.

wildcard

Eine Zeile je Alias mit einem Domain-Glob (postmaster@*) — kompakt, passt aber auch auf später hinzugefügte Domains.

primary

Nur mit der ersten akzeptierten Domain qualifizieren; die übrigen werden als nicht aliasiert gemeldet.

Einträge, die Pepsi nicht ausdrücken kann — eine Zustellung an ein Kommando (|/usr/bin/…), an eine Datei oder ein unlesbares :include: — werden als inerte # UNCONVERTED-Kommentare in die umgewandelte Map geschrieben, neben einem Berichtseintrag, der erklärt warum, sodass nichts spurlos verschwindet. Die erzeugte Map wird mit derselben strengen Syntaxprüfung geprüft, die run auf eine handgeschriebene anwendet.

85.1.39.1.6.2. Abdeckung je Server

Postfix

/etc/postfix/main.cf (mit $parameter-Interpolation und Fortsetzungszeilen) und master.cf. Die Identität stammt aus myhostname/mydomain, die akzeptierten Domains aus mydestination, virtual_alias_domains, virtual_mailbox_domains und relay_domains; der Smarthost aus relayhost, sein Transport aus smtp_tls_security_level / smtp_tls_wrappermode und seine Zugangsdaten aus smtp_sasl_password_maps. Die lokale Zustellung wird aus home_mailbox, mailbox_transport/virtual_transport (ein lmtp:unix:-Ziel wird zu Pepsis LMTP-Stage) und mail_spool_directory gelesen; die Submission-SASL aus smtpd_sasl_type = dovecot und smtpd_sasl_path; die aktivierten Dienste in master.cf entscheiden über die Richtung. alias_maps/alias_database und virtual_alias_maps werden zur Alias-Map (Virtual-Einträge gewinnen, wie sie es in Postfix tun), und smtpd_sender_login_maps wird zu username.map, invertiert in Pepsis nach dem Login geschlüsselte Form. message_size_limit, mynetworks, recipient_delimiter, maximal_queue_lifetime, smtp_helo_name und die smtpd_tls_*-Zertifikatspfade kommen als Experten-Optionen an.

Gemeldet statt migriert: header_checks/body_checks, transport_maps, kanonisches Umschreiben, smtpd_*_restrictions, postscreen_*, content_filter, Zustellung in virtuelle Postfächer, dienstweise -o-Überschreibungen in master.cf und Map-Typen, die nichts als Text lesen kann (regexp:, pcre:, mysql:, ldap:, …). Rund neunzig Parameter, die Postfix‘ eigene Installation oder Feinabstimmung beschreiben, werden stillschweigend ignoriert; alles andere wird als nicht erkannt aufgeführt.

Exim

Debians Antwortdatei /etc/exim4/update-exim4.conf.conf ist die reichhaltigste und zuverlässigste Quelle und hat Vorrang: dc_eximconfig_configtype gibt die Richtung und ob es einen Smarthost gibt, dc_other_hostnames die Domains, dc_smarthost das Relay, dc_relay_nets die vertrauenswürdigen Netze und dc_localdelivery das Postfachformat. Der Hauptteil von exim4.conf.template / exim.conf / conf.d/main/* (alles vor dem ersten begin) ergänzt primary_hostname, qualify_domain, domainlist local_domains, hostlist relay_from_hosts, message_size_limit, smtp_accept_max und das tls_certificate-Paar. Exims Listensyntax wird korrekt behandelt — verdoppelte Trennzeichen, <;-Überschreibungen, .include, +named-Referenzen und .ifdef, ausgewertet gegen die tatsächlich definierten Makros. /etc/aliases wird zur Alias-Map, /etc/email-addresses zur Submission-Identitäts-Map und /etc/exim4/passwd.client zu den Smarthost-Zugangsdaten.

Exims Router, Transports, ACLs, Rewrite-Regeln, Authenticators und Retry-Regeln sind eine Programmiersprache, und ein halbes Parsen davon erzeugt eine plausible, aber falsche Migration. Sie werden daher überhaupt nicht interpretiert: Jeder begin-Block wird einmal gemeldet, benannt mit dem, was ihn in Pepsi ersetzt (der Stage-Graph für Router und Transports, Listener-MYNETWORKS/SASL plus die Stages für weiße Liste und Anti-Spam für ACLs, SRS und die Alias-Map für das Umschreiben). Zwei Folgen: Weil die Retry-Leiter in begin retry liegt, wird MAX_LIFETIME nie erraten, und weil der Transport die TLS- und AUTH-Richtlinie hält, wird die Transportsicherheit des Smarthosts angenommen statt gelesen. Ein tls_certificate, das eine $-Expansion enthält, ist eine Berechnung und kein Pfad und wird gemeldet statt importiert.

Sendmail

/etc/mail/sendmail.mc — die m4-Quelle, die ein Administrator tatsächlich bearbeitet — wird bevorzugt; sendmail.cf wird verwendet, wenn keine .mc existiert, und dann nur seine zuverlässig lesbaren Zeilen (Dj der kanonische Name, DS der Smarthost, Cw/Fw die lokalen Hostnamen, DZ die Version und die O-Optionen). Die erzeugten Regelsätze werden nie interpretiert, und der Bericht sagt das. Aus der .mc: SMART_HOST (mit seinem Mailer-Präfix, Port und Klammern), confDOMAIN_NAME, confMAX_MESSAGE_SIZE, confTO_QUEUERETURN, confMAX_DAEMON_CHILDREN, confSERVER_CERT/confSERVER_KEY, ALIAS_FILE, DAEMON_OPTIONS (welche Ports bedient wurden, also die Richtung) und die FEATUREs, auf die es ankommt — use_cw_file, virtusertable, authinfo, local_lmtp, plussed_users, local_procmail, nullclient. Die Tabellen local-host-names, virtusertable, aliases und authinfo (die Smarthost-Zugangsdaten, mit dem Mechanismus aus ihrem M:-Feld) werden gelesen; postmaster wird über die Alias-Kette zu einer echten Adresse aufgelöst.

Gemeldet statt migriert: MASQUERADE_AS und Verwandte (Pepsi schreibt Absender stattdessen mit SRS um), access_db, mailertable, domaintable, genericstable, LOCAL_RULE_*/LOCAL_CONFIG/HACK, DNSBL- und Greet-Pause-Funktionen, smrsh/procmail als lokale Mailer und rechte virtusertable-Seiten, die Pepsi nicht ausdrücken kann (error:, %1).

qmail

Das Control-Verzeichnis (/var/qmail/control, /etc/qmail oder /usr/local/etc/qmail) wird aufgezählt und nicht namentlich abgefragt, sodass jede Control-Datei entweder verarbeitet, stillschweigend als irrelevant ignoriert oder gemeldet wird — einschließlich solcher aus einem Fork, von dem dieser Importer nie gehört hat. me gibt den Hostnamen; locals, rcpthosts, morercpthosts und virtualdomains die Domains; der :relay:port-Catch-All in smtproutes den Smarthost (mit Zugangsdaten, wenn die erweiterte Form der AUTH-Patches verwendet wird); defaultdelivery (oder das qmail-start-Argument in rc) das Postfachformat; databytes, queuelifetime, helohost und ein servercert.pem die Experten-Optionen.

Die Alias-Tabelle sind die .qmail-*-Dateien in qmails Alias-Verzeichnis: .qmail-foo-bar wird zu foo-bar, : dekodiert zurück zu ., .qmail-default wird zu einem Catch-All und .qmail-foo-default zu einem Glob. Ihre Inhalte werden als Ziele durchgereicht, sodass ein |command, ein Dateipfad oder ein relatives ./Maildir/ im Bericht erklärt statt zu einer unsinnigen Adresse verstümmelt wird. Benutzereigene ~/.qmail-Dateien werden bewusst nicht durchlaufen (teuer und datenschutzsensibel; pepsi-stage-dot-forward ist die Laufzeit-Entsprechung), und es wird nie eine .cdb geöffnet — stattdessen wird das textuelle users/assign gelesen. badmailfrom/badrcptto, spfbehavior, percenthack, qmqpservers und tlsclients werden mit ihren Pepsi-Gegenstücken gemeldet.

Stalwart

config.toml unter /opt/stalwart-mail/etc, /opt/stalwart/etc, /etc/stalwart oder /etc/stalwart-mail (ein Verzeichnis von .toml-Fragmenten wird ebenfalls gelesen, und !include-Direktiven wird gefolgt). server.hostname und die server.listener.*-Ports geben Identität und Richtung, queue.outbound.next-hop / queue.strategy.route und die remote.*-Tabelle den Smarthost (ein Hop mit protocol = "lmtp" wird stattdessen zu lokaler LMTP-Zustellung), certificate.* die TLS-Pfade, session.data.limits.size und der Queue-Ablauf die Experten-Optionen. Ein directory vom Typ memory (oder ein principals-Array) liefert Konten: Jede zusätzliche Adresse wird zu einem Alias auf die primäre Adresse des Kontos, und die Logins werden zu username.map. Als %{file:…}% geschriebene Geheimnisse werden aufgelöst; %{env:…}% kann nicht aufgelöst werden und wird gemeldet.

Stalwarts eigene Ausdrücke ([{if = …}, {else = …}]) werden nie ausgewertet — nur ein einfacher Wert wird berücksichtigt, alles andere wird gemeldet statt erraten. Der wichtige Fall, den man kennen sollte: Neuere Stalwart-Versionen halten die Betriebskonfiguration in ihrem Datenspeicher, nicht in der TOML. Wenn die Datei wie ein Bootstrap-Rumpf aussieht, sagt der Bericht das deutlich, benennt den Speicher und weist Sie an, die Konfiguration aus Stalwarts Admin-Oberfläche zu exportieren — auf der Platte gibt es für Pepsi nichts zu lesen. IMAP-, JMAP-, POP3-, ManageSieve-, Sieve-, Spamfilter- und Reporting-Einstellungen werden als nicht unterstützt gemeldet, mit einem Verweis auf die Pepsi- (oder Dovecot-)Entsprechung.

85.1.39.1.6.3. Zugangsdaten

Zugangsdaten für das Smarthost-Relay werden aus der eigenen Passwortdatei des Quell-MTA gelesen (Postfix‘ smtp_sasl_password_maps, Exims passwd.client, Sendmails authinfo, Stalwarts TOML), sodass der Operator ein Passwort nicht wiederbeschaffen muss, das er vielleicht nicht mehr hat. Der Bericht benennt immer die Datei, aus der ein Geheimnis gelesen wurde. Importierte Passwörter gehen denselben Weg wie eingegebene: Der Assistent verschiebt sie aus der weltweit lesbaren Konfiguration in secrets.d/*.secret-Fragmente, die mit @inline-secret@ referenziert werden.

85.1.39.1.6.4. Was nicht migriert wird

Bereits im alten Server eingereihte Mail wird nicht migriert — lassen Sie die Warteschlange leerlaufen oder leeren Sie sie, bevor Sie den MX umschalten. DKIM-Schlüssel werden ebenfalls nicht migriert; run erzeugt frische und gibt die zu veröffentlichenden DNS-Einträge aus. Wenn der alte MTA noch auf Port 25 lauscht, während der Assistent läuft, sagt der Bericht das: pepsi-ingress kann den Port nicht binden, bis er gestoppt und deaktiviert ist.

85.1.39.1.7. Experten-Optionen

Zwischen den Fragen, die das Interview stellt, und dem vollen Optionsumfang von pepsi.conf(5) liegt eine Schicht gewöhnlicher Pepsi-Optionen, die niemand beantworten muss, um einen funktionierenden Server zu bekommen: das Nachrichtengrößenlimit, das Empfänger-Trennzeichen, die vertrauenswürdigen Netze, die Warteschlangen-Lebensdauer, der DKIM-Selektor.

–expert SPEC lässt den Assistenten in einem abschließenden Interview-Schritt nach ihnen fragen. SPEC ist eine durch Kommas oder Leerzeichen getrennte Liste von Gruppenwörtern und/oder Optionsnamen:

high

Die Optionen, die ein Administrator plausiblerweise anpasst: MAX_MESSAGE_SIZE, MYNETWORKS, RECIPIENT_DELIMITER, MAX_LIFETIME, DMARC_ENFORCE und MAILBOX_QUOTA (bewusst in dieser Gruppe statt in insane: Ein Standort, der lokal zustellt, will einen Standardwert für die Quota und sollte den Namen der Option nicht kennen müssen).

insane

Alles in der Registry, ergänzt um HELO_NAME, TLS_CERT, TLS_KEY, DNS_TIMEOUT, MAX_CONNECTIONS, MAX_OPEN_SOCKETS, DKIM_SELECTOR, KEY_DIR, MAILBOX_OVER_QUOTA und CRYPTO_ALLOW_DOWNGRADE.

Ein Optionsname

Fragt genau nach dieser einen, unabhängig von ihrer Gruppe: --expert=MAX_MESSAGE_SIZE,RECIPIENT_DELIMITER. Kombinierbar mit einem Gruppenwort: --expert=high,DKIM_SELECTOR.

all wird als Synonym für insane akzeptiert, und none (oder off) löscht ein zuvor in derselben SPEC angegebenes Gruppenwort. Ein unbekannter Selektor ist ein Fehler, der die gültigen Namen auflistet, und keine stillschweigend leere Auswahl.

--expert=help gibt die Liste aus und beendet sich.

Jede Option wird in den Abschnitt geschrieben, der sie tatsächlich liest — MYNETWORKS auf den Port-25-Listener (nie auf einen Submission-Listener), MAX_MESSAGE_SIZE auf [pepsi-ingress], HELO_NAME auf die Route des Smarthosts ([pepsi-stage-relay-to-smarthost-mta-smarthost]) — und wird in [pepsi-wizard] festgehalten, sodass ein späterer erneuter Lauf sie beibehält. Eine leer gelassene Antwort entfernt die Option und stellt Pepsis eigenen Standardwert wieder her.

RECIPIENT_DELIMITER ist diejenige, die es auszubuchstabieren lohnt: Sie wird in den globalen [pepsi]-Abschnitt geschrieben statt auf die Stages der lokalen Zustellung, weil pepsi-ingress (das keinen eigenen Stage-Abschnitt hat) denselben Wert lesen muss, um zu entscheiden, zu wessen Postfachkontingent ein Empfänger mit Subadresse gehört, und weil der Locality-Parser der Stages auf [pepsi] zurückfällt. MAILBOX_QUOTA, MAILBOX_OVER_QUOTA und CRYPTO_ALLOW_DOWNGRADE landen ebenfalls dort.

–expert steuert nur, nach welchen Optionen gefragt wird. Ein von einem MTA-Import gefundener Wert wird angewendet, ob danach gefragt wurde oder nicht: Wenn Pepsi die Option hat, wird eine migrierte Einstellung nie mangels einer Frage verworfen.

85.1.39.1.8. Befehle

import [MTA] [–root DIR] [–out DIR] [–alias-style STYLE]

Meldet, was von einem bestehenden MTA migriert würde, ohne etwas zu schreiben. Ohne MTA wird der installierte erkannt (und wenn es mehrere sind, werden sie aufgelistet und einer muss benannt werden). Die Ausgabe ist derselbe Migrationsbericht, den –wizard schreibt, dazu die Alias-Map, die erzeugt würde, und die Assistenten-Antworten, die der Import vorbelegen würde; Geheimnisse werden als Platzhalter gezeigt, nie ausgegeben.

Dieser Befehl benötigt keine Pepsi-Konfiguration — er ist dafür gedacht, bevor es eine gibt, ausgeführt zu werden, um zu sehen, was eine Migration erzeugen würde.

–root DIR

Liest die Konfiguration des MTA unterhalb von DIR statt von /. Nützlich, um eine Sicherung oder das an Ort und Stelle kopierte /etc einer anderen Maschine zu inspizieren.

–out DIR

Schreibt den Bericht und die umgewandelten Map-Dateien nach DIR (eine bestehende Datei wird nach <name>.imported umgeleitet statt überschrieben).

–alias-style STYLE

Wie bloße Alias-Namen qualifiziert werden: per-domain (Standardwert), wildcard oder primary; siehe Migration von einem anderen MTA.

run [-r | –reset]

Führt die vollständige Einrichtung durch (validieren, TLS-Zertifikate einrichten, Schema installieren, Schlüssel erzeugen, DNS-Einträge ausgeben). Dies ist auch die Standardaktion, wenn kein Unterbefehl angegeben ist. Es richtet außerdem das Herkunftsnachweis-Secret ein, wann immer [pepsi-origin] weder ein SECRET noch ein SECRET_FILE hat und nicht mit ENABLED = no abgeschaltet ist — der Herkunftsnachweis ist standardmäßig an, der Abschnitt muss also nicht vorhanden sein: Ein zufälliges Secret wird in ein secrets.d/pepsi-origin.secret-Fragment geschrieben (im Besitz des pepsi-Kontos, Modus 0640) und von der Hauptkonfiguration mit einer @inline-secret@-Direktive referenziert, sodass es aus dieser weltweit lesbaren Datei herausgehalten wird; ein erneuter Lauf verwendet das vorhandene Fragment wieder, statt den Schlüssel zu rotieren. Es wird mit einer Warnung übersprungen, wenn [pepsi-ingress] HOSTNAME nicht gesetzt ist (der Name ist in den Pepsi-Origin-MAC eingebunden) oder wenn der Pfad der zu aktualisierenden Konfigurationsdatei unbekannt ist.

Nach demselben Grundsatz erzeugt es den Schlüsselverpackungsschlüssel von [pepsi-crypto], wenn es keinen gibt — aber erst nachdem das Schema installiert ist, und nur wenn die Datenbank bestätigt, dass noch kein verpackter privater Schlüssel existiert. Ein fehlendes Fragment neben gespeicherten Schlüsseln ist ein verlorener Schlüssel und keine Neuinstallation, und einen frischen zu prägen würde stillschweigend jeden gespeicherten privaten Schlüssel unöffenbar machen; sowohl „Schlüssel existieren“ als auch „ich konnte es nicht prüfen“ verweigern daher lautstark und benennen das Wiederherstellen des Fragments als Abhilfe.

Noch vor allem anderen sichert run alle Secret-Fragmente neben der Konfiguration — die secrets.d/*.secret-Dateien, in die –wizard die Geheimnisse externalisiert (siehe unten) —, indem es jedem den Modus 0640 gibt und es an das Konto übergibt, das es lesen muss: secrets.d/pepsi.secret (Smarthost-/LMTP-Passwörter, das Händler-Zugriffstoken) an pepsi, secrets.d/pepsi-httpd.secret (das RESUME_AUTHORIZATION_TOKEN) an pepsi-httpd, secrets.d/pepsi-ingress.secret (das SRS-SECRET) an pepsi-ingress, secrets.d/pepsi-crypto.secret (das KEY_WRAP_SECRET von [pepsi-crypto], aktuell und ausgemustert) an pepsi-crypto sowie secrets.d/pepsi-secure-link.secret (das [pepsi-secure-link] PEPPER) und secrets.d/pepsi-list.secret (das [pepsi-list] UNSUBSCRIBE_SECRET) an pepsi-httpd mit der Gruppe pepsi — die beiden Fragmente mit zwei Lesern, da das Portal bedient, was die Stage versiegelt hat, und der Web-Endpunkt das Abmelde-Token verifiziert, das die Zustellungs-Stage berechnet hat. Das SRS-Secret gehört pepsi-ingress, weil Ingress SRS-Rückadressen rückwärtsdekodiert; die SRS-Stage läuft als pepsi und liest es über die geteilte pepsi-ingress-Gruppe (das Debian-Paket macht pepsi zu einem Mitglied — eine Quellinstallation muss das Äquivalent einrichten). Das Schlüsselverpackungs-Secret ist dasjenige, dessen Verlust nicht wiederherstellbar ist: Es öffnet jeden gespeicherten privaten Schlüssel, sichern Sie es also getrennt von der Datenbank (siehe pepsi-keys(1)).

Dies ist der erste Schritt, damit ein Lauf, der später abbricht — ein Zertifikat, das nicht ausgestellt werden kann, eine nicht erreichbare Datenbank —, dennoch jedes Geheimnis für seinen Dienst lesbar zurücklässt. Anschließend wird für jedes Fragment verifiziert, dass es wirklich diesem Konto gehört, und jedes, bei dem das nicht der Fall ist, wird unter den aufgeschobenen Schritten aufgeführt: Ein unlesbares Fragment ist sonst unsichtbar, weil der Konfigurationslader über eine @inline-secret@-Datei, die er nicht öffnen kann, nur warnt und der Dienst startet und später mit einem irreführenden „… is not configured“ fehlschlägt.

Zuletzt bringt run pepsi-telemetry-client.service mit [pepsi] SHARE_TELEMETRY in Einklang: systemctl enable --now, wenn die Telemetrie an ist. Ist sie aus, bleibt die Unit so, wie der Operator sie hinterlassen hat — nie gestartet und nicht mehr gestoppt: Ein laufender Daemon ist ruhend (kein Socket, nichts übermittelt), und ihn zu behalten ist das, was es der Browser-Konsole erlaubt anzubieten, Telemetrie einzuschalten. In beiden Fällen sendet run danach die Benachrichtigung telemetry_changed, sodass ein laufender Daemon der Antwort sofort folgt — das Ausschalten der Telemetrie wirkt sofort. pepsi.target startet diese Unit nicht — nichts im Target Wants sie, denn eine Unit, die das Target mitzöge, liefe, gleich was die Antwort war; die Unit ist allerdings PartOf= des Targets und stoppt daher mit der Pipeline. Es geschieht hier, am Ende, weil die SYSTEM_ID früher im selben Lauf erzeugt wird; mit eingeschalteter Telemetrie und ohne gültige Kennung wird die Unit trotzdem scharfgeschaltet (der Daemon bleibt ruhend und sagt, warum), und der Grund wird protokolliert. All das geschieht nach bestem Bemühen: Einem Host ohne systemd, ohne installierte Unit oder ohne root wird stattdessen der einzelne systemctl-Befehl genannt. Siehe pepsi-telemetry-client(1).

-r, –reset

Verwirft alle bestehenden pepsi-Objekte, bevor sie neu erstellt werden. GEFÄHRLICH: Alle gespeicherten Nachrichten sind unwiederbringlich verloren. Signierschlüssel auf der Festplatte sind nicht betroffen. Nötig ist dies nur für eine Datenbank, die eine Entwicklungsversion aus einer anderen Fassung eines unveröffentlichten Patches gebaut hat; das Schema eines älteren Releases wird an Ort und Stelle aktualisiert (siehe schema).

schema [–backup-dir DIR] [–if-installed]

Installiert das Datenbankschema oder führt sein Upgrade durch und wendet die Rollenrechte erneut an, und sonst nichts: keine Konfigurationsprüfung über [pepsi-postgres] hinaus, keine Zertifikate, keine Schlüssel, kein DNS. Es funktioniert daher mit jeder Konfigurationsdatei, die die Datenbank nennt – /etc/pepsi/pepsi.conf auf einem Mail-Host, /etc/pepsi-telemetry/pepsi-telemetry.conf auf einem Telemetrie-Collector –, und ist das, was eine Paketaktualisierung ausführt, bevor die Dienste neu starten.

Der Installer hält den SHA-256 jeder angewendeten SQL-Datei und das Release, aus dem sie stammt, in pepsi.schema_file fest; jedes Pepsi-Programm vergleicht diesen Eintrag beim Verbinden mit den in es einkompilierten Hashes und verweigert den Betrieb (Exit-Status 78) gegen ein Schema, das älter, neuer oder aus anderen Dateien gebaut ist. schema bringt ein älteres Schema auf den Stand dieses Releases. Es weist zurück, bevor es irgendetwas ändert und mit Exit-Status 78, ein Schema, das neuer als dieses Release ist (Downgrades werden nicht unterstützt: ältere gespeicherte Funktionen, über ein neueres Schema installiert, würden es beschädigen), eines, das aus einer anderen Fassung einer Patch-Datei gebaut wurde, und eines ganz ohne Eintrag (von einer Entwicklungsversion gebaut, bevor es den Eintrag gab; eine solche Datenbank muss geleert und mit run –reset neu erstellt werden). Es weist auch SQL-Dateien in SQL_DIR zurück, die nicht diejenigen sind, mit denen dieses Binary gebaut wurde – ein veraltetes Verzeichnis nach einem unvollständigen Upgrade. Gleichzeitig laufende Installer serialisieren sich über eine Advisory-Sperre.

–backup-dir DIR

Sichert das Schema, bevor ein Upgrade irgendetwas ändert, mit pg_dump(1) (Custom-Format; die Schemas pepsi und _v sowie die Erweiterungen, die der Trigramm-Index des Archivs braucht) als DIR/pepsi-OLD-VERSION-UTC-TIME.dump, Modus 0600, ausgeführt als Schemaeigentümer. Wird nur angelegt, wenn es etwas zu aktualisieren gibt. Schlägt der Dump fehl, wird nichts aktualisiert. Alte Dumps werden nie gelöscht. Wiederherstellen lässt sich einer mit pg_restore(1) in eine leere Datenbank.

–if-installed

Tut nichts, wenn die Datenbank noch kein Pepsi-Schema hat. Eine Neuinstallation wird mit run eingerichtet; dies ist für Maintainer-Skripte gedacht, die kein Schema installieren dürfen, um das niemand gebeten hat.

check

Fragt Live-DNS ab und meldet für jede autoritative Domain, ob die tatsächlich veröffentlichten Einträge dem entsprechen, was run erzeugen würde. Geprüft werden die DKIM-Selektor-Einträge (ein wohlgeformter Schlüsseleintrag vom richtigen k=-Typ, dessen öffentlicher Schlüssel in p= dem lokalen Schlüssel entspricht; siehe Gibt DNS-Einträge aus unter run), der SPF-Eintrag (der v=spf1-Eintrag führt jede konfigurierte PUBLIC_IP auf), der _dmarc-TXT-Eintrag (genau einer, und streng gültig — siehe Gibt DNS-Einträge aus unter run oben) und der _mta-sts-TXT-Eintrag (vorhanden und ein parsbarer v=STSv1-Eintrag mit einem id=-Tag — der Wert von id wird vom Operator gewählt und nicht verglichen, seine Syntax aber schon: RFC 8461 §3.1 erlaubt 1 bis 32 Buchstaben und Ziffern). Jeder Eintrag wird als [ok], [MISSING], [MISMATCH], [INVALID] oder [lookup failed] gemeldet; auf jede Zeile, die nicht [ok] ist, folgt eine eingerückte →-Zeile, die den genau zu veröffentlichenden Eintrag nennt und für den maßgeblichen Wert auf run zurückverweist. Der Befehl ändert nichts, und seine Befunde bestimmen nie den Exit-Status: Er beendet sich mit 0, ganz gleich, wie viele Einträge fehlen oder falsch sind; lesen Sie also seine Ausgabe statt seines Exit-Status. (Nur eine Konfiguration, die nicht validiert, oder ein Resolver, der sich gar nicht erst aufbauen lässt, führt zu einem Exit-Status ungleich null — dann hat er nichts zu melden.)

[INVALID] ist das Urteil für einen Eintrag, der zwar veröffentlicht ist, den Empfänger aber verwerfen, sodass die Domain ungeschützt ist, während sie konfiguriert aussieht. Die Abhilfe unterscheidet sich von der der anderen: Der Eintrag wird an Ort und Stelle repariert, statt durch den Wert ersetzt zu werden, den run ausgibt. Neben den unten beschriebenen DKIM-Befunden erzeugen ihn drei Prüfungen — ein DMARC-Eintrag, der sich nicht parsen lässt (oder ein zweiter unter demselben Namen), mehr als ein v=spf1-Eintrag (RFC 7208 §4.5 macht das zu einem permanenten Fehler, sodass keine SPF-Richtlinie gilt, statt dass die erste gewinnt), und mehr als ein v=STSv1-Eintrag oder einer, dessen id= außerhalb der erlaubten Syntax liegt. Ein v=spf1-Eintrag, der auf +all endet, wird als [MISMATCH] gemeldet: Er ist gültig, er besteht den Test „sind meine Adressen aufgeführt?“, und er ermächtigt jeden Host im Internet, als die Domain zu senden, womit er die daneben veröffentlichten DKIM- und DMARC-Einträge aushebelt.

Jeder Eintrag wird zweimal geprüft: in der Antwort des System-Resolvers und bei jedem autoritativen Nameserver der Zone, direkt gefragt. Ein Eintrag, den der Resolver korrekt liefert, ein Nameserver aber nicht (ein veralteter Secondary, ein lahmer oder unerreichbarer Server), ist ein [MISMATCH], der die Server nennt, mit einer Abhilfe, die auf die Verteilung der Zone statt auf den Eintrag zeigt. Ein DKIM-Eintrag mit falschem oder fehlendem k=, einem falsch platzierten v=, einer h=/s=-Einschränkung, die ausschließt, was Pepsi signiert, oder einem zweiten Schlüsseleintrag unter demselben Namen ist [INVALID]; t=y ist ein [MISMATCH]. Wenn Ed25519-Signieren an ist, erklärt ein abschließendes note:, warum Google diesen Selektor als fail meldet.

Ein Eintrag kann auch [ok] sein und eine Anmerkung tragen — eine p=none-DMARC-Richtlinie ist gültig, ist der richtige Anfang und setzt nichts durch, sodass der Bericht das sagt, statt eine Domain unbegrenzt im Überwachungsmodus sitzen zu lassen.

Über die TXT-Einträge hinaus führt es für jede Domain, für die eine MTA-STS-Richtlinie ausgeliefert wird, die beiden unter run beschriebenen MTA-STS-Gegenprüfungen durch — die mx-Menge der Richtlinie gegen die aktuellen MX-Einträge und einen Abruf von https://mta-sts.<domain>/.well-known/mta-sts.txt, verglichen mit der konfigurierten Richtlinie — und endet mit einem Hinweis, der die MTA_STS_MX-Zeile angibt, mit der beide übereinstimmen würden. Für die [pepsi-srs] SRS_DOMAIN fügt es die unter Die SRS-Domain kann ihre eigenen Bounces empfangen beschriebene Zustellbarkeitsprüfung hinzu.

questions

Gibt das Setup-Interview auf stdout als JSON aus: die geordneten Schritte und für jede Frage ihren Bezeichner, ihre Art (text, bool, choice, list, secret, path, port, domain, integer, address, url), Eingabeaufforderung, Hilfetext, Vorgabe, ob sie erforderlich ist, die Konfigurationsoption, auf die sie abbildet, wenn sie auf genau eine abbildet, und die Bedingung, unter der sie überhaupt gestellt wird.

Das ist das Modell, durch das beide Frontends beschrieben werden — das Terminal-Interview und das Browser-Interview, das pepsi-httpd unter /api/v1/setup/questions bedient —, und es ist das Schema, gegen das eine –answers-Datei geschrieben wird. Es braucht keine Konfiguration — es ist das, was man liest, bevor man eine hat.

apply [–once] [–idle SECS] | apply –clear

Führt die privilegierte Einrichtungsarbeit aus, um die die Browser-Oberfläche gebeten hat. Als root ausführen. Siehe Das Vertrauensmodell des Appliers unten, bevor Sie das einsetzen.

Auf einem Debian-System liegen die systemd-Units, die dies auf Anforderung ausführen, im separaten Paket pepsi-httpd-admin; es zu entfernen lässt diesen Unterbefehl aus einer root-Shell weiterarbeiten und macht ihn zugleich von der Web-Konsole aus unerreichbar. Siehe Die Fähigkeit entfernen: das Paket pepsi-httpd-admin unten.

Es liest Absichts-Datensätze aus der Tabelle pepsi.setup_task — jeder eine Anforderung der administrativen API für etwas aus einer geschlossenen Menge —, prüft, dass jeder ausgeführt werden darf, tut es und hält das Ergebnis und seine Fortschrittszeilen wieder im Datensatz fest. Es verrichtet keine andere Arbeit und nimmt keine andere Eingabe an: Insbesondere liest es nie einen Befehl, einen auszuführenden Pfad oder eine wortgetreu zu schreibende Datei aus einer Aufgabe.

–once

Leert, was ansteht, und endet. Das, was ein Cron-Eintrag oder ein manueller Lauf will.

–idle SECS

Ohne –once wartet es nach dem Leeren auf dem setup_task-NOTIFY-Kanal und endet, sobald SECS ohne Arbeit vergangen sind (Standardwert 300). Das ist es, was Socket-Aktivierung funktionieren lässt: pepsi-httpd verbindet sich nach dem Einreihen mit dem Türklingel-Socket, systemd startet diese Unit, sie leert die Warteschlange und verschwindet wieder. Ein root-Prozess, der dauerhaft auf einer von einer Web-Schicht gelieferten Arbeitswarteschlange sitzt, ist genau das dauerhafte Privileg, das der Entwurf vermeidet.

–clear

Löscht jeden Datensatz von pepsi.setup_task ohne einen davon auszuführen, meldet, wie viele entfernt wurden, und endet. Zusammen mit –once oder –idle abgelehnt: Dies ist ein administratives Zurücksetzen, kein Leerungsmodus.

Eine Aufgabe ist eine dauerhafte Anfrage an einen als root laufenden Prozess, und nichts lässt sie verfallen, sodass eine Warteschlange, die dort herumliegt, eher eine Gefahr als ein Rückstau ist. Die Units des Appliers sind genau deshalb ein eigenes Paket, damit eine Installation laufen kann, ohne dass irgendetwas diese Warteschlange leert — und Datensätze können sie in diesem Zustand dennoch erreichen, etwa von einem Operator mit einer root-Shell. Installieren Sie das fehlende Paket Monate später, und jeder einzelne davon läuft beim ersten Betätigen der Türklingel, in der Reihenfolge, in der er verlangt wurde, gegen eine Installation, die weitergezogen ist. Zustimmung hält sich nicht, daher führt die Installation von pepsi-httpd-admin dies aus ihrem postinst aus.

Jeder Datensatz geht, nicht nur die pending. Nur ein pending-Datensatz kann je ausgeführt werden, und ein running-Datensatz ist definitionsgemäß verwaist, sodass nur diese beiden zu löschen für die Sicherheit genügte — aber ein „Leeren“, das eine Konsole voller done- und refused-Datensätze zurückließe, wäre keines, und nichts geht durch ihr Entfernen verloren: Jede Anfrage, Ablehnung, jeder Erfolg und Fehlschlag ist ein eigener dauerhafter Prüfeintrag, den dies nicht anfasst. Die setup_task_log-Fortschrittszeilen der Aufgabe folgen ihr per Kaskade.

Eine Datenbank ohne Pepsi-Schema wird als leere Warteschlange gemeldet statt als Fehler — sie hat nie eine Aufgabe gehalten —, sodass dies auf einem noch nicht eingerichteten Host gefahrlos ausgeführt werden kann.

Übergeben Sie für die Leerungsmodi ein -c FILE: Der Applier schreibt diese Datei und ihre secrets.d-Fragmente, und der Pfad kommt von seiner eigenen Kommandozeile und nie von irgendetwas, das eine Aufgabe beeinflussen kann. Streng erforderlich ist er nicht — ohne -c gilt die gewöhnliche Standardsuche weiter unten, und der Applier scheitert erst, wenn diese nichts findet —, aber die Datei zu benennen ist der Punkt: Die Standardsuche zieht $XDG_CONFIG_HOME und $HOME heran, und das ist nicht das, was ein als root laufender Applier auflösen sollte. –clear führt nichts aus und braucht daher keine solche Datei.

bootstrap [–valid-for SECS] [–admin-url URL]

Prägt das Einmal-Credential, das das erste Administratorkonto anlegt, und gibt es samt dem curl-Befehl aus, der es verwendet.

Eine frische Installation hat kein Konto, sodass sich nichts an der Konsole anmelden kann, die eines anlegen würde. Dies gibt ein Bearer-Token aus, das den vollständigen Satz an Administrator-Geltungsbereichen hält, SECS lang gültig (Standardwert 3600) und genau einmal akzeptiert — genug für ein einzelnes POST /api/v1/accounts. Es wird bei Vorlage durch eine Aktualisierung verbraucht, die nur eine konkurrierende Anfrage gewinnen kann, sodass ein von zwei Personen gelesenes Token eine davon einlässt.

Die Liste der Geltungsbereiche ist keine Wahl: POST /api/v1/accounts weigert sich, einen Geltungsbereich auszustellen, den der Aufrufer nicht selbst hält, sodass ein Token, das allein setup:write hält, keinen Administrator anlegen könnte — und da das Token verbraucht wird, bevor der Handler ablehnt, würde der Versuch es aufbrauchen. Das ausgegebene curl verlangt genau die Geltungsbereiche, mit denen das Token geprägt wurde, aus derselben Liste gerendert, sodass die beiden nicht auseinanderdriften können.

Einmalig, wegen des Ortes, an dem es ausgegeben wird: Ein Token auf einem Terminal steckt in einem Scrollback-Puffer, und ein Token im Journal ist für jeden lesbar, der das Journal lesen kann. Nur sein Digest wird gespeichert, sodass es nicht wiederhergestellt werden kann — führen Sie den Befehl erneut aus, wenn Sie es verlieren. Ihn erneut auszuführen widerruft außerdem jedes ausstehende Bootstrap-Token.

Ein lokaler Administrator über den ADMIN = yes-UNIX-Socket-Listener wird über SO_PEERCRED identifiziert und braucht überhaupt kein Credential, sodass ein abgelaufenes oder verlorenes Bootstrap-Token eine Unannehmlichkeit ist und keine Aussperrung.

visualize

Gibt die konfigurierte [stage-*]-Pipeline auf stdout als Graphviz-dot-Graphen aus. Jede Stage ist ein Knoten, beschriftet mit ihrem Konfigurationsabschnittsnamen (z. B. stage-init) und dem PROGRAM, das sie ausführt, mit entferntem pepsi-stage--Präfix (z. B. arc). Eine durchgezogene Kante folgt dem NEXT_STAGE jeder Stage und eine gestrichelte rote bounce-Kante ihrem BOUNCE_STAGE. Der Befehl liest nur die Konfiguration (keine DNS-, Schema- oder Dateisystemänderungen); leiten Sie ihn zum Rendern durch dot, zum Beispiel:

pepsi-setup -c /etc/pepsi/pepsi.conf visualize | dot -Tpng -o pipeline.png

85.1.39.1.9. Das Vertrauensmodell des Appliers

pepsi-setup apply ist die eine Komponente in Pepsi, die im Auftrag einer HTTP-Anfrage als root läuft.

85.1.39.1.9.1. Warum die Konsole nicht handelt

pepsi-httpd gibt Privilegien ab, bevor es eine einzige Verbindung annimmt, und darf sie nie zurückerlangen können: Es parst berufsmäßig vom Angreifer gelieferte Eingaben. Es kann daher /etc/pepsi/pepsi.conf nicht schreiben, ein secrets.d-Fragment nicht dem Konto übergeben, das es liest, certbot nicht ausführen, keine Datenbankrolle anlegen und kein Schlüsselmaterial erzeugen — alles Dinge, die das Setup tun muss.

Also versucht es das nicht. Es schreibt einen Datensatz, der sagt, was wahr sein soll, und der Applier entscheidet wie. Root bleibt vollständig vom Netz fern: Es wird über eine Datenbanktabelle erreicht, nicht über einen Socket, der ein Protokoll spricht.

85.1.39.1.9.2. Die geschlossene Aufgabenliste

Es gibt zehn Aufgabenarten, und es wird keine allgemeine geben. Eine Beliebiger-Befehl-Art wäre eine root-Shell über HTTP im Gewand eines Aufgabennamens.

write-config

Rendert die Konfiguration aus einer Antwortmenge — denselben Antworten, die das Interview sammelt —, prüft sie genau so, wie pepsi-setup run es täte, und schreibt dann die Datei und ihre Secret-Fragmente und übergibt jedes Fragment seinem besitzenden Konto. Die Antworten sind die Absicht; die Datei ist das eigene Rendering des Appliers davon. Nichts, was eine Aufgabe liefert, wird wortgetreu geschrieben.

write-secret

Speichert ein Credential im secrets.d-Fragment, das sein Leser besitzt, und bewahrt dabei jedes andere Geheimnis in diesem Fragment. Es lehnt jedes [section] OPTION-Paar ab, das nicht bereits ein von der Secrets-Schicht verwaltetes Credential ist — sonst wäre es ein beliebiges Optionsschreiben in eine root-eigene Datei, die jeder Dienst liest.

obtain-certificate

Beschafft die TLS-Zertifikate, um die die Konfiguration bittet. Benannte Hosts engen ein, was gemeldet wird, nicht, was versucht wird: Eine Aufgabe einen Host einführen zu lassen machte certbots Argumente aufgabengeliefert.

install-schema

Installiert oder migriert das Schema. ``reset`` wird abgelehnt: Das Schema fallen zu lassen zerstört jede eingereihte Nachricht und macht jeden verpackten privaten Schlüssel unöffenbar, was nichts ist, worum ein Webformular bitten darf. Verwenden Sie pepsi-setup run --reset auf einer Konsole.

provision-roles

Legt die Datenbank-Login-Rollen an und wendet ihre Berechtigungen erneut an.

generate-keys

Erzeugt das DKIM-Material je Domain. Eine Aufgabe darf die Domainmenge einengen, nie erweitern: Eine Domain, die diese Installation nicht bedient, bekommt keinen Signierschlüssel.

run-preflight

Führt nur lesende Umgebungsproben aus und hält den Bericht fest. Welche Proben, ist eine Positivliste (ports, dnssec, dns-records), sodass „führe einen Preflight aus“ nicht zu „führe dies aus“ werden kann.

generate-identity

Erzeugt einen vom Server verwalteten OpenPGP-Schlüssel (einen MTA-Schlüssel) für eine Adresse (Parameter address und ein optionales boolesches vks, dessen Standardwert [pepsi-keys] VKS_PUBLISH ist und das ein Hochladen auf einen Schlüsselserver anfordert). Die Adresse muss an einer Domain aus [pepsi-ingress] ACCEPTED_DOMAINS liegen, und ein KEY_WRAP_SECRET muss konfiguriert sein. Wird auf Anforderung immer ausgeführt, auch neben dem eigenen Schlüssel des Benutzers oder einem widerrufenen Schlüssel. Der Applier erledigt die Arbeit als die Rolle pepsi-crypto (root wird für die Verbindung zu diesem Konto, wie es pepsi-keys(1) tut), weil nur diese Rolle die private Spalte schreiben darf.

register-client-key

Registriert den eigenen öffentlichen Schlüssel des Benutzers (einen MUA-Schlüssel, custody = client) für eine Adresse (Parameter address und key, ein öffentlicher OpenPGP-Schlüssel als Text, höchstens 64 KiB). Die Adresse muss bedient werden, der Schlüssel muss ein einzelnes OpenPGP-Zertifikat sein, von dessen User-IDs eine die Adresse nennt, und ein Fingerabdruck, den die Adresse bereits hat, ausgemustert oder nicht, wird nicht erneut registriert. Dies läuft über den Applier, obwohl kein privates Material beteiligt ist: Ein als eigener Schlüssel des Benutzers registrierter Schlüssel wird zum öffentlichen Gesicht der Adresse und verifiziert Signaturen als die des Benutzers, daher darf eine kompromittierte Web-Schicht keinen solchen unterschieben können.

revoke-identity

Widerruft eine lokale Identität (Parameter address, identity_id und ein optionaler einzeiliger reason von höchstens 1024 Bytes, der als Widerrufsgrund festgehalten wird). Die Identität muss zu address gehören. Die Ausmusterungsregel ist die von pepsi-keys identity revoke: Die private Hälfte eines reinen Signaturschlüssels wird vernichtet, die eines Verschlüsselungsschlüssels wird behalten, sodass bereits an ihn verschlüsselte Mail lesbar bleibt. Wird als die Rolle pepsi-crypto ausgeführt, weil das Vernichten einer privaten Hälfte die private Spalte schreibt. Das Widerrufen einer bereits widerrufenen Identität ändert nichts und gelingt; das Ergebnis sagt, was geschehen ist.

reset-otp

Entfernt den zweiten Faktor einer Adresse (Parameter address); so wird auch ein durch zehn falsche Codes gesperrter zweiter Faktor entsperrt, und sein Inhaber registriert sich danach erneut. Ausgeführt als Rolle pepsi-crypto, der einzigen mit einer Berechtigung auf pepsi.otp_key. Das Entfernen eines nicht vorhandenen gelingt und sagt das.

Diese vier wirken auf die Schlüssel einer Adresse statt auf die Installation und werden anders autorisiert (siehe Die zwei Schranken).

Der zweite Faktor des Inhabers. generate-identity, register-client-key und revoke-identity akzeptieren einen optionalen Parameter otp (sechs Ziffern). Für eine allein aufgrund von own:<address> zugelassene Aufgabe – der Inhaber der Adresse fragt, nicht ein Operator mit keys:write – prüft der Applier ihn gegen den zweiten Faktor der Adresse (siehe pepsi-keys(1), otp), bevor er irgendetwas tut: Eine Adresse ohne zweiten Faktor braucht keinen Code, und ein fehlender, falscher, wiederverwendeter oder gesperrter Code lässt die Aufgabe mit dem Grund fehlschlagen. Der Versuch wird festgehalten (ein falscher Code zählt auf die Sperre an), und ein Code ist verbraucht, auch wenn die Aufgabe danach fehlschlägt.

85.1.39.1.9.3. Was bewusst fehlt

Es gibt keine Neustart-, Reload- oder Abschaltaufgabe, und es wird keine geben — dieselbe Entscheidung, die die Dienststeuerung aus der Konsole heraushält. Der Preis ist real: Eine Konfigurationsänderung, die einen Neustart einer Komponente braucht, endet damit, dass der Operator sie neu startet. Wo es möglich ist, greifen Komponenten Änderungen stattdessen selbst auf (die config_changed-Benachrichtigung tut das für die Konfigurations-Überlagerung in der Datenbank).

85.1.39.1.9.4. Die zwei Schranken

Eine Aufgabe wird nur ausgeführt, wenn beides gilt:

  • ihre festgehaltenen scopes setup:write enthalten — die Autorisierung, die die administrative API für den anfragenden Principal festgestellt hat. Für die vier Schlüsselarten generate-identity, register-client-key, revoke-identity und reset-otp ist der erforderliche Geltungsbereich stattdessen keys:write oder – für alle außer reset-otp, das allein dem Operator vorbehalten ist – own:<address> für genau die in den Parametern der Aufgabe genannte Adresse: Ein Benutzer, der seinen eigenen Schlüssel verwaltet, konfiguriert nicht den Server, und setup:write allein genügt nicht. Die Adresse wird den geparsten Parametern entnommen, nie der Liste der Geltungsbereiche, sodass ein auf eine Adresse beschränkter Principal keine andere nennen kann; und

  • ihr written_by ist die Datenbankrolle pepsi-config — der Beweis, dass der Datensatz die Tabelle über den einen Weg erreicht hat, den wir kontrollieren. Diese Spalte wird von einem BEFORE INSERT-Trigger aus current_user erzwungen, sodass sie eine Tatsache über die Verbindung statt einer Behauptung in der Nutzlast ist, und es gibt keine Schreibweise des INSERT, die einen gefälschten Wert daran vorbeibrächte.

pepsi-setup run setzt die zweite Hälfte bei jedem Lauf gegen PostgreSQL durch: Nur pepsi-config darf in setup_task INSERT``en; ``pepsi-httpd darf nur SELECT (es reiht über die separate [pepsi-admin] CONFIG_DB-Verbindung ein); und kein Konto, das Mail verarbeitet, darf die Tabelle überhaupt berühren. Ein Stage-Worker parst berufsmäßig feindliche Mail und darf einem root-Prozess keine Arbeit vorlegen können. Das wird geprüft, nicht behauptet: Eine Abweichung ist ein harter Fehler, der die Rolle und das Privileg nennt.

85.1.39.1.9.5. Was es nicht versprechen kann

Der Applier hat die HTTP-Anfrage nie gesehen, kann den Prinzipal also nicht erneut authentifizieren. scopes ist eine von der administrativen Oberfläche festgehaltene Behauptung; was der Applier prüft, ist, dass die Behauptung von der einzigen Rolle festgehalten wurde, die sie festhalten darf. Eine Kompromittierung von pepsi-httpd zusammen mit seinem Credential für die Konfigurationsdatenbank erreicht daher die obige geschlossene Aufgabenliste. Das ist das Restrisiko, und es ist der Grund, warum die Liste geschlossen und klein statt bequem ist.

85.1.39.1.9.6. Die Fähigkeit entfernen: das Paket pepsi-httpd-admin

Der Applier wird nur je von systemds Socket-Aktivierung auf der Türklingel gestartet, die pepsi-httpd betätigt. Diese beiden Unit-Dateien — pepsi-setup-apply.socket und pepsi-setup-apply.service — sind daher der gesamte Weg von einer HTTP-Anfrage zu einer Änderung unter /etc/pepsi, und Debian liefert sie in einem eigenen Binärpaket aus, pepsi-httpd-admin.

pepsi Recommends es, sodass eine Standardinstallation es hat und die Browser-Konsole wie dokumentiert funktioniert. Ein Operator, der diese Installation vom Terminal aus verwaltet, entfernt es:

apt remove pepsi-httpd-admin

und pepsi bleibt installiert. Eine Quellinstallation hat denselben Hebel als make install INSTALL_ADMIN_UNITS=no.

Was das entfernt, ist der Mechanismus, nicht ein Knopf. Sind die Units fort, startet nichts den Applier, sodass ein setup_task-Datensatz inaktiv ist, wie auch immer er dorthin kam: pepsi-httpd erkennt die fehlende Türklingel und bedient seine Konfigurations- und Einrichtungsseiten nur lesend und weist die entsprechenden API-Änderungen mit 503 setup_applier_unavailable ab — siehe pepsi-httpd(1), Der privilegierte Applier, und ohne ihn auskommen.

pepsi-setup selbst bleibt im pepsi-Paket und ist unberührt. pepsi-setup run, pepsi-setup --wizard, pepsi-setup check und sogar pepsi-setup apply --once funktionieren weiterhin — root, das das Programm ausführt, ist root, das handelt, und das ist nicht das, was dies einschränkt. Was es entfernt, ist die Fähigkeit der Web-Schicht, das geschehen zu lassen.

Bemerkung

Das Entfernen des Pakets widerruft bewusst nicht die Datenbankberechtigung, die der Rolle pepsi-config das INSERT in pepsi.setup_task erlaubt, aus drei Gründen: Ein Maintainer-Skript bräuchte einen erreichbaren Cluster und ein Superuser-Credential, das es nicht hat, sodass ein Härtungsschritt zu einem Entfernungsfehlschlag werden könnte; die Berechtigung ist nicht die Grenze, auf die es ankommt, denn ein Datensatz, den nichts leert, ist inaktiv, und die beiden Schranken des Appliers gelten ohnehin; und eine spätere Neuinstallation käme mit einer Konsole zurück, die auf eine Weise kaputt ist, deren Fehlermeldung auf den Socket statt auf die Berechtigung zeigt.

Ein Standort, der Gürtel und Hosenträger will, kann es von Hand tun, und pepsi-setup run (das die Berechtigungen erneut anwendet) stellt es wieder her:

REVOKE INSERT ON pepsi.setup_task FROM "pepsi-config";

85.1.39.1.9.7. Prüfbarkeit

Jede Aufgabe ist ein dauerhafter Datensatz: wer gefragt hat, was verlangt wurde, wann sie begann und endete, was sie erzeugte und was schiefging. Jede Zulassung, Ablehnung, jeder Erfolg und Fehlschlag wird zusätzlich in das Prüfprotokoll geschrieben (setup.task.requested, setup.task.refused, setup.task.done, setup.task.failed), das für jede Komponente, die Mail verarbeitet, nur anfügbar ist. Fortschrittszeilen werden während der Arbeit in setup_task_log gestreamt, sodass ein certbot-Lauf oder eine Schemainstallation beobachtet werden kann, ohne dass der Applier eine HTTP-Verbindung hält.

Die Schreibvorgänge des Appliers werden angekündigt, sodass niemand, der eine Aufgabe beobachtet, die Datenbank immer wieder fragen muss. Zwei Trigger in procedures.sql benachrichtigen mit der Aufgaben-ID als Nutzlast: setup_task_progress für jede setup_task_log-Zeile und setup_task_done, wenn eine Aufgabe done, failed oder refused wird – welcher Schreiber diesen Übergang auch vollzieht, ob der Applier eine Aufgabe abschließt oder eine aufräumt, die ein früherer Applier als running hinterlassen hat. Der Applier selbst setzt kein pg_notify ab; pepsi-httpd(1) lauscht auf beiden Kanälen und weckt die Anfragen, die auf diese Aufgabe warten (GET /api/v1/setup/tasks/{id}?wait= und die Aufgabenseite der Konsole). Der Kanal setup_task, der den Applier weckt, ist ein anderer und wird von keinem der beiden ausgelöst.

85.1.39.1.10. Globale Optionen

Diese globalen Optionen stehen vor dem Unterbefehl (ein nachgestelltes Flag wird abgelehnt).

-c FILE, –config FILE

Liest die Konfiguration aus FILE statt die Standardorte zu durchsuchen (siehe FILES). pepsi-setup schreibt diese Datei außerdem an Ort und Stelle um, wenn es TLS-Zertifikatspfade, den Reverse-Proxy-Socket, das Herkunftsnachweis-Secret, den Verweis auf den Schlüsselverpackungsschlüssel, die Telemetrie-System-ID und das sondierte [pepsi] MAILBOX_FS_QUOTA automatisch ausfüllt. Wenn -c weggelassen wird, löst es denselben Standardort auf, aus dem die Konfiguration geladen wurde — normalerweise /etc/pepsi/pepsi.conf — und schreibt diesen um, sodass ein bloßes pepsi-setup run sich wie pepsi-setup -c /etc/pepsi/pepsi.conf run verhält. Es meldet den Pfad nur dann als unbekannt, wenn an keinem Standardort eine Konfigurationsdatei existiert.

–no-certbot

Ruft certbot nicht auf, um fehlende TLS-Zertifikate zu beziehen. Das certbot-Pfad-Layout wird bei Bedarf weiterhin in die Konfiguration gefüllt; ein Zertifikat, das dann fehlt, wird aufgeschoben, nicht fatal — der Host wird in der Zusammenfassung am Ende des Laufs mit einer umsetzbaren Meldung aufgeführt, und der Rest des Laufs (Schema, Schlüssel, DNS) fährt fort. Verwenden Sie dies, wenn Zertifikate auf andere Weise verwaltet werden, und beachten Sie, dass ein erfolgreiches Ende daher nicht behauptet, dass jedes konfigurierte Zertifikat vorhanden ist.

–no-reverse-proxy

Integriert sich nicht automatisch mit einem bestehenden Front-HTTP-Server. pepsi-httpd bindet dann Port 443 direkt, statt auf einen UNIX-Socket hinter einem Reverse-Proxy umgestellt zu werden (siehe Schritt 3 der Beschreibung). Verwenden Sie dies, wenn kein anderer Webserver 80/443 belegt oder wenn Sie den Reverse-Proxy von Hand verdrahten.

-y, –yes-to-all

Nimmt für jede interaktive Eingabeaufforderung, die das Setup stellen kann, „ja“ an (derzeit das Angebot, das Dovecot-Drop-in zu installieren, Schritt 4), sodass ein Lauf nie auf Eingabe wartend blockiert — nützlich in Skripten und nicht-interaktiven Installationen. Schließt sich mit -n gegenseitig aus.

-n, –no-to-all

Nimmt für jede interaktive Eingabeaufforderung „nein“ an: Das Setup führt keine angebotene Aktion aus und gibt stattdessen aus, was es getan hätte (z. B. das von Hand auszurollende Dovecot-Drop-in), und schiebt es dann auf. Macht den Lauf ebenfalls vollständig nicht-interaktiv.

–wizard

Führt den interaktiven Konfigurationsassistenten aus (siehe Assistent). Die Konfiguration wird in den -c-Pfad geschrieben oder nach /etc/pepsi/pepsi.conf, wenn kein -c angegeben ist. Anders als die anderen Modi erfordert dies keine bestehende Konfigurationsdatei. Er nimmt keinen Unterbefehl (pepsi-setup --wizard run wird zurückgewiesen): Am Ende bietet er an, das vollständige Setup selbst auszuführen. Die unten stehenden Optionen, die „mit –wizard“ sagen, werden ohne es zurückgewiesen, außer --expert=help.

–force

Überschreibt mit –wizard eine bestehende Konfigurationsdatei, die keine importierbaren [pepsi-wizard]-Antworten hat, ohne um Bestätigung zu bitten.

–expert SPEC

Fragt mit –wizard auch nach den tieferliegenden Pepsi-Optionen, die das Interview normalerweise für Sie entscheidet. SPEC ist eine Gruppe (high, insane), eine kommagetrennte Liste von Optionsnamen oder beides; --expert=help listet sie auf und beendet sich. Siehe Experten-Optionen.

–answers FILE

Beantwortet mit –wizard jede Frage aus dem JSON-Objekt in FILE, statt zu fragen: Die Schlüssel sind die Frage-Kennungen, die pepsi-setup questions ausgibt (plus die Namen der Experten-Optionen), und eine Frage, die die Datei nicht beantwortet, nimmt den Standardwert des Assistenten an, wie es das Drücken der Eingabetaste täte. Ein unbekannter Schlüssel oder eine Antwort der falschen Form ist ein Fehler. Von stdin wird nichts gelesen, und auch jede andere Eingabeaufforderung nimmt ihren Standardwert an — insbesondere das abschließende Angebot „Run setup now“, führen Sie daher danach pepsi-setup run aus. Siehe Ohne Terminal antworten.

–import MTA

Importiert mit –wizard Standardwerte aus diesem bestehenden MTA (postfix, exim, sendmail, qmail, stalwart), statt ein Menü des Erkannten anzubieten. Anders als die automatische Erkennung gilt dies auch, wenn bereits eine Konfigurationsdatei existiert, und es funktioniert bei nicht-interaktivem stdin. Siehe Migration von einem anderen MTA.

–no-import

Sucht mit –wizard überhaupt nicht nach einer bestehenden MTA-Konfiguration.

–import-root DIR

Liest mit –wizard den zu importierenden MTA unterhalb von DIR statt von / — eine Sicherung oder die an Ort und Stelle kopierte Konfiguration einer anderen Maschine. Dieselbe Option, die der import-Unterbefehl –root nennt.

-L LOGLEVEL, –log LOGLEVEL

Setzt die Log-Ausführlichkeit. LOGLEVEL ist eines von error, warn, info, debug oder trace (Standardwert: info).

-v, –verbose

Zeigt Log-Meldungen aus allen Quellen, einschließlich Drittanbieter-Bibliotheken.

-h, –help

Gibt eine Verwendungsübersicht aus und beendet sich.

-V, –version

Gibt die Version aus und beendet sich.

85.1.39.1.11. Exit-Status

0

Erfolgreicher Abschluss.

1

Ein Fehler ist aufgetreten: eine fehlerhafte Konfigurationsdatei, ein ungültiger Domainname oder PUBLIC_IP-Eintrag, eine Konfigurationsdatei, die nicht geschrieben werden konnte, eine fehlgeschlagene Datenbankverbindung oder ein Schlüssel, der nicht geschrieben werden konnte. Der Grund wird in das Journal geschrieben.

Ein TLS-Zertifikat, das fehlt und nicht bezogen werden konnte, steht nicht auf dieser Liste: Es wird aufgeschoben und in der Zusammenfassung am Ende des Laufs gemeldet (Schritt 4), und der Lauf gelingt dennoch.

85.1.39.1.12. Dateien

Wenn –config nicht angegeben ist, wird die erste vorhandene Datei aus der folgenden Liste verwendet:

  • $XDG_CONFIG_HOME/pepsi.conf

  • $HOME/.config/pepsi.conf

  • /etc/pepsi/pepsi.conf

  • /etc/pepsi.conf

Beachten Sie die letzten beiden: Jedes Pepsi-Programm bevorzugt das kanonische /etc/pepsi/pepsi.conf gegenüber dem bloßen /etc/pepsi.conf, weil die Paketierung, die systemd-Units und @inline-secret@ allesamt das Unterverzeichnis benennen — eine veraltete Kopie direkt in /etc darf die Datei, die die laufenden Dienste lesen, nicht verdecken. Existiert mehr als eine davon, protokolliert pepsi-setup, welche Datei es verwendet und welche ignoriert werden.

Erzeugtes Schlüsselmaterial wird unterhalb des konfigurierten KEY_DIR gespeichert (Standardwert /var/pepsi/keys), ein Verzeichnis pro Domain, das dkim.rsa.key und dkim.ed25519.key enthält.

Neben der Konfigurationsdatei schreibt –wizard aliases (die Alias-Map, umgewandelt aus den Routing-Tabellen des vorherigen MTA, wenn einer importiert wurde), username.map (die Submission-Identitäts-Map), secrets.d/*.secret (die externalisierten Geheimnisse) und, nach einer Migration, import-report.txt. Eine bereits bestehende Datei wird von einem Import nie überschrieben: Der umgewandelte Inhalt wird stattdessen nach <name>.imported geschrieben.

85.1.39.1.13. Beispiele

Eine frische Installation bootstrappen und die zu veröffentlichenden DNS-Einträge erfassen:

pepsi-setup -c /etc/pepsi/pepsi.conf run > pepsi-dns.zone

Nach einem Upgrade erneut ausführen, das neue Migrationen mitliefert (Schlüssel und DNS bleiben unverändert, sofern keine neue Domain hinzugefügt wurde):

pepsi-setup -c /etc/pepsi/pepsi.conf run

Die Konfiguration validieren und die Datenbank von Grund auf zurücksetzen:

pepsi-setup -c /etc/pepsi/pepsi.conf run --reset

Nach dem Veröffentlichen (oder Ändern) von DNS das tatsächlich Veröffentlichte gegen das überprüfen, was Pepsi erwartet:

pepsi-setup -c /etc/pepsi/pepsi.conf check

Die Stage-Pipeline in ein PNG rendern, um zu überprüfen, wie Nachrichten geroutet werden:

pepsi-setup -c /etc/pepsi/pepsi.conf visualize | dot -Tpng -o pipeline.png

Vor einer Migration sehen, was vom heute auf diesem Host laufenden Mailserver übernommen würde (es wird nichts geschrieben):

pepsi-setup import

Von Postfix migrieren und dabei auch die tieferliegenden Fragen beantworten:

pepsi-setup --wizard --import postfix --expert=high

Inspizieren, was eine Migration aus dem unter /mnt/oldhost gespeicherten /etc einer anderen Maschine erzeugen würde:

pepsi-setup import postfix --root /mnt/oldhost --out /tmp/migration

85.1.39.1.14. Siehe auch

pepsi-config(1), pepsi.conf(5), pepsi-ingress(1), pepsi-stage-relay-to-smarthost(1), pepsi-keys(1), pepsi-keydisc(1)

85.1.39.1.15. Fehler

Melden Sie Fehler an den Pepsi-Issue-Tracker.