85.1.3. pepsi-httpd¶
serve MTA-STS policy, Web Key Directory, the Outlook add-in and metrics
- Handbuchabschnitt:
1
85.1.3.1.1. Name¶
pepsi-httpd - HTTP/HTTPS-Server für MTA-STS, das Web Key Directory, das Outlook-Add-in und Metriken.
85.1.3.1.2. Übersicht¶
pepsi-httpd [GLOBAL-OPTIONS] serve
pepsi-httpd [GLOBAL-OPTIONS] prune
85.1.3.1.3. Beschreibung¶
pepsi-httpd ist der HTTP/HTTPS-Server von Pepsi. Er bindet einen oder mehrere Listener und routet jede Anfrage durch eine generische Dispatch-Tabelle, wobei er nach HTTP-Methode und URL-Form abgleicht: Der Pfad einer Route ist eine Liste von Segmenten, deren jedes ein Literal, eine benannte Erfassung eines Segments oder eine Erfassung des gesamten Rests ist. Routen werden in Registrierungsreihenfolge probiert, und die erste, deren Methode und Pfad passen, gewinnt. Weitere Endpunkte werden als einzelne Tabelleneinträge hinzugefügt.
Jeder [pepsi-httpd-listener-<name>]-Abschnitt bindet einen Socket — SERVE = tcp (BIND_TO/PORT, Standardport 443), unix (UNIXPATH) oder systemd (Socket-Aktivierung) — mit MODE = plain oder tls. Ein TLS-Listener wählt sein Zertifikat pro Verbindung anhand des SNI-Hostnamens des Clients: Jeder [pepsi-httpd-cert-<name>]-Abschnitt führt einen oder mehrere SNI-Hostnamen mit einem TLS_CERT/TLS_KEY-Paar auf, und das eigene TLS_CERT/TLS_KEY des Listeners (falls vorhanden) ist der Rückfall für Verbindungen, die kein passendes SNI vorlegen.
Wenn bereits ein anderer Webserver die Ports 80/443 besitzt, konfiguriert pepsi-setup(1) stattdessen eine Reverse-Proxy-Installation. Der Listener bleibt socket-aktiviert (SERVE = systemd), aber Klartext-HTTP (MODE = plain); der Wechsel geschieht stattdessen in der pepsi-httpd.socket-Unit: pepsi-setup legt ein Drop-in-Override (/etc/systemd/system/pepsi-httpd.socket.d/10-reverse-proxy.conf) ab, das das ausgelieferte ListenStream=443 zurücksetzt und es an einen UNIX-Socket unter /run/pepsi/httpd.sock neu bindet (Modus 0660, im Besitz der eigenen Gruppe des Frontservers — www-data, wo es diese Gruppe gibt, sonst nginx/apache/httpd), sodass systemd den fd dieses Sockets genau so an pepsi-httpd übergibt, wie es den Port-443-Socket übergeben würde. Der Frontserver terminiert TLS und leitet die mta-sts.<domain>-Anfragen an ihn weiter; in diesem Modus hält pepsi-httpd keine eigenen Zertifikate. Das Löschen des Drop-ins und das Ausführen von systemctl daemon-reload stellt die direkte :443-Bindung wieder her. Siehe pepsi-setup(1) und --no-reverse-proxy.
85.1.3.1.4. Endpunkte¶
- GET /.well-known/mta-sts.txt
Gibt die MTA-STS-Richtlinie (RFC 8461) zurück, gebaut aus den
[pepsi]-MTA_STS_*-Optionen und dem[pepsi-ingress]-HOSTNAME(demmx). Die Richtlinie wird nur bereitgestellt, wenn derHostder Anfragemta-sts.<domain>für eine Domain inACCEPTED_DOMAINSist; jeder andere Host (oderMTA_STS_MODE = none) ergibt404. Sie hier bereitzustellen erspart das händische Hosten der Richtliniendatei; pepsi-setup(1) gibt den_mta-sts-TXT-Eintrag zur Veröffentlichung im DNS aus.- GET /mail/config-v1.1.xml
- GET /.well-known/autoconfig/mail/config-v1.1.xml
Liefert das Dokument zur Autokonfiguration von Mailkonten (draft-ietf-mailmaint-autoconfig): das XML, das ein Mail-Client abholt, wenn er nur die Adresse des Benutzers kennt, um herauszufinden, welche Server zu verwenden sind, auf welchen Ports, unter welcher Transportsicherheit und mit welcher Authentifizierung.
Dies sind die ersten beiden Sprossen der Rückfallkette, die der Draft definiert, und der
Hostwählt zwischen ihnen: Die erste wird bedient, wenn der Anfrage-Hostautoconfig.<domain>ist (die verpflichtende Sprosse und die, die Clients zuerst versuchen), die zweite, wenn er<domain>selbst ist. In beiden Fällen muss DOMAIN inACCEPTED_DOMAINSstehen; jeder andere Host ergibt404. Der optionale?emailaddress=-Parameter des Drafts wird angenommen und ignoriert — das Dokument nennt%EMAILADDRESS%, den Platzhalter, den der Client ersetzt, sodass nie anfragegesteuerter Text in die Antwort interpoliert wird.Die Antwort ist
text/xml; charset=utf-8, eine Stunde lang cachefähig und — wie der Draft es verlangt — öffentlich: Sie trägt keine Authentifizierung, weil ein Client sie lesen muss, bevor er wissen kann, wie er sich authentifiziert.Das Dokument wird aus
[pepsi-autoconfig]gebaut, und der Endpunkt antwortet mit404, bis dieser Abschnitt mindestens einen eingehenden Server benennt (IMAP_HOSToderPOP3_HOST). Der ausgehende Server wird aus dem[pepsi-ingress-listener-*]mit dem KennzeichenSUBMISSION = yesabgeleitet, sofernSMTP_HOSTihn nicht überschreibt. Die Veröffentlichung erfordert einenautoconfig.<domain>-DNS-Eintrag und ein Zertifikat, das ihn abdeckt; siehe pepsi.conf(5).- GET /.well-known/openpgpkey/hu/HASH
- GET /.well-known/openpgpkey/policy
- GET /.well-known/openpgpkey/DOMAIN/hu/HASH
- GET /.well-known/openpgpkey/DOMAIN/policy
Das Web Key Directory (draft-koch-openpgp-webkey-service), sowohl in seiner direkten Form (unter der Domain selbst bedient) als auch in seiner erweiterten Form (unter
openpgpkey.<domain>bedient, mit der im Pfad wiederholten Domain). HASH ist der z-base-32-SHA-1 des kleingeschriebenen lokalen Teils, der neben der Domain gespeichert und indiziert wird, sodass eine Anfrage eine indizierte Abfrage kostet.Ein Schlüssel wird nur für eine Domain in
ACCEPTED_DOMAINSund nur aus einer Identität zurückgegeben, diepublished,activeund OpenPGP ist. Die Antwort ist der binäre übertragbare öffentliche Schlüssel — nicht Armor — mitContent-Type: application/octet-streamundAccess-Control-Allow-Origin: *, wie die Spezifikation es verlangt. Ein unbekannter Hash ergibt404mit leerem Nachrichtentext.Die
policy-Datei ist ein200mit einem Nachrichtentext der Länge null. Sie trägt keine Flags, aber sie muss existieren: GnuPG deutet ihr Fehlen als „diese Domain betreibt kein Web Key Directory“ und gibt auf, bevor es nach einem Schlüssel fragt.Der Parameter
?l=<local-part>wird gelesen und ignoriert. Ihn zu beachten würde den Endpunkt zu einer Abfrage nach einer vom Aufrufer gelieferten Adresse machen statt nach einem Hash, den der Aufrufer bereits kennen musste.Der Endpunkt bedient nur die eigenen veröffentlichten Identitäten dieser Installation (
crypto_identity). Er bedient nie einen zwischengespeicherten Korrespondentenschlüssel (peer_key): Dieses Material wurde nie von uns verifiziert, und es steht uns nicht zu, es unter unserem eigenen Namen zu veröffentlichen. Es gibt keine Option, das zu ändern.Es gibt hier bewusst keine Ratenbegrenzung und keine einheitliche 404-Formung. Ein Web Key Directory ist konstruktionsbedingt ein öffentliches Orakel, der Hash deckt nur den lokalen Teil ab (er beantwortet also Rateversuche, statt aufzuzählen), und die Adressen stehen außen auf jeder Nachricht, die die Domain versendet. Siehe pepsi-keys(1) und das Kapitel zur Schlüsselverwaltung im Handbuch.
Für die erweiterte Form muss
openpgpkey.<domain>auf diesen Host auflösen und das ausgelieferte Zertifikat den Namen abdecken; es ist ein SNI-Name auf demselben HTTPS-Listener, kein zweiter Listener. pepsi-setup(1) fügt ihn der certbot-Anforderung hinzu und meldet jeden, der nicht auflöst.- GET /addin/manifest.xml
- GET /addin/taskpane.html
Das Outlook-Add-in: ein Manifest und ein einseitiger Aufgabenbereich, die einem Benutzer eines Mailsystems hinter diesem Gateway erlauben, für eine Nachricht Signierung oder Verschlüsselung anzufordern. Der Bereich setzt
X-Pepsi-Sign/X-Pepsi-Encryptauf der gerade verfassten Nachricht; pepsi-stage-encrypt(1) liest sie und entfernt sie, bevor die Nachricht auf die Leitung geht.Beide Routen ergeben
404, sofern[pepsi-httpd] ADDINnicht gesetzt ist. Zwei Platzhalter werden je Anfrage ersetzt: der öffentlichehttps://-Origin dieses Gateways (ausADDIN_URL, sonst demHostder Anfrage; das Schema ist immerhttps, weil Outlook sich weigert, Add-in-Ressourcen über einfaches HTTP zu laden – ein konfigurierterhttp://-Origin wird beim Start abgelehnt, es sei denn, sein Host ist Loopback, was für lokale Tests erlaubt ist) und ein aus diesem Origin abgeleiteter Manifest-Bezeichner — stabil für eine Installation und zwischen Installationen verschieden, sodass zwei per Sideloading in eine Exchange-Organisation eingebrachte Gateways nicht kollidieren. EinHost, der irgendetwas anderes enthält, als ein Hostname und Port enthalten dürfen, wird mit400abgelehnt statt maskiert.Die Verteilung erfolgt per Sideloading: Der Exchange-Administrator richtet „Integrierte Apps“ auf die Manifest-URL. Siehe das Kapitel „Microsoft Exchange als Gateway“ im Handbuch.
- GET /metrics
Pipeline-Statistiken im Prometheus-Text-Expositionsformat. Live-Anzeigen (
pepsi_stage_active_messages,pepsi_pause_backlog) werden direkt aus der Warteschlange gelesen; Zähler (pepsi_stage_timeouts_total,pepsi_stage_crashes_total,pepsi_stage_messages_total,pepsi_stage_duration_seconds_totalund die globalenpepsi_stages_executed_total/pepsi_messages_processed_total) stammen aus den Statistiktabellen, die pepsi-dispatch(1) aktualisiert.Der Endpunkt ist administrativ: Warteschlangentiefen, Absturz- und Timeout-Zahlen je Stage, Gesamtsummen über die Lebensdauer und jeder vom Operator gewählte Stage-Name beschreiben zusammen, wie viel Mail diese Installation trägt und wie ihre Pipeline gebaut ist. Er wird daher nur auf einem Listener mit dem Kennzeichen
ADMIN = yesbedient, der die administrative Oberfläche tatsächlich tragen darf, und antwortet überall sonst mit einem schlichten404— dem, was jeder unbekannte Pfad erhält. Anders als/api/v1verlangt er kein Credential, weil ein Prometheus-Scraper keines vorzulegen hat: Das Listener-Kennzeichen ist die gesamte Zugriffskontrolle, kennzeichnen Sie also nur einen Listener, den allein das Überwachungssystem erreichen kann.Richten Sie den Scraper auf den administrativen Listener, oder ergänzen Sie
ADMIN = yesbei dem Listener, den er bereits abfragt (ein Klartext-Listener muss Loopback oder ein UNIX-Socket sein — siehe Die administrative Oberfläche unten). pepsi-httpd selbst an eine private Adresse zu binden ist keine Alternative: Derselbe Prozess mussmta-sts.<domain>(RFC 8461) undopenpgpkey.<domain>aus dem öffentlichen Internet beantworten, und es gibt keine Listener-Bindung je Route. Die erste Abfrage, die abgelehnt wird, weil ihr Listener nicht gekennzeichnet ist, wird mit dem Namen des Listeners im Journal vermerkt.- POST /resume
Gibt eine pausierte Nachricht zurück in die Pipeline frei: Der passende Datensatz wird von
pausedaufpendinggesetzt und der Dispatcher benachrichtigt, sodass die zuständige Stage erneut läuft. Dies ist das Ziel des GNU-Taler-pepsi-resume-Zahlungs-Webhooks (siehe pepsi-setup(1) und[pepsi-payments]), der aufgerufen wird, wenn eine Bestellung bezahlt ist.Die Anfrage muss
Authorization: Bearer <token>tragen, das zum konfiguriertenRESUME_AUTHORIZATION_TOKENpasst (in konstanter Zeit verglichen), und einen JSON-Nachrichtentext{"message_id": "<token>"}, der das externe Token der Nachricht (die Händler-order_id) benennt. Antworten:200, wenn die Nachricht existiert (eine pausierte Nachricht wurde fortgesetzt, oder sie war bereits nicht pausiert — der Aufruf ist idempotent),404, wenn das Token unbekannt ist,401bei einer fehlgeschlagenen Autorisierung,400bei einem fehlerhaften Nachrichtentext,413bei einem Nachrichtentext über 4 KiB. Der Endpunkt ist deaktiviert (404), wennRESUME_AUTHORIZATION_TOKENnicht konfiguriert ist.- /api/v1/…
Die administrative API — die Warteschlange, die Gesundheitszusammenfassung, die Konfiguration, der Schlüsselspeicher, das Prüfprotokoll. Nur auf einem Listener mit dem Kennzeichen
ADMIN = yesbedient, und nur einem authentifizierten Prinzipal. Siehe Die administrative Oberfläche unten und das Kapitel „Die administrative API“ im Handbuch für die Endpunktreferenz, die Tabelle der Geltungsbereiche und die Fehlerform.- /ui, /ui/…
Die administrative Konsole: ein serverseitig gerendertes Browser-Front-End für die Warteschlange, den Schlüsselspeicher, die Konfiguration und die Journale. Auf denselben
ADMIN = yes-Listenern bedient wie/api/v1, unter derselben Authentifizierung, denselben Prüfungen der Geltungsbereiche und demselben Prüfprotokoll — sie ist ein Client der API und fügt ihr keine Fähigkeit hinzu. Die Seiten sind/ui(Dashboard),/ui/login,/ui/logout,/ui/queue,/ui/queue/ID,/ui/queue/ID/{requeue,bounce,cancel},/ui/identities,/ui/identities/ID,/ui/identities/ID/{publish,unpublish,vks,primary,revoke,delete},/ui/identities/request/{generate,register},/ui/peers,/ui/peers/ID/delete,/ui/ca-trust,/ui/ca-trust/ID/delete,/ui/config,/ui/config/SECTION,/ui/logs,/ui/logs/{mail,tls,dns},/ui/domains,/ui/domains/check,/ui/secure,/ui/secure/TOKEN,/ui/secure/TOKEN/ACTION,/ui/setup,/ui/setup/STEP (GET und POST),/ui/setup/tasks(GET und POST),/ui/setup/tasks/ID und das einzelne Stylesheet/ui/static/console.css.Warten auf eine Setup-Aufgabe.
GET /api/v1/setup/tasks/ID nimmt?wait=SECONDS (höchstens 60, kombinierbar mit?since=SEQ) und antwortet, sobald die Aufgabe beendet ist oder eine Fortschrittszeile nach SEQ hat, oder wenn die Zeit abgelaufen ist; die Aufgabenseite der Konsole wartet auf dieselbe Weise bis zu 20 Sekunden je Neuladen. Keines von beiden fragt die Datenbank zyklisch ab: Der Server hält eineLISTEN-Verbindung auf den Kanälensetup_task_doneundsetup_task_progress, auf denen die Schreibvorgänge des Appliers mit der Aufgaben-ID benachrichtigen, und weckt die Anfragen, die auf diese Aufgabe warten. Die Verbindung ist vom Anfrage-Pool getrennt und verbindet sich mit wachsender Verzögerung selbst neu; solange sie unterbrochen ist, kehrt ein Warten sofort zurück, statt zu hängen, und die Konsolenseite fällt darauf zurück, sich alle fünf Sekunden neu zu laden.Der Telemetrie-Schalter. Die Frage
SHARE_TELEMETRYdes Interviews kann nur mit ja beantwortet werden, solange pepsi-telemetry-client(1) läuft (ruhend, solange Telemetrie ausgeschaltet ist) und[pepsi] SYSTEM_IDkonfiguriert ist, denn dieser Server erzeugt nie eine Kennung, und ein ja ohne Daemon, der danach handelt, bewirkte nichts. Beides erfährt er aus der Lebendigkeitszeile des Daemons inpepsi.telemetry_client, die er lesen, aber nicht schreiben darf und die für die Kennung einen Wahrheitswert trägt, nie ihren Wert. Andernfalls wird das Kontrollkästchen deaktiviert mit Hinweisen dargestellt (die Unit starten; eineSYSTEM_IDhinzufügen),GET /api/v1/setup/questionskennzeichnet die Frage mit"disabled": trueund einemdisabled_reason, und ein ja überPUT /api/v1/setup/answersoder einewrite-config-Aufgabe wird mit409 telemetry_client_not_readyabgelehnt.GET /api/v1/setup/telemetrymeldet denselben Zustand (sharing,can_enable,reason,client). Das Ausschalten der Telemetrie wird nie abgelehnt. Daswrite-configdes Appliers benachrichtigt den Daemon nach dem Schreiben der Datei, in beide Richtungen.Eine Pfad-Positivliste eines Reverse-Proxys muss auch die Familien
/ui/setup*und/ui/secure*einschließen: die erste ist das gesamte Setup-Interview im Browser, die zweite sind die Verwaltungsseiten für Secure-Link.Die Konsole liefert kein JavaScript und lädt nichts von einem anderen Host; jede Aktion ist ein Formular, jede zerstörerische wird bestätigt, und jedes verändernde Formular trägt das CSRF-Token der Sitzung als verstecktes Feld (eine verändernde Anfrage, deren
Origineinen anderen Host benennt, wird rundweg abgelehnt). Sie übt keine Dienststeuerung aus — es gibt bewusst keinen Neustart-, Abschalt- oder Sicherungsknopf. Siehe das Kapitel „Die administrative Konsole“ im Handbuch.- /3.0/…, /3.1/…
Die REST-API von GNU Mailman 3 – upstream Version 3.3.10, nachgebaut, damit für GNU Mailman 3 geschriebene Software (
mailmanclient, Postorius, HyperKitty) unverändert gegen Pepsi läuft. Wird nur auf einem Listener mit dem FlagLIST_API = yesangeboten, unter derselben Bindungsregel wieADMIN(Klartext auf Loopback, ein Unix-Socket oder TLS), und mit HTTP Basic gegen das einzige Paar[pepsi-list]API_USER/API_PASSauthentifiziert. Das ist nicht/api/v1: anderes Publikum, anderer Sammlungsrahmen, andere Fehlerform, keine Scopes. Siehe das Kapitel „Die REST-API von GNU Mailman 3“ im Handbuch.LIST_API_TESTING = yesbewaffnet zusätzlichGET /3.1/reserved/reset, das jede Mailinglisten- und Archivtabelle leert. Es existiert für die Kompatibilitätssuiten und darf auf einer Installation mit echter Post nicht gesetzt werden.- GET /favicon.ico
- GET /favicon-VERSION.svg
Das Pepsi-Abzeichen als Browser-Icon, ausgeliefert auf jedem Listener, gleich mit welchen Flags: Ein Icon verrät nichts über die Installation. Die Konsole, ihre Anmeldeseite und die Mailinglisten-Seiten verlinken das SVG, dessen Name den Anfang seines SHA-256 trägt; da ein neues Icon eine neue URL ist, wird es mit
Cache-Control: public, max-age=31536000, immutablegesendet./favicon.ico(16, 32 und 48 px) ist das, was ein Browser von sich aus für eine Seite abruft, die kein Icon verlinkt; seine URL kann sich nicht ändern, daher ist es eine Woche lang cachebar. Beide tragen einETagund beantworten ein passendesIf-None-Matchmit304. Die Dateien sind in das Binary einkompiliert.- /lists, /lists/…, /archives/list/…, /robots.txt
Die öffentliche Mailinglisten-Weboberfläche: das Listenverzeichnis, die Informationsseite einer Liste, die An- und Abmeldeformulare, die Bestätigungsseiten, das Ein-Klick-Abmeldeziel nach RFC 8058, das Archiv (in den URL-Formen von HyperKitty, sodass die
Archived-At:-Links einer migrierten Installation weiter funktionieren) und seine Suche. Wird nur auf einem Listener mit dem FlagLISTS = yesangeboten, für jeden, ohne Zugangsdaten.Dies ist das eine Flag, dessen Auslieferungsrat dem der beiden anderen entgegengesetzt ist.
ADMINist für den Betreiber undLIST_APIträgt ein gemeinsames Passwort, beide weigern sich daher, dort angeboten zu werden, wo ihre Zugangsdaten ein Klartextnetz überqueren würden; diese Oberfläche existiert, um aus dem offenen Internet erreicht zu werden, diese Einschränkung wird auf sie also absichtlich nicht angewandt. Ein Klartext-LISTS-Listener ist die Wahl des Betreibers und erhält eine Protokollzeile statt einer Weigerung – aber ein Anmeldeformular trägt die Adresse eines Menschen, legen Sie es also auf einen TLS-Listener.Diese Seiten liefern kein JavaScript aus, und ihre Content-Security-Policy hat infolgedessen überhaupt kein
script-src./robots.txterlaubt das Archiv und verbietet die Suche, also die eine Route, die je Anfrage eine Volltextabfrage ausführt; die Suche ist zusätzlich auf ihrem eigenen Budget ratenbegrenzt, denn ein Crawler, der die Datei ignoriert, muss dennoch überlebbar sein.Beide Budgets sind Anfragen pro Minute je Quelladresse (ein IPv6-Client je
/64) und werden aus dem Abschnitt[pepsi-list]gelesen:- WEB_RATE_LIMIT
(Ganzzahl, optional) Jede Route dieser Oberfläche und der Mitgliederebene unten. Standardwert
600.- WEB_SEARCH_RATE_LIMIT
(Ganzzahl, optional) Die Such-Route, zusätzlich zum obigen. Standardwert
30.
Ein Wert unter
1wird auf1angehoben: keines von beiden lässt sich abschalten. Hinter einem Reverse-Proxy kommt jede Anfrage über den UNIX-Socket ohne Client-Adresse an, sodass sich alle Clients ein Budget teilen; heben Sie dort die Grenzen an und lassen Sie den Proxy je Client begrenzen.Dasselbe Flag bietet auch die Mitgliederebene an –
/lists/register,/lists/verify/<token>,/lists/sign-in,/lists/sign-out,/lists/resetund/lists/me– sowie die Konsole für Verwalter und Moderatoren unter/lists/<list-id>/admin.... Keines von beiden ist ein zweites Flag: ein Kontosystem, das niemand erreichen kann, ist keine Auslieferungsentscheidung, die jemand träfe.Diese Seiten benutzen
pepsi.list_sessionund die Cookiespepsi_list_session/pepsi_list_csrf, die nicht diepepsi_session/pepsi_csrfder Betreiberkonsole sind und dort nichts gewähren – und umgekehrt ebenso nicht. Befugnis über eine Liste ist eine Abfrage der Mitgliederliste und kein Kontoflag: einlist_member-Datensatz mitrole = ownerodermoderatorfür diese Liste, dazulist_user.is_server_ownerals einzige globale Befugnis auf dieser Ebene. Ein Aufrufer ohne sie erhält die gewöhnliche Nicht-gefunden-Seite, denn auf einer öffentlichen Oberfläche hat eine Ablehnung, die sich unterscheidet, verraten, dass die Sache existiert. Siehe den Abschnitt „Zwei Kontosysteme“ im Handbuch.
85.1.3.1.5. Die administrative Oberfläche¶
Ein Listener mit ADMIN = yes bedient zusätzlich /api/v1, die /ui-Konsole und /metrics. Auf jedem anderen Listener antworten diese Routen mit einem schlichten 404, byte-für-byte demselben, den jeder unbekannte Pfad erhält, sodass den öffentlichen Listener zu veröffentlichen nicht die Administration veröffentlicht und ein öffentlicher Listener nicht daraufhin abgetastet werden kann, ob die Administration auf dieser Installation aktiviert ist.
/api/v1 und /ui authentifizieren und autorisieren zusätzlich jede Anfrage, wie unten beschrieben. /metrics tut das nicht: Ein Scraper hat kein Credential vorzulegen, das Listener-Kennzeichen ist daher alles, was davor steht.
pepsi-httpd weigert sich, sie auf einem gekennzeichneten Listener zu bedienen, der sie im Klartext von diesem Host wegtragen würde: Klartext-TCP wird nur auf einer Loopback-Adresse angenommen, während TLS-Listener und UNIX-Sockets stets in Frage kommen. Ein socket-aktivierter Listener (SERVE = systemd) kommt ohne TLS nie in Frage, was auch immer seine Unit bindet — auch ein ListenStream= auf Loopback oder auf einem UNIX-Pfad —, weil die Adresse des geerbten Deskriptors von hier aus nicht sichtbar ist und ihn als zulässig zu behandeln den strengsten Fall durch die lockerste Prüfung ließe. Da die ausgelieferte Installation socket-aktiviert ist, will die Administration einen eigenen Listener (einen UNIX-Socket oder einen mit TLS). Ein Listener, der die Prüfung nicht besteht, schreibt beim Start eine Warnung ins Journal und bedient nur die öffentlichen Endpunkte; pepsi-setup(1) meldet dasselbe zur Konfigurationszeit.
Drei Authentifizierungsmechanismen lösen sich zu einem Identitätsmodell auf, in dieser Reihenfolge probiert — ein ausdrücklich vorgelegtes Credential gewinnt immer, sodass ein bewusst eng gefasstes Token nie stillschweigend erweitert wird:
Authorization: Bearer pepsi_<id>.<secret>— ein Datensatz inpepsi.api_token. Nur der Digest der geheimen Hälfte wird gespeichert.Ein Sitzungs-Cookie aus
POST /api/v1/auth/login— oder aus dem eigenen FormularPOST /ui/loginder Konsole, das dieselbe Sitzung prägt —, mit einem bei jeder verändernden Anfrage erforderlichen CSRF-Token. Sitzungen haben standardmäßig eine Leerlaufzeitüberschreitung von 30 Minuten und eine harte Lebensdauer von 12 Stunden ([pepsi-admin] SESSION_IDLEundSESSION_LIFETIME).SO_PEERCREDauf einem UNIX-Socket-Listener:rootoder ein Mitglied von[pepsi-admin] ADMIN_GROUPist Administrator ganz ohne Credential. Das ist es, was den Bootstrap beim ersten Lauf funktionieren lässt und worauf sich die ausgelieferte Konfiguration stützt.
PAM wird bewusst nicht unterstützt: Es würde einen privilegierten Authentifizierungspfad und Systemkonto-Semantik in die Web-Schicht des Mailservers verlegen.
Die Autorisierung erfolgt über Geltungsbereiche, je Endpunkt deklariert (config:read, config:write, keys:read, keys:write, peers:write, queue:read, queue:write, logs:read, setup:write, secure:read, secure:write, dazu own:<address> für einen auf eine Adresse beschränkten Prinzipal). GET /api/v1/openapi.json wird aus der eigenen Routentabelle des Servers erzeugt und ist die maßgebliche Liste für einen gegebenen Build.
secure:read und secure:write sind getrennt, weil das Widerrufen einer Secure-Link-Nachricht deren einzige Kopie zerstört; eine unwiderrufliche Löschung gehört nicht hinter eine Fähigkeit namens „read“.
Schlüsselmaterial wird hier nie erzeugt oder widerrufen: privates Material gehört allein der Datenbankrolle pepsi-crypto. Einen servergeführten Schlüssel zu erzeugen (POST /api/v1/identities), den eigenen öffentlichen Schlüssel eines Benutzers zu registrieren (POST /api/v1/identities/client) und eine Identität zu widerrufen (PATCH /api/v1/identities/{id} mit {"status": "revoked"} und einem optionalen revocation_reason, was die private Hälfte eines reinen Signaturschlüssels vernichtet) wird stattdessen angefragt, als Zeilen generate-identity, register-client-key und revoke-identity in pepsi.setup_task, die pepsi-setup apply erneut validiert und als pepsi-crypto ausführt (siehe unten). Ein widerrufendes PATCH ist daher asynchron: es trägt allein status und antwortet mit der eingereihten Aufgabe; die Identität liest sich als revoked, sobald der Applier gelaufen ist. Die Registrierung umfasst kein privates Material, aber ein als eigener Schlüssel des Benutzers registrierter Schlüssel wird zu seinem öffentlichen Gesicht und verifiziert Signaturen als seine, daher darf eine kompromittierte Web-Schicht keinen solchen unterschieben können. Eine CSR zu erzeugen und ein ausgestelltes Zertifikat zu importieren, wird über HTTP nicht angeboten; verwenden Sie pepsi-keys(1).
Selbstbedienung für die eigenen Schlüssel. Ein auf eine Adresse beschränkter Prinzipal (own:<address>) darf, nur für diese Adresse, die drei Schlüssel-Schreiboperationen der Selbstbedienung im Stil von pEp erreichen: POST /api/v1/identities ({"address": ..., "vks": true|false}, vks optional und standardmäßig [pepsi-keys] VKS_PUBLISH), POST /api/v1/identities/client ({"address": ..., "key": "<armoured OpenPGP public key>"}, höchstens 64 KiB) und PATCH /api/v1/identities/{id} (dessen Feld vks_wanted, wenn true, eine Upload-Anfrage an den Keyserver für eine aktive OpenPGP-Identität festhält und sie über WKD veröffentlicht; den Upload übernimmt der Wiederholungsjob pepsi-keys identity publish --retry; und dessen status: revoked einen Widerruf anfragt). Jeder Handler prüft die Adresse erneut; die Identität einer anderen Adresse antwortet mit 404. Die beiden POST-Routen und ein widerrufendes PATCH antworten mit der eingereihten Aufgabe ({"task": ..., "kind": ..., "applier_notified": ...}), nicht mit dem Schlüssel, und der Prinzipal, der angefragt hat, darf dieser Aufgabe folgen: GET /api/v1/setup/tasks/ID antwortet jedem Prinzipal für eine Aufgabe, die er selbst eingereiht hat (404 für die eines anderen, wie für eine, die nicht existiert; der Besitz ist der requester_key der Aufgabe – der Selektor des Tokens, die Zeilennummer des Kontos oder der Login des Peers, von denen keiner je wiederverwendet wird –, nicht der Anzeigename requested_by), und GET /api/v1/setup/tasks listet einem Prinzipal ohne setup:write nur diese Aufgaben. Die Schlüsselformulare der Konsole antworten unter denselben Bedingungen mit der Seite der Aufgabe, /ui/setup/tasks/ID. DELETE /api/v1/identities/{id} bleibt dem Operator vorbehalten (keys:write): ein Benutzer setzt einen Schlüssel außer Dienst, er löscht nicht dessen Zeile. Die Konsole bietet dasselbe über die Formulare Generate a server-managed key und Register my own key auf der Identitäten-Seite sowie die Aktionen Upload to the key server und Revoke auf der Seite einer Identität.
Der Applier lässt diese drei Aufgabenarten mit einer eigenen Autorisierungsschranke zu: der anfragende Prinzipal muss keys:write besessen haben, oder own:<address> für genau die in den Parametern der Aufgabe genannte Adresse (setup:write allein genügt nicht). Anschließend verlangt er, dass die Adresse zu einer Domain aus [pepsi-ingress] ACCEPTED_DOMAINS gehört, und für eine Registrierung ein OpenPGP-Zertifikat, dessen User-IDs die Adresse nennen; für einen Widerruf muss die Identität zu dieser Adresse gehören. Ohne den Applier antworten alle drei mit 503 setup_applier_unavailable, wie jeder andere Applier-Pfad; das Einreihen benötigt außerdem die Verbindung [pepsi-admin] CONFIG_DB (andernfalls 503 setup_write_unavailable).
Der zweite Faktor. Jeder der drei Rümpfe (und die Formulare der Konsole) nimmt ein optionales "otp": "123456", den aktuellen Zweitfaktor-Code des Adressinhabers (siehe pepsi-keys(1), otp). Dieser Server kann ihn nicht prüfen – er hat überhaupt keine Berechtigung auf pepsi.otp_key –, also reicht er den Code nur in den Parametern der Aufgabe weiter, wo der Applier ihn für eine allein aufgrund von own:<address> zugelassene Aufgabe prüft, bevor er handelt; ein fehlender, falscher, wiederverwendeter oder gesperrter Code lässt die Aufgabe mit dem Grund fehlschlagen. Ein Prinzipal mit keys:write wird nicht gefragt. DELETE /api/v1/otp/ADDRESS (keys:write, unter own: nie erreichbar) reiht eine reset-otp-Aufgabe ein, die den zweiten Faktor der Adresse entfernt; so wird ein gesperrter entsperrt. Die synchronen Flag-Änderungen von PATCH /api/v1/identities/{id} (is_primary, published, vks_wanted) werden hier ausgeführt und sind daher nicht durch den zweiten Faktor geschützt.
Zwei Operationen verweigert dieser Server bewusst: die Konfigurations-Überlagerung zu schreiben (503, sofern [pepsi-admin] CONFIG_DB nicht eine Verbindung benennt, die sich als Rolle pepsi-config authentifiziert, was der Server beim Start prüft) und jede privilegierte Setup-Anfrage, wenn das Applier-Paket nicht installiert ist (503, siehe Der privilegierte Applier, und ohne ihn auskommen unten).
Die Aufbewahrungsrichtlinie des Audit-Logs und, wenn es aktiviert ist, des Mail-Logs wird vom Befehl prune dieses Programms angewandt, nicht vom Server: Jedes Mail verarbeitende Konto darf an diese Tabellen anhängen, aber nicht aus ihnen löschen, und die Rolle pepsi-httpd ist die einzige Dienstrolle, die DELETE auf ihnen besitzt (der einzige andere Inhaber ist die Operator-Rolle pepsi-config). Der mitgelieferte pepsi-log-prune.timer führt ihn täglich unter diesem Konto aus, sodass die Aufbewahrung gilt, ob der Webserver läuft oder nicht — früher war sie eine Hintergrundaufgabe von serve, die nur gestartet wurde, wenn ein Listener die administrative Oberfläche bediente, und eine Installation ohne die Konsole behielt jeden Eintrag für immer.
Bemerkung
Ein Binärprogramm bedient die öffentliche und die administrative Oberfläche. Ein Fehler im gemeinsamen Serverprozess ist daher ein Fehler in beiden; die Isolierung zu konfigurieren ist Sache des Operators — binden Sie den administrativen Listener an einen UNIX-Socket oder an das Loopback.
- GET /secure/TOKEN
Die Einstiegsseite des Secure-Link-Ausweichportals. Ohne Sitzung fragt sie nach der PIN; mit einem gültigen Sitzungs-Cookie rendert sie die Nachricht. Antwortet mit
404, wenn das Token unbekannt ist (oder das Portal nicht konfiguriert ist), mit410, wenn die Nachricht abgelaufen ist, und mit429, solange das Token gesperrt ist. Siehe das Secure-Link-Kapitel im Handbuch und pepsi-stage-secure-link(1).- POST /secure/TOKEN
Prüft die PIN. Bei Erfolg setzt sie das Sitzungs-Cookie und leitet (
303) auf die obige Seite um; bei falscher PIN rendert sie das Formular mit401erneut, und bei dem Versuch, derMAX_ATTEMPTSausschöpft, antwortet sie mit429und sperrt das Token für einen Zeitraum, der sich mit jeder weiteren Sperre verdoppelt. Eine Übermittlung ohne PIN wird ebenfalls mit401beantwortet, aber nicht aufMAX_ATTEMPTSangerechnet: Sie ist kein Rateversuch, und ein Client, der das Formular leer erneut absendet, würde sonst die Versuche eines legitimen Empfängers für ihn verbrauchen. Die PIN wird im Nachrichtentext der Anfrage übermittelt und erscheint nie in einer URL.- GET /secure/TOKEN/part/N
Lädt Anhang N der Nachricht herunter. Autorisiert durch die Sitzung, nie durch die PIN. Wird stets als
Content-Type: application/octet-streammitContent-Disposition: attachmentund einer Sandbox-Content-Security-Policyausgeliefert, welchen Medientyp die Nachricht auch behauptete — eintext/html-Teil, der aus dem eigenen Origin des Portals inline gerendert wird, ist genau das, was der Entwurf ausschließt.- POST /secure/TOKEN/reply
Verfasst eine Antwort, als
multipart/form-data(eintext-Feld und optionalefiles). Autorisiert durch die Sitzung. Empfänger und Umschlagabsender der Antwort werden dem gespeicherten Datensatz entnommen und sind keine Eingaben; der Nachrichtentext ist stetstext/plain; Uploads werden durchMAX_REPLY_SIZE/MAX_REPLY_FILESwährend des Streamens des Nachrichtentexts gedeckelt; und die injizierte Nachricht trägt bewusst keinstate.local_origin, sodass sie keine Submission-Privilegien erben kann. Antwortet mit404, wennREPLY_STAGEnicht gesetzt ist (Antworten erfolgt je Installation auf Opt-in).Jede Portalantwort trägt, je Route statt je Host,
Content-Security-Policy: default-src 'none'(mit einer Nonce je Antwort für das eine eingebettete Stylesheet und keiner Skriptquelle),Referrer-Policy: no-referrer,X-Content-Type-Options: nosniff,X-Frame-Options: DENYundCache-Control: no-store. Das Sitzungs-Cookie ist aufPath=/secure/beschränkt,HttpOnly,SecureundSameSite=Strict, sodass das Teilen eines Origins mit den obigen Endpunkten konstruktionsbedingt sicher ist und nicht erst durch Disziplin bei der Installation.
85.1.3.1.6. Der privilegierte Applier, und ohne ihn auskommen¶
pepsi-httpd führt nie eine privilegierte Änderung durch. Es hält einen Absichtsdatensatz in pepsi.setup_task fest und verbindet sich mit einem Türklingel-Socket; systemds Socket-Aktivierung macht aus dieser Verbindung ein kurzlebiges root-pepsi-setup apply, das den Datensatz prüft und die Arbeit erledigt. Das vollständige Vertrauensmodell steht in pepsi-setup(1), Das Vertrauensmodell des Appliers.
Das macht die Fähigkeit entfernbar, und Debian paketiert sie getrennt:
pepsiDer eigentliche Mailserver: die Binärprogramme — einschließlich pepsi-setup selbst —, das Schema, die Vorlagen und jede andere Unit (abgesehen von den getrennt paketierten
pepsi-stage-detect-languageundpepsi-telemetry). Eine vom Terminal aus verwaltete Installation braucht sonst nichts.pepsi-httpd-adminpepsi-setup-apply.socketundpepsi-setup-apply.service, und sonst nichts. Es ist das, was aus einer HTTP-Anfrage eine Änderung unter/etc/pepsimacht.pepsiRecommends es, sodass eine Standardinstallation es hat;apt remove pepsi-httpd-admingelingt, ohnepepsianzufassen.
Mit entferntem Paket gibt es nichts, was pepsi.setup_task leert. Die Schleife wird am Mechanismus gebrochen, nicht am Knopf: Ein Insert in diese Tabelle wird inaktiv, was auch immer mit der Web-Schicht geschieht. (Eine Quellinstallation bekommt denselben Hebel aus make install INSTALL_ADMIN_UNITS=no.)
Inaktiv, und es bleibt so: Das Paket wieder einzuspielen wirkt nicht auf das, was sich in seiner Abwesenheit angesammelt hat. Sein postinst führt pepsi-setup apply --clear aus, das jeden eingereihten Datensatz löscht, ohne einen auszuführen, sodass das Scharfstellen des Appliers nie zugleich das Ereignis ist, das eine Anfrage ausführt, an die sich niemand erinnert. Siehe pepsi-setup(1).
85.1.3.1.6.1. Was die Konsole dann tut¶
Nur lesend, und sie sagt es. Jede Einstellung, nach der das Setup-Interview fragt, wird weiterhin gerendert, mit ihrer vorbereiteten Antwort oder ihrem Standardwert; jedes Bedienelement, das eine ändern würde, ist deaktiviert, unter einem Banner, das das fehlende Paket benennt. Die Seiten werden nicht verborgen: Ein Operator, der den Applier bewusst entfernt hat, muss weiterhin sehen können, wozu die Installation konfiguriert ist.
Die API weist die entsprechenden Änderungen mit einem eigenen Status und Code zurück statt mit einem generischen Fehlschlag:
HTTP/1.1 503 Service Unavailable
{"code": "setup_applier_unavailable",
"hint": "the administrative package 'pepsi-httpd-admin' is not installed …",
"detail": {"package": "pepsi-httpd-admin", "unit": "pepsi-setup-apply.socket"}}
Es gilt für POST /api/v1/setup/tasks, /setup/preflight, /setup/dns-check, /setup/certificates, PUT /api/v1/setup/answers, POST /api/v1/identities, POST /api/v1/identities/client, ein widerrufendes PATCH /api/v1/identities/{id} und DELETE /api/v1/otp/{address} sowie für die eigenen Formular-Posts der Konsole — POST /ui/setup/{step}, /ui/setup/tasks, /ui/identities/request/{generate,register}, /ui/identities/{id}/revoke und /ui/domains/check, den „jetzt prüfen“-Knopf auf der Domains-Seite. Jeder davon erreicht die Warteschlange über eine einzige Einreihungsfunktion, die zuerst nachfragt, sodass die Ablehnung eine Entscheidung ist statt einer je Oberfläche; das deaktivierte Bedienelement auf der Seite ist Darstellung über dieser Prüfung und nicht ihr Ersatz. Das Vorbereiten von Antworten ist bewusst eingeschlossen: Der einzige Zweck einer Entwurfsantwort ist, angewandt zu werden, und ein Assistent, der sechs Schritte davon auf einem Host anhäuft, auf dem nichts sie anwenden kann, ist stillschweigend wirkungslos. DELETE /api/v1/setup/answers ist nicht gesperrt — Entwürfe zu verwerfen kann keine privilegierte Änderung bewirken, und eine nur lesende Konsole muss ein halbfertiges Interview weiterhin leeren können.
Beachten Sie den eigenen Code. setup_write_unavailable (keine CONFIG_DB-Verbindung) und setup_applier_unavailable haben verschiedene Abhilfen, und der Applier wird zuerst gemeldet, wenn beides zutrifft: Eine Datenbankrolle zu konfigurieren hätte nicht geholfen.
Nicht betroffen sind /api/v1/config und die Konfigurationsseiten der Konsole. Diese schreiben pepsi.config_override, die Datenbank-Überlagerung, die jede Komponente zur Laufzeit liest — keine Datei in /etc. Ihre einzige Sperre ist [pepsi-admin] CONFIG_DB, weil der Applier mit ihnen nichts zu tun hat und die Nur-lesen-Regel darauf auszuweiten eine Fähigkeit entfernte, um die es bei der Paketaufteilung nicht ging. Die beiden Schichten sind unter Konfigurationsschichtung im Handbuch beschrieben.
85.1.3.1.6.2. Wie es das erkennt¶
Indem es zwei Dateien betrachtet, die zusammen installiert und scharfgestellt beantworten:
pepsi-setup-apply.socketexistiert als Unit-Datei in einem Verzeichnis, das systemd durchsucht (/etc/systemd/system,/run/systemd/system,/usr/local/lib/systemd/system,/usr/lib/systemd/system,/lib/systemd/system); und[pepsi-admin] APPLY_SOCKETexistiert, ist ein Socket und ist für dieses Konto beschreibbar — sich mit einem UNIX-Socket zu verbinden braucht Schreibrecht.
Zwei stats und ein access, ohne Privileg — was zählt, denn der Server hat die Privilegien bereits an das unprivilegierte Konto pepsi-httpd abgegeben und kann weder dpkg noch systemd etwas fragen. Er verbindet sich bewusst nicht: Sich zu verbinden ist die Türklingel und würde bei jedem Seitenaufbau einen root-Prozess starten.
Keine der beiden Prüfungen ist überflüssig. Ohne die erste liest sich ein veralteter Socket-Knoten als lebendige Türklingel — und veraltete Knoten kommen vor: systemds RemoveOnStop= ist standardmäßig aus (die ausgelieferte Unit setzt es; eine von Hand bearbeitete vielleicht nicht), und ein Paket, dessen Dateien gelöscht statt gestoppt werden, lässt den Knoten schlicht zurück. Das ist genau der Fall, für den es diese Funktion gibt, und ihn falsch zu behandeln hieße, im Fehlerfall durchzulassen. Ohne die zweite läse sich ein frisch installiertes Paket, dessen Socket nie aktiviert wurde, als bereit, und jede Aufgabe bliebe für immer pending.
Die Prüfung ist fail-closed. Ein Pfad, der nicht untersucht werden kann, ein Pfad, der kein Socket ist, ein Fehler bei den Zugriffsrechten — jede Unsicherheit liest sich als „nicht verfügbar“, und die Konsole wird nur lesend. Der behebbare Fehlschlag ist, aufgefordert zu werden, etwas zu installieren, das bereits installiert ist; der unbehebbare ist zu glauben, eine Änderung sei vorgenommen worden.
Zwei Konsequenzen:
Ein Standort, der die Warteschlange anders leert —
pepsi-setup apply --onceaus cron, eine handgeschriebene Unit, ein Host ohne systemd, Unit-Dateien irgendwo, wo systemd nicht sucht —, hat keine Türklingel (oder keine Unit-Datei) und liest sich als nicht verfügbar.[pepsi-admin] APPLIER = yessetzt die Probe außer Kraft. Es ist ein Versprechen, das der Operator gibt; nichts hier kann es prüfen.Umgekehrt: Der Socket kann vorhanden sein, während die Service-Unit maskiert oder kaputt ist, in welchem Fall eine Aufgabe eingereiht wird und
pendingbleibt. Die Aufgabenseite zeigt diesen Status, statt etwas anderes vorzugeben. Beide Units werden in einem Paket ausgeliefert, sodass dies ein von Hand hergestellter Zustand ist und kein Paketierungsergebnis.
[pepsi-admin] APPLIER = no macht die Konsole allein durch Konfiguration nur lesend, für eine Installation, die ihre Paketmenge nicht ändern kann.
85.1.3.1.7. Konfiguration¶
Folgendes ist in pepsi.conf(5) dokumentiert: die Optionen des Abschnitts [pepsi-httpd] (MAX_CONNECTIONS, MAX_CONNECTIONS_PER_IP, DB_POOL_SIZE, das Paar ADDIN / ADDIN_URL, das das Outlook-Add-in aktiviert, und das optionale RESUME_AUTHORIZATION_TOKEN, das POST /resume schützt), die Socket- und SNI-Zertifikatsabschnitte [pepsi-httpd-listener-<name>] und [pepsi-httpd-cert-<name>] (einschließlich der Listener-Flags ADMIN, LIST_API, LIST_API_TESTING und LISTS), der Abschnitt [pepsi-admin], der die administrative API konfiguriert, der Abschnitt [pepsi-list], der die Zugangsdaten API_USER/API_PASS der Mailman-API und API_RATE_LIMIT sowie WEB_RATE_LIMIT/WEB_SEARCH_RATE_LIMIT der Weboberfläche enthält, der Abschnitt [pepsi-autoconfig], aus dem das Autokonfigurationsdokument gebaut wird, und der Abschnitt [pepsi-secure-link], der das Portal aktiviert.
85.1.3.1.8. Privilegienabgabe¶
Um privilegierte Ports (80/443) zu binden, wird pepsi-httpd oft als root gestartet. Es bedient nicht als root: Sobald jeder konfigurierte Listener gebunden ist (und etwaiges TLS-Schlüsselmaterial gelesen wurde), gibt der Prozess die Privilegien an das unprivilegierte Dienstkonto pepsi-httpd ab, legt alle ergänzenden Gruppen ab und wechselt zu Gruppe und Benutzer-ID dieses Kontos, bevor er auch nur eine Verbindung annimmt. Das Konto muss daher existieren, bevor der Server als root gestartet wird; legen Sie es (zum Beispiel useradd --system --no-create-home --shell /usr/sbin/nologin pepsi-httpd) im Rahmen der Installation an.
Wenn die Abgabe beim Lauf als root nicht abgeschlossen werden kann — meist, weil das pepsi-httpd-Konto nicht existiert — schreibt der Server einen Fehler ins Journal und beendet sich ohne zu bedienen, statt zu riskieren, als root zu laufen. Wird er von einem Nicht-Root-Benutzer gestartet, wird keine Privilegienänderung vorgenommen (der Server läuft einfach als der aufrufende Benutzer); er läuft nie als root.
85.1.3.1.9. TLS-Schlüsselmaterial¶
Das Zertifikat und der private Schlüssel jedes TLS-Listeners — sein eigenes TLS_CERT/TLS_KEY sowie jedes [pepsi-httpd-cert-*]-SNI-Zertifikat — werden einmalig beim Start gelesen, vor der oben beschriebenen Privilegienabgabe. Woher sie gelesen werden, hängt davon ab, wie der Server gestartet wurde.
Unter systemd (die paketierte Installation). Die Unit läuft von Anfang an unter dem unprivilegierten Benutzer pepsi-httpd — sie besitzt nie root — und kann daher certbots nur für root lesbares /etc/letsencrypt/{live,archive} nicht öffnen. Sie muss es auch nicht: pepsi-setup(1) schreibt ein Drop-in /etc/systemd/system/pepsi-httpd.service.d/10-tls-credentials.conf mit einem LoadCredential=-Eintrag pro Datei. systemd öffnet diese Dateien 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 und das für jede andere Unit unsichtbar ist —, wo pepsi-httpd jeden konfigurierten Pfad nachschlägt, bevor es auf das Lesen des Pfades selbst zurückfällt. Die Konfiguration bleibt davon unberührt: TLS_CERT/TLS_KEY benennen weiterhin die echten Dateien, und aus diesen Pfaden werden die Credential-Namen abgeleitet.
Zwei Konsequenzen:
Führen Sie
pepsi-setup runerneut aus, nachdem Sie ein Zertifikat hinzugefügt, verschoben oder entfernt haben. Das Drop-in wird aus der Konfiguration neu erzeugt und führt bewusst nur Dateien auf, die existieren, denn systemd weigert sich, eine Unit zu starten, deren Credential-Quelle fehlt.Ein Credential wird beim Start der Unit bereitgestellt, ein erneuertes Zertifikat erreicht die Clients also erst nach einem Neustart. Der von pepsi-setup installierte certbot-Deploy-Hook führt ihn durch (
systemctl try-restart).
Direkt gestartet, ohne systemd. Der Server wird als root gestartet, liest die Dateien selbst und gibt erst danach die Privilegien ab; es ist also kein Credential beteiligt, und die Dateirechte spielen nie eine Rolle.
Ein Zertifikat, das nicht geladen werden kann, wird gemeldet und übersprungen, nicht als fatal behandelt: Die SNI-Hostnamen, die es bedient hätte, sind dann nicht mehr über HTTPS erreichbar, während jedes andere Zertifikat weiter funktioniert. Nur ein TLS-Listener, dem kein einziges brauchbares Zertifikat bleibt, beendet den Server. Eine einzige unlesbare Datei kann somit nicht die MTA-STS-Richtlinie unbeteiligter Domains — oder den Metriken-Endpunkt — mit sich reißen.
85.1.3.1.10. Befehle¶
- serve
Führt den Server aus, bis er unterbrochen wird. Erfordert, dass das Schema mit pepsi-setup(1) installiert wurde.
- prune
Löscht Audit-Einträge, die älter als
[pepsi-admin] EVENT_RETENTION_DAYSsind, Mail-Log-Einträge, die älter alsMAIL_LOG_RETENTION_DAYSsind, sowie abgelaufene administrative Sitzungen und beendet sich dann. Als root ausgeführt, wechselt es zuerst zum Kontopepsi-httpd, dessen Datenbankrolle dieDELETE-Berechtigung besitzt.pepsi-log-prune.timerführt es täglich aus; auf einem System ohne systemd führen Sie es über cron aus.
85.1.3.1.11. Globale Optionen¶
- -c FILE, –config FILE
Liest die Konfiguration aus FILE, statt die Standardorte zu durchsuchen.
- -L LOGLEVEL, –log LOGLEVEL
Setzt die Log-Ausführlichkeit (Standardwert
info).- -v, –verbose
Zeigt Log-Meldungen aus allen Quellen.
- -h, –help; -V, –version
Gibt eine Verwendungsübersicht / die Version aus und beendet sich.
85.1.3.1.12. Signale¶
- SIGINT
Leitet das Herunterfahren ein und beendet sich sauber.
- SIGTERM
Nicht abgefangen: Die Standardbehandlung beendet den Prozess sofort und schneidet jede laufende Anfrage ab. Dadurch geht nichts verloren — die Warteschlange liegt in PostgreSQL, und dieser Server hält keinen eigenen Zustand —, und so beendet
systemctl stopdie Unit.
85.1.3.1.13. Exit-Status¶
- 0
Sauberes Herunterfahren.
- 1
Ein Fehler ist aufgetreten (zum Beispiel eine fehlerhafte Konfigurationsdatei, ein nicht lesbares Zertifikat oder eine fehlgeschlagene Datenbankverbindung). Der Grund wird in das Journal geschrieben.
85.1.3.1.14. Beispiele¶
Über HTTPS bedienen:
pepsi-httpd -c /etc/pepsi/pepsi.conf serve
Eine Richtlinie zum Testen abrufen (Auflösen des SNI-Hosts auf den Server):
curl --resolve mta-sts.example.org:443:203.0.113.7 \
https://mta-sts.example.org/.well-known/mta-sts.txt
Prüfen, ob der Schlüssel eines Benutzers veröffentlicht ist, so wie es der Client eines Korrespondenten täte:
gpg --locate-external-key alice@example.org
85.1.3.1.15. Siehe auch¶
pepsi-config(1), pepsi.conf(5), pepsi-dispatch(1), pepsi-keys(1), pepsi-setup(1)
85.1.3.1.16. Fehler¶
Melden Sie Fehler an den Pepsi-Issue-Tracker.