Enregistrement d’audit des actions d’agent : un modèle pratique de contrôle
Concevez un enregistrement d’audit des actions d’agent qui capture l’identité du processus, les cibles, les approbations, les résultats, les révocations et les preuves de falsification, sans journaliser les secrets.

Les actions des agents ont besoin d’enregistrements qui décrivent l’autorité, pas seulement l’activité. Une ligne comme POST /deploy returned 200 ne permet pas de savoir si le bon processus a envoyé la requête, si une personne l’a autorisée, quel système l’a reçue ni si une révocation ultérieure a interrompu quoi que ce soit.
L’unité pratique est un enregistrement d’action immuable, relié aux événements de session, d’approbation et de révocation. Gardez l’enregistrement assez compact pour être recherché et vérifié, mais assez précis pour qu’un ingénieur fatigué puisse reconstituer un appel contesté sans inventer une histoire autour de champs manquants.
Une entrée d’audit doit décrire une tentative autorisée
Un enregistrement d’audit d’action d’agent décrit un effet tenté sur un système externe et le contexte d’autorité présent à cet instant. Une action peut échouer avant d’atteindre le réseau, échouer pendant la transmission, recevoir un refus de la cible ou se terminer correctement. Ces quatre cas doivent figurer dans la piste d’audit.
Les équipes enregistrent souvent l’une de deux choses insuffisantes. Elles enregistrent une transcription de discussion, qui décrit l’intention mais pas l’exécution. Ou elles enregistrent le trafic brut des requêtes, ce qui produit trop de secrets tout en omettant la décision humaine qui a permis l’appel. Aucun de ces enregistrements ne permet de savoir si un acteur donné avait l’autorité d’effectuer une opération donnée.
Traitez ces éléments comme des objets distincts :
- Une session identifie un processus d’agent en cours d’exécution et sa durée de vie.
- Une approbation consigne une décision humaine avec une portée définie.
- Une action consigne une opération externe demandée et son résultat.
- Une révocation met fin à une session ou à une autorisation à un instant précis.
Cette distinction a une conséquence pendant un incident. Si une personne révoque une session à 14:03, vous devez voir chaque action antérieure à 14:03, chaque action tentée après 14:03 et la décision locale qui a refusé ces tentatives ultérieures. Une seule ligne mutable indiquant « session approuvée : false » détruit cet historique.
Ne faites pas dépendre le modèle d’enregistrement de la réussite de l’action. La requête elle-même peut révéler une intention malveillante, un défaut de configuration ou un agent qui a mal compris sa tâche. Les appels échoués sont souvent les premiers éléments de preuve utiles.
L’acteur est un processus, pas un nom convivial d’agent
Enregistrez le processus qui a réellement demandé l’action. Le nom du modèle, de l’espace de travail ou le surnom de l’agent peut aider une personne à parcourir un rapport, mais aucun de ces éléments n’identifie de manière unique l’exécutable qui détenait la connexion à ce moment-là.
Un objet acteur utile contient un identifiant interne de session, un identifiant de processus, le chemin de l’exécutable, l’heure de lancement et l’autorité de signature du code lorsque le système d’exploitation la fournit. Ajoutez l’identifiant et l’exécutable du processus parent lorsque vous pouvez les collecter de manière fiable. La relation parent-enfant explique souvent si un terminal a lancé l’agent, si une extension d’éditeur l’a créé ou si un assistant inattendu est intervenu.
Utilisez une capture instantanée de l’identité du processus au lieu de rechercher le processus plus tard. Les identifiants de processus sont réutilisés. Les chemins peuvent changer. Une recherche ultérieure ne peut pas réparer une observation manquante.
{
"actor": {
"session_id": "ses_01J8Q1F9K9Z3",
"pid": 48217,
"started_at": "2025-02-18T21:14:06Z",
"executable": "/usr/local/bin/agent-runner",
"signing_authority": "Developer ID Application: Example Developer",
"parent_pid": 48091,
"parent_executable": "/Applications/Terminal.app"
}
}
La valeur de signing_authority doit provenir de l’évaluation de signature de la plateforme, et non d’une chaîne fournie par l’agent. Un agent peut se nommer claude-code, deploy-helper ou trusted-agent. Un libellé n’est qu’un élément décoratif tant que le système d’exploitation ne le relie pas à l’identité d’un exécutable.
Ne transformez pas l’identité du processus en fausse affirmation d’auteur. Un binaire signé peut mal agir après une injection de prompt, l’intrusion d’un plugin ou une instruction imprudente. Le champ établit quelle autorité logicielle a lancé la requête. Il ne certifie pas la pertinence de cette requête.
RFC 5424, la spécification du protocole syslog, sépare les champs d’en-tête comme le nom de l’application et l’identifiant du processus des données structurées. Cette séparation reste pertinente pour les enregistrements d’agents. Placez l’identité stable et les horodatages dans des champs dédiés que les machines peuvent interroger. Placez le contexte variable, comme le dépôt ou la référence de tâche, dans un objet doté d’un espace de noms. Quand tout est placé dans une seule chaîne de message, chaque enquête ultérieure devient une opération d’analyse de texte.
Une cible a besoin d’une adresse et d’une signification
Enregistrez où l’action a été envoyée et quelle ressource ou commande elle cherchait à modifier. Ces faits sont liés, mais ils ne sont pas interchangeables.
Pour HTTP, la destination réseau peut être api.example.internal, tandis que l’opération significative est POST /v1/releases/{release_id}/promote. Stockez l’hôte, le port, le protocole, la méthode HTTP et un modèle de route. Ajoutez un identifiant de système cible contrôlé par votre équipe, comme release-service-prod. Cet identifiant reste valable après une migration de nom d’hôte, tandis que le nom d’hôte aide à diagnostiquer la requête réellement sortie de la machine.
Pour SSH, stockez l’alias ou le nom d’hôte, le port, l’empreinte de la clé d’hôte ou une référence à l’entrée known-hosts, ainsi que le libellé du compte distant lorsque vous pouvez le conserver sans risque. La cible doit également nommer la classe de commande demandée. restart-worker explique davantage que ssh succeeded, tout en révélant moins qu’une commande shell complète contenant des chemins client et des variables d’environnement.
Expurgez les données avant leur persistance, et non après qu’un analyste a ouvert le journal. Les chaînes de requête URL, les en-têtes, les arguments shell et les corps JSON contiennent régulièrement des jetons. Une bibliothèque de journalisation qui les capture « pour le débogage » finira par produire un fichier d’incident rempli d’identifiants.
Cette structure garde les faits concernant la cible interrogeables sans recopier tout le contenu de la requête :
{
"target": {
"kind": "http",
"system_id": "release-service-prod",
"endpoint": {
"scheme": "https",
"host": "api.example.internal",
"port": 443,
"method": "POST",
"route_template": "/v1/releases/{release_id}/promote"
}
},
"operation": {
"name": "promote_release",
"request_fingerprint": "sha256:8e8c...",
"request_bytes": 286,
"redacted_parameters": {
"environment": "production",
"release_id": "rel_7b2"
}
}
}
L’empreinte n’est utile que si vous définissez une canonisation. Triez les champs des objets, supprimez ceux que votre politique d’expurgation exclut, normalisez l’encodage du texte, puis hachez les octets obtenus. Enregistrez la version de la canonisation. Sinon, deux requêtes équivalentes peuvent produire des condensés sans rapport, et une modification ultérieure du schéma peut rendre les anciens enregistrements suspects.
Un condensé ne remplace pas les preuves conservées lorsqu’un organisme de réglementation, un contrat ou une procédure d’incident exige la requête d’origine. Dans ce cas, chiffrez les preuves séparément, limitez leur accès et stockez leur condensé dans l’enregistrement d’action. Ne placez pas le corps original dans le journal de recherche ordinaire simplement parce que le stockage est peu coûteux.
L’opération demandée et le résultat observé nécessitent des champs différents
Une requête d’agent exprime une intention. Le résultat indique ce que la passerelle a observé après avoir tenté d’exécuter cette intention. Ne fusionnez pas ces éléments dans un statut vague comme completed.
Pour un appel réseau, enregistrez la phase de transport à laquelle l’exécution s’est arrêtée, le statut du protocole lorsqu’il existe, un résumé limité de la réponse et le temps écoulé. Pour SSH, enregistrez le résultat de la connexion, celui de l’authentification, le code de sortie distant et des résumés limités de la sortie standard et des erreurs. Une cible peut accepter une requête et effectuer ensuite un travail asynchrone, donc une réponse 202 ne signifie pas que la modification externe a eu lieu.
Utilisez un vocabulaire de résultats qui indique où l’échec s’est produit. Par exemple :
denied_vault_lockedsignifie que la limite locale des secrets a refusé l’appel.denied_approvalsignifie que la décision humaine requise ne l’a pas autorisé.network_errorsignifie que la passerelle n’a pas pu établir ou conserver une connexion.target_rejectedsignifie que le service distant a renvoyé un refus.target_acceptedsignifie que le service distant a accepté la requête.
Gardez l’erreur brute du transport hors du champ de statut principal. Placez un code normalisé comme dns_lookup_failed ou tls_validation_failed à côté d’un court diagnostic expurgé. Les ingénieurs ont besoin d’agrégations ; les personnes chargées de la réponse à l’incident ont besoin d’un contexte local suffisant pour distinguer un certificat expiré d’un nom d’hôte bloqué.
Un objet de résultat complet peut ressembler à ceci :
{
"result": {
"outcome": "target_accepted",
"started_at": "2025-02-18T21:19:42.184Z",
"finished_at": "2025-02-18T21:19:43.021Z",
"duration_ms": 837,
"http_status": 202,
"response_fingerprint": "sha256:2a64...",
"response_summary": "promotion job accepted",
"evidence_ref": null
}
}
Évitez d’appeler target_accepted une réussite dans votre schéma. Ce mot créera des problèmes plus tard. Si le service accepte une tâche et que celle-ci échoue, la passerelle a fait exactement ce qu’elle devait faire, tandis que l’opération métier n’est pas terminée. Un événement ultérieur de fin distante, associé à un identifiant de tâche, pourra répondre à cette question.
Les enregistrements d’approbation doivent préciser ce que la personne a approuvé
Un enregistrement d’approbation doit comporter une décision, une portée, un sujet et des horodatages. « L’utilisateur a approuvé l’agent » ne dit pas assez. Les personnes chargées de l’examen doivent deviner si l’utilisateur a autorisé un appel API, un identifiant précis, une session ou toutes les sessions futures d’un processus portant un nom similaire.
Une approbation de session autorise généralement les appels d’un processus identifié jusqu’à sa fin ou jusqu’à sa révocation. Une approbation par appel s’applique à une utilisation unique d’un identifiant ou d’une opération. Enregistrez directement la portée, car ces deux contrôles produisent des niveaux de risque très différents.
{
"approval": {
"approval_id": "apr_01J8Q1P4Y5D6",
"decision": "approved",
"scope": "session",
"subject_session_id": "ses_01J8Q1F9K9Z3",
"approved_at": "2025-02-18T21:14:11Z",
"expires_at": "2025-02-18T22:02:53Z",
"approver_presence": "local_user_confirmation"
}
}
Ne prétendez pas à une certitude supérieure à celle que votre interface peut fournir. Si l’application reçoit un événement de confirmation locale, enregistrez ce fait. N’enregistrez pas le nom d’une personne, son compte auprès d’un fournisseur d’identité ou sa méthode biométrique, sauf si le système authentifie réellement cette association et la conserve selon une politique documentée. Des informations d’identité inventées créent une fausse confiance et des obligations en matière de vie privée.
Stockez l’approbation qui a gouverné une action sous forme d’identifiant dans l’enregistrement d’action. Stockez également la décision d’autorisation prise immédiatement avant l’exécution. Cela peut sembler répétitif jusqu’à l’examen d’un cas limite temporel : une ancienne approbation de session peut exister, mais une exigence par appel peut refuser l’action. L’action doit conserver ces deux faits.
La fatigue liée aux approbations est un défaut de conception, pas une raison pour supprimer les preuves d’approbation. Si une personne doit approuver chaque requête sans danger, elle finira par approuver sans lire. Réservez la confirmation par appel aux identifiants ou opérations dont l’utilisation abusive mérite une attention directe, et indiquez dans l’enregistrement pourquoi la passerelle l’a demandée.
La révocation est un événement avec une heure limite
La révocation met fin à l’autorité pour la suite. Elle n’efface pas une session, ne retire pas une requête déjà transmise et ne modifie pas la décision d’approbation qui existait cinq minutes plus tôt.
Enregistrez la cible de la révocation, le type d’initiateur, l’horodatage observé et le résultat de l’application. Si la passerelle peut terminer ou bloquer une session active, indiquez si elle l’a fait. Si une action a déjà franchi la limite réseau, précisez que la révocation ne peut pas la rappeler. Les ingénieurs ont besoin de ce fait désagréable pendant la réponse, pas d’un libellé revoked rassurant mais faux.
Considérez la séquence d’échec suivante :
- Un processus d’agent reçoit une approbation de session à 09:00 et soumet une modification de production à 09:17.
- L’opérateur remarque une cible inattendue et révoque la session à 09:18:04.
- La cible répond à la requête de 09:17 à 09:18:07, car elle avait déjà mis le travail en file d’attente.
- L’agent tente un autre appel à 09:18:09 et la passerelle le refuse.
Un bon journal conserve les quatre événements. L’action de 09:17 était autorisée lorsqu’elle a commencé. La réponse reçue après la révocation appartient à cette action antérieure. La tentative refusée prouve que la révocation a pris effet pour le travail suivant. Si vous estampillez toutes les actions précédentes comme « révoquées », vous perdez la séquence qui explique l’exposition réelle.
Utilisez un numéro de séquence monotone en plus de l’heure civile. Les horloges peuvent dériver, les utilisateurs peuvent modifier l’heure locale et plusieurs événements peuvent partager la même résolution temporelle. Un numéro de séquence établit l’ordre dans lequel le journal a accepté les enregistrements. Si vous opérez sur plusieurs hôtes, conservez la séquence locale de chaque hôte et utilisez des identifiants de corrélation au lieu de prétendre que les horloges établissent un ordre mondial parfait.
La preuve de falsification dépend d’une discipline append-only
Une chaîne de hachage rend les modifications non détectées plus difficiles en incluant le condensé de l’enregistrement précédent dans chaque nouvel enregistrement. Elle ne transforme pas un fichier journal ordinaire en preuve de l’existence de chaque événement attendu. Une personne qui contrôle le processus d’écriture et la tête de chaîne stockée peut supprimer un suffixe, commencer une nouvelle chaîne ou empêcher les enregistrements d’atteindre un stockage durable.
Cette limite ne rend pas les chaînes de hachage inutiles. Elles répondent à une question plus étroite mais utile : ces enregistrements ont-ils été modifiés, ont-ils disparu du milieu ou sont-ils arrivés dans un ordre différent après leur écriture par le système ? Gardez les champs de chaîne explicites.
{
"journal": {
"sequence": 1842,
"recorded_at": "2025-02-18T21:19:43.024Z",
"previous_hash": "sha256:68b1...",
"record_hash": "sha256:93f4...",
"hash_format": "canonical-json-v1"
}
}
Hachez l’enregistrement canonique complet, en excluant uniquement record_hash. Ne hachez pas une représentation joliment formatée dont les espaces, l’ordre des champs ou le formatage des horodatages changent selon les versions. Versionnez le format canonique et conservez le vérificateur de chaque format émis.
La publication spéciale 800-92 du NIST, Guide to Computer Security Log Management, considère la génération, le stockage, l’analyse et la conservation des journaux comme des responsabilités distinctes. Cette distinction permet d’éviter une erreur fréquente : les équipes ajoutent un hachage aux entrées et considèrent le travail terminé. Il faut également un stockage durable, des contrôles d’accès autour du processus d’écriture, une décision de conservation, des vérifications régulières et une procédure d’enquête en cas d’échec de vérification.
Sallyport projette ses journaux Sessions et Activity à partir d’un journal d’audit chiffré, chaîné par hachage et inscriptible sans possibilité de lecture. Sa commande sp audit verify vérifie la chaîne hors ligne sur le texte chiffré sans nécessiter de clé de coffre. Cette conception sépare la capacité d’un lecteur à vérifier l’intégrité du journal de sa capacité à utiliser des identifiants.
Un identifiant de corrélation unique rend l’enregistrement exploitable sous pression
Attribuez un identifiant d’action à chaque action demandée avant que la passerelle n’évalue l’autorisation. Faites-le suivre la décision locale, la tentative réseau, le traitement de la réponse et tout rappel ultérieur de fin distante. Lorsqu’un ingénieur examine un déploiement contesté, il doit pouvoir rechercher un seul identifiant et retrouver toute la chronologie.
Utilisez des identifiants associés pour les relations différentes. L’action pointe vers sa session, son approbation, sa référence d’identifiant, sa cible et sa séquence de journal. Une référence de tâche ou de conversation peut relier l’action au contexte de l’agent, mais ne faites pas de la transcription de conversation la source de vérité. Le texte des prompts change, peut contenir des informations privées et décrit souvent mal la requête finalement envoyée.
Un enregistrement complet compact peut utiliser cette structure :
{
"schema_version": "1.0",
"action_id": "act_01J8Q2ABR8M7",
"event_type": "action.completed",
"actor": {"session_id": "ses_01J8Q1F9K9Z3", "pid": 48217},
"target": {"kind": "http", "system_id": "release-service-prod"},
"operation": {"name": "promote_release", "request_fingerprint": "sha256:8e8c..."},
"authorization": {"vault": "unlocked", "approval_id": "apr_01J8Q1P4Y5D6", "decision": "approved"},
"result": {"outcome": "target_accepted", "http_status": 202},
"journal": {"sequence": 1842, "previous_hash": "sha256:68b1..."}
}
N’utilisez pas l’identifiant de corrélation comme jeton d’autorisation. Générez-le indépendamment, rendez-le imprévisible lorsque des appelants externes peuvent l’observer et n’acceptez jamais la possession de cet identifiant comme permission de lire une action ou d’effectuer un appel de suivi.
La conservation doit préserver les preuves sans créer un second dépôt de secrets
Les données d’audit accumulent des informations privées même lorsque vous les expurgez rigoureusement. Les noms de cibles peuvent révéler des clients, les paramètres de route des projets internes, les résumés de réponse l’état d’un compte et les chemins de processus les habitudes des développeurs. Décidez qui peut rechercher les enregistrements, qui peut les exporter et pendant combien de temps chaque catégorie reste disponible.
Séparez les métadonnées d’action consultables des preuves de requête ou de réponse chiffrées. Appliquez une conservation plus courte aux preuves détaillées lorsque le besoin d’enquête disparaît. Conservez les hachages et les enregistrements de liaison assez longtemps pour prouver que les résumés restants correspondent toujours à ce que le système a enregistré.
Testez le modèle avec une question réelle d’une revue d’incident : « Quel processus signé a demandé l’accès à cette cible de production, sous quelle approbation, et une tentative s’est-elle poursuivie après la révocation ? » Si une requête oblige un analyste à relier des messages non structurés, à inspecter les journaux de débogage du client ou à demander à l’agent ce dont il se souvient, le modèle est incomplet.
La chaîne de décision fixe de Sallyport donne à ce modèle des limites claires : la passerelle du coffre, l’autorisation de session et l’approbation de l’identifiant par appel produisent chacune un fait d’autorisation distinct. Gardez ces faits séparés dans votre propre conception d’audit. L’enregistrement doit montrer où l’autorité s’est arrêtée, plutôt que de cacher chaque refus sous un code d’échec générique.
Construisez le schéma avant que les agents n’obtiennent des identifiants étendus. Ajouter après un incident l’identité de l’acteur, la portée de l’approbation et l’ordre des révocations revient à reconstituer l’autorité à partir de lacunes. Ce travail est lent et se termine souvent par un « nous pensons que », alors que l’enregistrement aurait dû dire exactement ce qui s’est passé.
FAQ
Quelle est la différence entre un journal de session d’agent et un journal d’audit des actions ?
Un journal de session indique qu’un processus a existé pendant une certaine période. Un enregistrement d’audit d’action indique ce que ce processus a demandé, quelle cible a reçu la requête, quelle limite d’identifiants s’est appliquée, si une personne l’a approuvée et ce qui s’est passé. Les deux sont nécessaires, car une session révoquée peut avoir effectué de nombreux appels avant sa révocation.
Un enregistrement d’audit doit-il conserver uniquement les actions d’agent réussies ?
Non. Un statut HTTP réussi décrit seulement la réponse visible par l’appelant. Enregistrez le résultat du transport, le code de statut, un résumé limité de la réponse et toute erreur d’exécution détectée localement. L’enquête pourra ainsi distinguer un refus, un délai d’attente et une modification distante terminée.
Comment identifier un système cible sans enregistrer de secrets ?
Utilisez un identifiant interne stable pour la cible et une description expurgée, par exemple un hôte API et un modèle de route, ou un alias d’hôte SSH et une classe de commande. Ne conservez pas par défaut les identifiants bruts, les en-têtes d’autorisation, les jetons dans les URL ni les corps de requête complets. Un journal qui copie des secrets manque son propre objectif de sécurité.
Pourquoi l’autorité de signature du code doit-elle figurer dans un journal d’audit d’agent ?
Enregistrez le chemin de l’exécutable, l’identifiant du processus, celui du processus parent lorsqu’il est disponible, l’heure de lancement et l’autorité de signature du code. L’autorité de signature répond à une question différente du nom du processus : elle aide à distinguer un binaire attendu d’un autre programme utilisant un nom familier.
Comment enregistrer une approbation de session par rapport à une approbation par action ?
Une approbation peut couvrir une session de processus, tandis qu’une autre peut couvrir une utilisation unique d’un identifiant sensible. L’enregistrement doit préciser la portée de l’approbation et sa décision. Sans cette portée, les personnes chargées de l’examen risquent de supposer qu’une approbation antérieure autorisait un appel ultérieur à fort impact, alors que ce n’était pas le cas.
La révocation doit-elle écraser les actions approuvées précédemment ?
Conservez les enregistrements d’action d’origine de manière immuable et ajoutez un événement de révocation qui indique la session ou l’autorisation concernée. Ne réécrivez pas les anciens enregistrements pour dire qu’ils sont devenus non autorisés plus tard. L’ordre temporel montre exactement quels appels ont eu lieu avant la prise d’effet de la révocation.
Un journal d’audit chaîné par hachage peut-il prouver qu’une action d’agent était sûre ?
Une chaîne de hachage détecte la suppression, l’insertion ou la modification lorsque l’état attendu de la chaîne est conservé et que la séquence est vérifiée. Elle ne détermine pas si une action approuvée était judicieuse et ne prouve pas qu’un système distant a respecté une requête. Associez-la à des enregistrements précis et, si nécessaire, aux journaux du système distant.
Que faut-il enregistrer pour les requêtes HTTP effectuées par des agents IA ?
Commencez par une empreinte de requête plutôt que par son corps brut. Conservez la méthode, le modèle de route, les paramètres non secrets sélectionnés, la longueur du corps et une empreinte cryptographique d’une représentation canonique expurgée. Ne conservez séparément des preuves chiffrées que si vos besoins d’enquête et vos règles de conservation le justifient.
Que doit contenir un enregistrement d’audit d’action SSH ?
Enregistrez la destination SSH, l’empreinte de la clé d’hôte ou la référence à l’entrée known-hosts, le libellé du compte distant s’il n’est pas secret, la classe de commande et des résumés limités de stdout et stderr. Considérez la ligne de commande complète comme sensible, car elle contient souvent des chemins, des identifiants et des jetons accidentels.
À quelles questions une piste d’audit des actions d’un agent doit-elle répondre ?
Lors d’un incident, il doit être possible de reconstituer qui a lancé l’acteur, ce qu’il a demandé, quelle approbation l’a gouverné, quelle cible l’a reçu, quel résultat est revenu et si la révocation a modifié l’autorité du processus. Si un enregistrement ne répond pas à l’une de ces questions, ajoutez un champ ou un événement associé.