Aller au contenu

Journal d'audit

Le Journal d'audit, sous Admin → Paramètres → Journal d'audit (/admin/settings?tab=audit-log), répond aux deux questions qu'une revue de sécurité pose à une instance qui détient la carte de tout le paysage informatique : qu'est-ce qui y a changé, et qui s'est connecté, et comment. Il est divisé en deux sous-onglets :

Sous-onglet URL Ce qu'il enregistre
Modifications /admin/settings?tab=audit-log Chaque écriture dans le paysage — fiches, relations, risques, étiquettes, rôles de parties prenantes, brouillons de décision —, regroupée en lots de mutations, avec le diff de chaque événement et une annulation (Rollback)
Sécurité et administration /admin/settings?tab=audit-log&view=security Connexions et déconnexions, tentatives échouées, verrouillages, sessions SSO et proxy, événements de mot de passe, emprunt de rôle et chaque action administrative

Les deux sont séparés à dessein. Modifications est un outil de travail — il sert à voir et à annuler une écriture erronée — et ne conserve qu'un historique court. Sécurité et administration est une piste de preuves : ses entrées ne peuvent être ni modifiées ni supprimées, et elle est conservée un an par défaut.

Qui peut le consulter

Les deux sous-onglets exigent la permission admin.events (« Consulter la piste d'audit et le flux d'événements »), que seul le rôle Admin détient par défaut. Pour donner un accès en lecture à un responsable sécurité ou conformité sans en faire un administrateur, créez un rôle portant admin.events sous Utilisateurs et rôles et attribuez-le-lui.

Modifications

Le sous-onglet Modifications est le registre des lots de mutations. Chaque écriture qui modifie des données y arrive sous forme de lot, avec son auteur et sa provenance :

Origine Signification
Web L'interface web de Turbo EA
API Un appel direct à l'API REST (un script, une intégration)
Outil IA Un assistant IA connecté via le serveur MCP
Extension Une extension installée, enregistrée comme lot ext:<key>

Cliquez sur un lot pour ouvrir son panneau : le diff de chaque événement montre l'ancienne et la nouvelle valeur de chaque champ, et Rollback rétablit les écritures sur les fiches, relations, risques, rôles de parties prenantes, étiquettes et brouillons de décision qu'il a effectuées.

Les lots sont conservés MUTATION_BATCH_RETENTION_DAYS jours (une variable d'environnement, 15 par défaut), puis purgés automatiquement. Les événements eux-mêmes restent dans l'onglet Historique de chaque fiche une fois le lot disparu.

Sécurité et administration

Journal de sécurité et d'administration

Le sous-onglet Sécurité et administration liste une entrée par action ayant trait à la sécurité, les plus récentes en premier :

  • connexions et déconnexions, par mot de passe, par SSO ou via un proxy inverse de confiance ;
  • tentatives de connexion échouées, chacune avec un code de motif indiquant pourquoi elle a échoué ;
  • verrouillages de compte après des échecs répétés ;
  • inscriptions, ainsi que les mots de passe définis, réinitialisés ou modifiés ;
  • emprunt de rôle — un administrateur qui démarre puis arrête Voir en tant que rôle… ;
  • les actions administratives — modifications des utilisateurs, des rôles, des paramètres, du métamodèle, des tags, des calculs, des extensions, des imports, des intégrations, des portails publics et des diagrammes publiés, des enquêtes et de l'accès opérateur (voir Actions administratives) ;
  • les exports de ce journal lui-même.

Dans la prochaine version

Les exports de données (exports CSV/JSON de l'inventaire, exports de workspace et de migration) seront enregistrés dans ce même journal dans la prochaine version.

Colonnes

Colonne Description
Quand Date et heure de l'action
Catégorie auth (authentification), admin (actions administratives) ou access (exports et autres accès aux données)
Action Ce qui s'est passé, par exemple auth.login.failed — voir le catalogue des actions
Résultat Succès ou Échec
Acteur L'utilisateur connecté qui a effectué l'action. Vide quand personne n'était connecté — lors d'une connexion échouée, par exemple
Sujet Le compte concerné par l'action — l'adresse e-mail saisie lors d'une connexion échouée, ou l'utilisateur dont le mot de passe a été réinitialisé
Cible L'objet visé, s'il y en a un — par exemple le rôle choisi au démarrage d'un emprunt de rôle
IP L'adresse IP du client (voir Adresse IP du client)
Origine La provenance de la requête : web, API, outil IA, extension, ops ou système
Rôle emprunté Quand un administrateur consultait l'application sous un autre rôle, ce rôle. L'acteur reste l'administrateur réel

Les colonnes s'affichent, se masquent, se réordonnent et se figent comme dans tout autre tableau de données ; Quand et Action sont toujours affichées.

Filtres

Le panneau de filtres à gauche restreint la liste par catégorie, résultat, action, acteur, adresse IP et plage de dates. Chaque en-tête de section indique le nombre de valeurs sélectionnées, et le panneau replié affiche le nombre de filtres actifs. L'onglet Colonnes du même panneau affiche, masque et fige les colonnes. Vos filtres et la disposition des colonnes sont mémorisés dans ce navigateur.

Une recherche sur une adresse e-mail porte sur l'acteur, le sujet et la cible : saisir une seule adresse retrouve à la fois ce que cette personne a fait et ce qui a été tenté contre son compte.

Détails d'une entrée

Cliquez sur une ligne pour ouvrir le panneau de l'entrée. Il affiche chaque champ, y compris l'agent utilisateur du navigateur et les détails enregistrés avec l'entrée — le code de motif d'une connexion échouée, l'heure de fin d'un verrouillage, le fournisseur d'identité d'une connexion SSO. Lorsqu'une entrée enregistre une modification, les détails s'affichent sous forme de tableau des anciennes et nouvelles valeurs. Les secrets ne sont jamais stockés : un mot de passe, un jeton ou un secret client est remplacé par *** avant l'écriture de l'entrée.

Les éléments qui situent une modification sans en faire partie — l'adresse actuelle d'un portail et s'il est publié, le remplacement ou non des identifiants d'une connexion, les types couverts par un mappage de migration — sont listés sous Contexte, sous le tableau.

Le panneau ne propose aucune action. Les entrées ne peuvent être ni modifiées ni supprimées.

Exporter en CSV

Exporter en CSV, dans la barre d'outils, télécharge les entrées correspondant aux filtres actuels sous forme de fichier CSV, jusqu'à 50 000 lignes. L'export est lui-même enregistré, sous access.audit_log.exported, si bien qu'un export du journal de sécurité y laisse toujours une trace.

Catalogue des actions

Action Enregistrée lorsque
auth.login.succeeded un utilisateur se connecte avec son e-mail et son mot de passe
auth.login.failed une connexion par mot de passe est refusée. Le code de motif indique pourquoi (voir ci-dessous)
auth.login.locked la cinquième tentative échouée d'affilée verrouille le compte pendant 15 minutes. Les détails indiquent l'heure de fin du verrouillage
auth.logout un utilisateur connecté se déconnecte. Une déconnexion sans session valide n'enregistre rien
auth.sso.succeeded un utilisateur se connecte via un fournisseur SSO. Les détails indiquent le fournisseur, le sujet du fournisseur d'identité et si le compte a été créé par cette connexion
auth.sso.failed une connexion SSO est refusée — domaine non autorisé, adresse e-mail manquante, compte local avec le même e-mail, compte inactif. Les détails indiquent le fournisseur et le motif
auth.proxy_session.succeeded un utilisateur se connecte via un proxy inverse de confiance
auth.proxy_session.failed une connexion via le proxy inverse est refusée
auth.register un utilisateur crée un compte par auto-inscription
auth.password.set un utilisateur invité définit son premier mot de passe
auth.password.reset_requested Quelqu'un demande un e-mail de réinitialisation du mot de passe. Toujours enregistré comme un succès avec l'adresse saisie, pour que la réponse ne révèle rien ; les détails indiquent si un compte correspondait et si un e-mail a été envoyé
auth.password.reset un mot de passe est modifié via un lien de réinitialisation
auth.password.changed un utilisateur connecté modifie son propre mot de passe
auth.impersonation.started un administrateur démarre Voir en tant que rôle…. La cible est le rôle choisi
auth.impersonation.stopped l'administrateur revient à son propre rôle
access.audit_log.exported quelqu'un exporte le journal de sécurité en CSV

Codes de motif de auth.login.failed :

Motif Signification
unknown_user Aucun compte ne porte cette adresse e-mail
sso_account Le compte se connecte par SSO et n'a pas de mot de passe
no_password Le compte n'a pas encore de mot de passe — une invitation jamais acceptée
locked Le compte est verrouillé après des échecs répétés
bad_password Le mot de passe est erroné
inactive Le compte est désactivé

Codes de motif de auth.sso.failed, auth.proxy_session.failed, auth.password.set et auth.password.reset :

Motif Signification
expired L'accès limité dans le temps du compte a pris fin
hd_mismatch Le compte Google appartient à un domaine non autorisé
no_email Le fournisseur d'identité n'a renvoyé aucune adresse e-mail
no_subject Le fournisseur d'identité n'a renvoyé aucun identifiant de sujet
local_account Un compte local avec mot de passe utilise déjà cette adresse e-mail
no_account Aucun compte n'existe et les comptes ne sont pas créés automatiquement
exchange_failed Le fournisseur d'identité n'a pas terminé la connexion
unauthenticated Le proxy inverse n'a pas authentifié la requête
identity_rejected L'identité transmise a été refusée (domaine ou e-mail non vérifié)
invalid_token Le lien d'invitation ou de réinitialisation était invalide ou a expiré

Une rafale d'échecs unknown_user depuis une même adresse IP est la signature d'une pulvérisation de mots de passe (password spraying) ; une série de bad_password contre un compte suivie de auth.login.locked est une tentative de devinette contre ce compte.

Actions administratives

Chaque modification qu'un administrateur apporte à la configuration de l'instance est enregistrée dans la catégorie admin. L'acteur est l'administrateur, la cible est l'objet modifié — un utilisateur, un rôle, un paramètre, un type de fiche — avec son nom tel qu'il était à ce moment-là, et les détails indiquent ce qui a changé sous forme d'anciennes et de nouvelles valeurs, limitées aux champs réellement modifiés. Deux règles s'appliquent à chaque entrée :

  • Les secrets sont masqués. Un mot de passe SMTP, un secret client SSO, une clé de fournisseur d'IA, un identifiant ServiceNow ou toute autre valeur secrète est écrit *** : l'entrée montre qu'il a changé, jamais ce qu'il était ni ce qu'il est devenu.
  • Aucun texte de licence ni identifiant n'est jamais stocké. Une licence d'extension est identifiée, pas copiée, et un mot de passe qu'un administrateur définit pour un utilisateur est enregistré comme modifié, jamais avec sa valeur.

Un enregistrement qui ne change rien n'est pas consigné, pas plus qu'un utilisateur qui modifie son propre nom ou sa langue dans son profil. Une configuration volumineuse — les champs, traductions ou la mise en page d'un type de fiche, les filtres d'un portail — est résumée par sa taille plutôt que copiée ; lorsque la taille n'a pas changé, une courte empreinte du contenu est ajoutée, afin que l'entrée montre malgré tout qu'il y a eu une modification. Les surcharges de permissions par rôle d'un type de fiche font exception : chaque cellule modifiée est listée avec son ancienne et sa nouvelle valeur, une valeur vide signifiant que la permission propre du rôle s'applique.

Domaine Actions Ce qui est enregistré
Utilisateurs et rôles admin.user.created, .updated, .deleted, .bulk_updated, .bulk_deleted, .unlocked; admin.user.invitation.resent, .deleted; admin.role.created, .updated, .archived, .restored; admin.stakeholder_role.created, .updated, .deleted, .archived, .restored Comptes créés, modifiés, activés ou désactivés, supprimés (un par un ou en masse) et déverrouillés, avec les champs modifiés — rôle, e-mail, nom, état actif ; invitations renvoyées ou révoquées ; rôles applicatifs et rôles de parties prenantes par type, avec les permissions accordées ou retirées
Paramètres admin.settings.updated Une entrée par paramètre enregistré — e-mail, authentification et SSO, inscription, IA, MCP, langues, activation des modules, image de marque, logo et favicon, durées de conservation. La cible est le paramètre ; les détails sont son ancienne et sa nouvelle valeur, secrets masqués
Métamodèle admin.metamodel.type.* (including .references_generated), admin.metamodel.relation_type.*, admin.metamodel.resource_type.*, admin.principle.* (including .imported), admin.regulation.* Types de fiches, types de relations et types de ressources créés, modifiés, supprimés ou restaurés, avec les propriétés modifiées ; références de fiches générées pour un type ; principes EA, y compris ceux importés depuis le catalogue ; réglementations de conformité
Tags et calculs admin.tag_group.*, admin.tag.*, admin.calculation.* Groupes de tags et tags ; champs calculés créés, modifiés, supprimés, activés ou désactivés, avec l'ancienne et la nouvelle formule, et l'exécution d'un calcul sur toutes les fiches (.recalculated)
Extensions admin.extension.install.uploaded, .applied, .discarded; admin.extension.store.claimed, .refreshed, .installed; admin.extension.enabled, .disabled, .uninstalled; admin.extension.license.updated, .removed Paquets téléversés, installés ou abandonnés ; licences et téléchargements depuis la boutique d'extensions ; extensions activées, désactivées et désinstallées ; licence remplacée ou supprimée — avec l'extension et sa version, jamais le texte de la licence
Transfert de workspace et migration admin.workspace.import.uploaded, .applied, .completed, .discarded; admin.migration.uploaded, .field_mappings.updated, .applied, .deleted Un paquet de workspace téléversé, son import lancé, terminé ou abandonné ; une migration de plateforme téléversée, ses correspondances de champs modifiées, appliquée ou supprimée
Intégrations admin.servicenow.connection.*, admin.servicenow.mapping.*, admin.servicenow.sync.pulled, .pushed, .applied Connexions ServiceNow, identifiants masqués, et correspondances ; chaque récupération, envoi et application d'enregistrements en attente
Exposition publique admin.web_portal.created, .updated, .deleted; admin.diagram.published, .unpublished Portails web et diagrammes publiés — tout ce qui rend des données accessibles sans compte
Enquêtes admin.survey.sent, admin.survey.closed Une enquête envoyée à ses destinataires, ou clôturée
Accès opérateur admin.ops.rescue_access.granted, .revoked Accès de secours accordé ou révoqué via l'API d'exploitation, enregistré à côté des événements ops.* existants

Ce qui n'est pas enregistré

  • Le renouvellement du jeton. L'application web renouvelle sa session à intervalle régulier : chaque onglet ouvert ajouterait des entrées, sans qu'aucune ne signifie quoi que ce soit.
  • Les requêtes refusées pour un jeton de session expiré ou invalide. Elles se produisent chaque fois qu'une session se termine normalement.
  • Les lectures de flux OData. Excel et Power BI interrogent le flux OData d'une vue sauvegardée selon un calendrier ; chaque actualisation ajouterait une entrée.
  • Le simple accès en lecture — ouvrir une fiche, exécuter un rapport, rechercher dans l'inventaire.

Conservation

Les entrées sont conservées 365 jours par défaut. Modifiez cette durée sous Admin → Paramètres → Général → Gestion des données → Conservation du journal de sécurité : n'importe quel nombre de jours jusqu'à 3650, ou 0 pour conserver les entrées indéfiniment. Une tâche supprime chaque nuit les entrées plus anciennes que cette durée et relit le paramètre à chaque passage, de sorte qu'un changement prend effet sans redémarrage.

Cette tâche de conservation est la seule chose qui supprime jamais une entrée. Il n'existe aucune action de modification ou de suppression, ni dans l'interface ni dans l'API, pour aucun rôle.

Le journal ne fait volontairement pas partie du Transfert de workspace : il constitue l'historique de sécurité de cette instance, pas le contenu du workspace, et cloner une instance ne le copie pas.

Le flux d'audit JSON

Chaque entrée est aussi écrite par le backend sous forme d'une ligne JSON sur le logger turbo_ea.audit, au moment même où elle est enregistrée. Le backend journalise sur la sortie standard, si bien que le flux parvient à tout ce qui collecte déjà les journaux de vos conteneurs — docker compose logs backend, la collecte de journaux de Kubernetes ou n'importe quel agent d'expédition vers un SIEM —, sans aucune configuration dans Turbo EA :

docker compose logs -f backend | grep turbo_ea.audit

La ligne est écrite au moment où l'entrée est enregistrée. Si la transaction de la requête échoue ensuite, la ligne existe sans enregistrement en base : la table fait foi, le flux est le fil en direct.

Chaque ligne porte les mêmes champs que l'entrée :

Champ Contenu
audit_id, created_at L'identifiant de l'entrée et le moment où elle a été écrite
category, action, outcome Ce qui s'est passé et si cela a réussi
actor_user_id, actor_email Qui l'a fait
subject_email Le compte concerné
target_type, target_id, target_label Ce sur quoi l'action a porté
ip, user_agent Le client
origin web, api, mcp, ext, ops ou system
impersonator_user_id, impersonated_role Renseignés pendant qu'un administrateur consulte l'application sous un autre rôle
details Codes de motif et anciennes/nouvelles valeurs, secrets déjà masqués

Expédier ce flux vers un stockage central de journaux en conserve une copie hors de l'instance, hors de portée de quiconque peut l'administrer — c'est ce dont a besoin une revue des menaces internes. Voir Journalisation et flux d'audit pour le collecter.

Adresse IP du client

La colonne IP enregistre l'adresse du client, et non celle du proxy placé devant le backend. Le nginx de bordure fourni renseigne l'en-tête X-Real-IP avec l'adresse d'où il a reçu la connexion, et le backend lit cet en-tête parce que l'image backend publiée définit TRUST_PROXY_HEADERS=true. Une valeur qui n'est pas une adresse IP valide est écartée plutôt qu'enregistrée.

  • Laissez TRUST_PROXY_HEADERS activé tant que chaque requête atteint le backend via le nginx fourni — la pile par défaut, le chart Helm et les modèles de conteneurs managés fonctionnent tous ainsi.
  • Désactivez-le (TRUST_PROXY_HEADERS=false) si vous exposez directement le conteneur backend, sans le nginx fourni devant lui : un client pourrait alors envoyer son propre X-Real-IP et choisir l'adresse enregistrée.
  • Derrière un autre répartiteur de charge, le nginx fourni voit l'adresse de ce répartiteur, et chaque entrée l'enregistre. Un paramètre permettant à nginx de faire confiance à l'adresse client transmise par votre répartiteur de charge (NGINX_TRUSTED_PROXIES) est prévu dans une version ultérieure.