Journal d’audit
Chaque action modifiant l’état, son auteur, sa provenance, et ce qu’elle a touché.
Chaque action modifiant l’état de l’installation laisse une ligne : son auteur, sa date, l’adresse IP d’origine, sa cible, et son issue. Admin → Audit, protégé par la permission plateforme audit:view — voir rôles et permissions.
Ce qui est enregistré
Chaque POST, PATCH, PUT et DELETE qui atteint l’API. Non pas une liste de points d’accès instrumentés, mais un plancher qu’un nouveau module ne peut oublier d’adopter, parce qu’il est appliqué au-dessus des contrôleurs plutôt que dans chacun d’eux.
Une entrée porte :
| Champ | Contient |
|---|---|
| Auteur | L’utilisateur connecté — ou rien pour un événement système ou anonyme, comme une connexion échouée sur une adresse ne correspondant à aucun compte. |
| Action | Un nom pointé dérivé de la route entière, pas du seul verbe : application.restart, application.env.update, user.role.change. |
| Ressource | Ce qui a été touché, et l’identifiant de l’objet. |
| Utilisateur ciblé | La personne sur laquelle l’action a été effectuée, quand elle diffère de l’auteur. |
| Origine | Adresse IP, agent utilisateur, et route appelée. |
| Issue | Le succès, ou l’échec avec son code de statut et son message. |
Les échecs sont enregistrés aussi, et ils comptent davantage que les succès. Une requête rejetée n’atteint jamais le contrôleur : elle est donc capturée en amont — une rafale de 403 depuis une adresse sur une ressource dessine quelqu’un qui cartographie ce qu’il peut atteindre, et n’aurait sinon laissé aucune trace.
Ce qui est délibérément exclu
- Les lectures. Un
GETne change rien, et toutes les journaliser enterrerait les modifications sous du trafic machine. - Le bavardage machine — rafraîchissement de jeton, battements de cœur des agents, contrôles de santé, notification marquée lue. Gros volume, aucun signal.
- Les rejets de flood. Une IP bannie est refusée à chaque requête ; le bannissement lui-même est déjà consigné une fois. Les
429du limiteur sont le limiteur qui fonctionne, pas une action d’exploitant.
Corps de requête et secrets
Le corps d’une mutation est la partie intéressante — il dit *ce qui* a changé, pas seulement que quelque chose a changé. Il transporte aussi des mots de passe, jetons, clés privées et valeurs d’environnement : les champs dont le nom correspond à un motif de secret sont donc masqués avant enregistrement, et la charge utile est plafonnée.
code aurait avalé exitCode, or exitCode: 137 est la signature d’un arrêt pour mémoire insuffisante — précisément le détail que le journal existe pour conserver. Trop masquer appauvrit le journal aussi sûrement que pas assez le fait fuir.Consulter le journal
La table filtre par auteur, utilisateur ciblé, action, ressource, identifiant de ressource, adresse IP, texte libre, plage de dates, et échecs seuls. La liste des actions est construite à partir des noms réellement présents : vous filtrez donc sur ce que fait vraiment votre installation, pas sur un menu figé.
Les trois questions auxquelles il répond le plus vite :
- « Qui a cassé la production à 14 h 12 ? » — une plage de dates et l’identifiant de l’application.
- « Quelqu’un nous sonde-t-il ? » — les échecs seuls, groupés par IP.
- « Qu’a touché ce prestataire ? » — filtre par auteur, sur toute la durée de sa mission.
Les entrées sont conservées 365 jours par défaut et purgées chaque heure par petits lots. La rétention est un réglage de plateforme — une table d’audit à croissance illimitée devient un problème de disque bien avant de devenir une archive utile, et une suppression massive verrouillerait la table contre toute modification de l’installation.
Les appels effectués avec une clé API apparaissent comme les autres, attribués au propriétaire de la clé, avec la route enregistrée. Une clé n’est pas un moyen d’agir sans laisser de trace.