7. Exploiter Pepsi

Ce chapitre traite des semaines qui suivent l’installation : où se trouvent les journaux, que surveiller, et que sauvegarder pour qu’un disque perdu vous coûte un après-midi plutôt que les clés de tous les utilisateurs. La mise à niveau est décrite dans Mise à niveau, et que faire lorsque quelque chose se passe mal dans Dépannage.

7.1. Journaux

Chaque programme de Pepsi journalise sur la sortie d’erreur standard. Sous les unités systemd livrées, il s’agit du journal, une unité par programme de longue durée :

journalctl -u pepsi-ingress -u pepsi-dispatch -u pepsi-httpd --since today
journalctl -u pepsi-dispatch -f          # follow the pipeline live
journalctl -u 'pepsi-*' -p warning       # warnings and errors, every unit

Les programmes d’étape n’ont pas d’unités propres : le dispatcher les lance comme workers et ils héritent de sa sortie d’erreur standard, de sorte que tout ce qu’une étape journalise apparaît sous pepsi-dispatch. Chaque enregistrement nomme le programme qui l’a écrit. Les timers (rafraîchissement des clés, réconciliation des quotas, élagage des journaux, …) journalisent sous leurs propres noms .service ; systemctl list-timers 'pepsi-*' les liste avec leur dernière et leur prochaine exécution.

7.1.1. Niveaux de journalisation

Les niveaux sont error, warn, info (par défaut), debug et trace.

  • [pepsi] LOG fixe le niveau pour tous les programmes à la fois, y compris les workers des étapes, qui ne reçoivent aucune option de ligne de commande du dispatcher. Redémarrez les services après l’avoir modifié (le dispatcher redémarre lui-même ses workers).

  • -L LEVEL (avant la sous-commande, p. ex. pepsi-queue -L debug list) le remplace pour un seul processus, ce qui est la manière habituelle d’examiner de plus près un outil lancé à la main.

  • -v laisse aussi passer les enregistrements propres aux bibliothèques de base de données, HTTP et TLS, qui sont masqués sinon. Utile pour un problème de connexion ; très bavard.

  • [pepsi] LOG_JSON = yes écrit un objet JSON par enregistrement, pour un agrégateur de journaux.

info enregistre une ligne ou quelques-unes par message et par étape. warn garde ce qui demande de l’attention et convient à un hôte chargé. debug et trace peuvent inclure les adresses d’enveloppe et des détails de protocole ; ne les laissez pas activés.

7.1.2. Ce qui est conservé, et pour combien de temps

La rétention du journal est celle de systemd (journald.conf). Dans la base de données, Pepsi conserve :

  • le journal d’audit (pepsi.event_log) : qui a modifié quoi, depuis les outils en ligne de commande, l’API et la console, élagué chaque jour par pepsi-log-prune.timer ;

  • aucun journal de remise par message, à moins que vous n’activiez [pepsi] MAIL_LOG (voir pepsi.conf(5) et l’avertissement sur la vie privée qui s’y trouve). Un message remis est supprimé de la file d’attente, de sorte que sans lui le journal est la seule trace du passage d’un message ;

  • les compteurs de rapports TLS (pepsi.tls_session), élagués par pepsi-tlsrpt-prune.timer.

7.2. Surveillance

Deux choses vous disent si le courrier circule : la file d’attente, et les messages que le pipeline a abandonnés.

7.2.1. pepsi-status

pepsi-status est un résumé en lecture seule de la file d’attente, des messages bloqués avec la raison de chacun, des compteurs cumulés par étape, des résultats TLS sortants, des quotas de boîtes aux lettres et des changements de clés récents. On peut le lancer sans risque à tout moment, et --json fournit le même rapport à un script :

pepsi-status
pepsi-status --json | jq .problem_total

problem_total est le nombre de messages en failed ou timeout. Le dispatcher ne les réessaie jamais ; pepsi-failure-bouncer.timer les fait rebondir vers leurs expéditeurs une fois qu’ils sont en échec depuis MIN_AGE (une heure ; voir Messages en failed ou timeout), de sorte que le compteur revient normalement à zéro de lui-même. S’il ne cesse d’augmenter, la même étape échoue message après message et la cause doit être corrigée. Une défaillance de l’hôte n’apparaît pas ici au début : ses messages attendent en paused à l’étape défaillante (pepsi_pause_backlog) avec l’erreur dans state.last_error, et sont réessayés jusqu’au MAX_LIFETIME de l’étape.

7.2.2. /metrics

pepsi-httpd sert des métriques Prometheus à /metrics sur un écouteur marqué ADMIN = yes (et nulle part ailleurs ; aucun identifiant n’est demandé, marquez donc un écouteur que seul votre système de surveillance peut atteindre). Les séries :

Série

Type

Signification

pepsi_stage_active_messages{stage}

jauge

Messages en cours de traitement.

pepsi_pause_backlog{stage}

jauge

Messages en attente d’une nouvelle tentative : un serveur distant qui a différé, une clé en cours de recherche, un paiement attendu.

pepsi_stage_messages_total{stage}

compteur

Messages qu’une étape a traités.

pepsi_stage_duration_seconds_total{stage}

compteur

Temps passé dans l’étape ; divisé par la série précédente, la moyenne.

pepsi_stage_timeouts_total{stage}

compteur

Workers tués pour avoir dépassé le MAX_RUNTIME de l’étape.

pepsi_stage_crashes_total{stage}

compteur

Workers morts pendant le traitement d’un message.

pepsi_messages_processed_total

compteur

Messages sortis du pipeline.

pepsi_stages_executed_total

compteur

Passages d’étape, toutes étapes confondues.

Les compteurs sont écrits par le dispatcher tous les STATS_INTERVAL et lorsqu’il devient inactif, de sorte qu’ils ont jusqu’à cet intervalle de retard. Ce sont des totaux depuis la création du schéma, non par collecte ; utilisez rate().

7.2.3. Sur quoi alerter

Condition

Pourquoi

pepsi-status --json indique un problem_total supérieur à zéro pendant plus de MIN_AGE plus dix minutes

Un message a échoué et n’a pas rebondi : pepsi-failure-bouncer.timer ne s’exécute pas (systemctl list-timers), ou le rebond lui-même a échoué. Les messages qui échouent à l’étape de rebond ne rebondissent pas à nouveau et vous attendent.

pepsi_pause_backlog d’une étape autre que de remise qui augmente, ou le journal qui répète « failed at stage … retrying »

Une défaillance de l’hôte à cette étape (une clé ou un modèle illisible, un helper qui ne peut démarrer, une instruction refusée). Ses messages sont retenus, non renvoyés en rebond, jusqu’à MAX_LIFETIME ; state.last_error dit pourquoi.

Le dispatcher qui journalise « the worker refused to start » pour une étape

La configuration de l’étape ou un secret qu’elle lit ne s’analyse plus ; ses messages sont retenus jusqu’à ce que ce soit à nouveau le cas.

pepsi_pause_backlog d’une étape de relais qui augmente pendant des heures

Le saut suivant, le DNS ou le port 25 sortant est injoignable. Les nouvelles tentatives continuent jusqu’à MAX_LIFETIME, puis les expéditeurs reçoivent des rebonds.

rate(pepsi_stage_crashes_total[15m]) ou rate(pepsi_stage_timeouts_total[15m]) supérieur à zéro

Un programme d’étape échoue ; ses messages finissent en failed ou timeout.

rate(pepsi_messages_processed_total[1h]) à zéro alors que du courrier est attendu

Rien ne sort du pipeline : le dispatcher est arrêté ou une étape est bloquée.

Une unité pepsi-* dans l’état failed (systemctl --failed)

Les unités de longue durée réessaient indéfiniment, de sorte qu’une unité en échec est en général un timer ou une tâche ponctuelle.

Enregistrements du journal au niveau error

Tout ce qui est journalisé comme erreur mérite d’être examiné.

L’expiration des certificats TLS

certbot les renouvelle ; un renouvellement qui échoue est journalisé par certbot, non par Pepsi.

L’espace libre là où PostgreSQL conserve ses données

En dessous de [pepsi] MIN_FREE_SPACE (1 GiB par défaut), pepsi-ingress refuse le nouveau courrier avec une erreur temporaire.

7.3. Sauvegarde et restauration

Avertissement

Un vidage de la base de données ne constitue pas à lui seul une sauvegarde de Pepsi. Les clés privées de la base de données sont chiffrées sous une clé de chiffrement de clés conservée, à dessein, hors de la base de données, dans /etc/pepsi/secrets.d/pepsi-crypto.secret. Perdez ce fichier et les clés privées stockées de tous les utilisateurs sont perdues avec lui : rien ne peut plus les ouvrir, et pepsi-setup n’en générera pas de remplaçante tant que des clés chiffrées existent.

7.3.1. Que sauvegarder

Quoi

Ce qui est perdu sans cela

/etc/pepsi/secrets.d/, avant tout pepsi-crypto.secret

pepsi-crypto.secret : toutes les clés privées stockées (voir plus haut). Les autres fragments : la clé SRS (les rebonds vers du courrier réacheminé avant la perte sont refusés), le poivre du lien sécurisé (les messages sécurisés pas encore retirés ne peuvent plus être ouverts), la clé de preuve d’origine (les demandes de paiement pour du courrier envoyé avant la perte ne sont plus reconnues comme les nôtres), ainsi que les mots de passe et jetons que vous avez saisis.

La base de données PostgreSQL (pepsi par défaut)

La file d’attente, les réglages par utilisateur, les listes blanches, les listes de diffusion et leur archive, le magasin de clés, les quotas, les comptes d’administrateur et les jetons d’API, le journal d’audit.

/etc/pepsi/ (le reste)

La configuration. Elle peut être réécrite avec l’assistant, mais pas rapidement.

/var/pepsi/keys/

Les clés de signature DKIM et ARC. De nouvelles clés peuvent être générées, mais chacune doit être publiée à nouveau dans le DNS, et le courrier signé avant cela échoue à DKIM.

/var/lib/pepsi-wallets/

Avec pepsi-stage-auto-pay en mode portefeuille partagé : les portefeuilles et l’argent qu’ils contiennent. En mode local-user, les portefeuilles se trouvent dans les répertoires personnels des utilisateurs.

/etc/letsencrypt/

Rien de permanent ; certbot obtient de nouveaux certificats. Conservez-le néanmoins si vous publiez des enregistrements DANE (TLSA) pour la clé actuelle.

/var/pepsi/tokens, /var/pepsi/token-refresh, /var/pepsi/tls

Seulement avec un smarthost OAuth ou à certificat client : le jeton de rafraîchissement doit être autorisé à nouveau.

Les boîtes aux lettres des utilisateurs (Maildir, ou le stockage du MDA derrière LMTP) n’appartiennent pas à Pepsi et relèvent de votre sauvegarde ordinaire des répertoires personnels.

Conservez les fichiers et le vidage de la base de données ensemble, et pris au même moment : un vidage plus récent que secrets.d peut contenir des clés enveloppées sous une clé de chiffrement de clés que la sauvegarde des fichiers n’a pas. Les deux contiennent des secrets ; stockez-les chiffrés et lisibles par root seulement.

7.3.2. Effectuer une sauvegarde

sudo -u pepsi-owner pg_dump --format=custom pepsi > pepsi-$(date +%F).dump
tar -C / -czpf pepsi-files-$(date +%F).tar.gz \
    etc/pepsi var/pepsi var/lib/pepsi-wallets

Exécutez en tant que root, afin que tar puisse lire secrets.d. pg_dump prend un instantané cohérent pendant que les services tournent ; les fichiers changent rarement (une nouvelle clé, une modification de configuration), il suffit donc de les prendre juste avant ou juste après le vidage. Le nom de la base de données et son propriétaire sont ceux de [pepsi-postgres].

Le vidage que pepsi-setup schema --backup-dir effectue avant une mise à niveau (voir Sauvegarder avant une mise à niveau du schéma) ne couvre que la base de données, et seulement le schéma pepsi ; il ne remplace pas ceci.

7.3.3. Restauration

Restaurez sur un hôte exécutant la même version de Pepsi que celle dont provient la sauvegarde (mettez à niveau ensuite, si vous le souhaitez), dans cet ordre :

  1. Installez Pepsi. Le paquet Debian crée les comptes de service et les rôles de base de données ; sur une installation depuis les sources, créez-les comme dans Installation.

  2. Arrêtez tout : systemctl stop pepsi.target.

  3. Restaurez les fichiers, secrets.d en premier. tar conserve les propriétaires par nom, les comptes doivent donc exister avant que vous ne décompressiez :

    tar -C / -xzpf pepsi-files-2026-10-01.tar.gz
    
  4. Restaurez la base de données dans une base vide appartenant au propriétaire du schéma :

    sudo -u postgres dropdb --if-exists pepsi
    sudo -u postgres createdb -O pepsi-owner pepsi
    sudo -u pepsi-owner pg_restore -d pepsi pepsi-2026-10-01.dump
    
  5. Exécutez pepsi-setup -c /etc/pepsi/pepsi.conf run. Il réapplique les droits des rôles, réécrit ce qui vit hors des deux sauvegardes (les drop-ins systemd qui remettent les certificats TLS aux services) et vérifie les enregistrements DNS par rapport aux clés restaurées. Il ne remplace aucune clé ni aucun secret qui existe déjà.

  6. Démarrez les services : systemctl start pepsi.target.

Si pepsi-setup indique qu’il refuse de générer une clé de chiffrement de clés parce que des identités existent, secrets.d/pepsi-crypto.secret n’a pas été restauré, ou n’est pas celui qui va avec cette base de données. Ne contournez pas le problème : retrouvez le bon fichier.