# J'ai coupé mon assistant en deux

Langue : fr

Identifiant : article:agent-personnel-deux-profils

Noa Matout

J'ai séparé mon agent personnel en deux profils. J'ai trouvé six pannes, dont cinq silencieuses.

J'ai installé un agent personnel sur un serveur, avec l'idée classique : un
assistant qui lit mes mails, suit mon agenda, surveille mes entraînements et fait
ma veille technique. Un seul agent, tous mes accès, accessible depuis mon
téléphone.

J'ai changé d'avis avant la fin de l'installation. Voici pourquoi, et surtout ce
que j'ai découvert ensuite, parce que la partie intéressante n'est pas la
conception. C'est ce qui a cassé.

## Trois ingrédients qu'il ne faut pas mélanger

Un agent devient dangereux quand trois choses se rejoignent chez lui : l'accès à
des données privées, l'exposition à du contenu que je n'écris pas, et un moyen de
sortir vers l'extérieur.

Pris séparément, chacun est banal. Ensemble, ils forment une chaîne complète. Une
page web ou un mail peut contenir une consigne déguisée. L'agent la lit comme du
texte à traiter, mais rien ne distingue au fond une donnée d'une instruction dans
ce que reçoit un modèle. S'il dispose en même temps de mes mails et d'un moyen
d'émettre, la consigne cachée devient une action.

C'est pour ça que j'ai arrêté de chercher la bonne formulation de consigne
défensive. Une règle écrite dans un fichier de configuration reste une
suggestion. Ce que je voulais, c'était une séparation que l'agent ne puisse pas
franchir même s'il le décidait.

## Des comptes séparés, un sens de circulation

J'ai donc deux profils, qui tournent sous
deux comptes Unix distincts sur la même machine.

Le premier a mes accès personnels : mails, agenda, notes, données sportives. Il
n'a aucun accès au web. Le second fait la veille : il lit des dépôts, des
bulletins de sécurité, des publications économiques. Il n'a accès à rien qui me
concerne, et il ne peut ni envoyer ni publier.

Chacun a son propre bot de messagerie et sa propre clé d'API. Si je dois révoquer
le profil exposé au web, je ne coupe pas celui qui lit mes mails.

Entre les deux, un répertoire d'échange, dans un seul sens. Le profil de veille
dépose des fichiers datés. Le profil personnel les lit comme des données, jamais
comme des instructions, et cette phrase est écrite dans sa configuration en
toutes lettres. Ce n'est pas une garantie, c'est une couche de plus. Le profil de veille n'a aucune clé permettant d'atteindre quoi
que ce soit chez moi.

J'ai ajouté un troisième compte, qui ne fait tourner aucun agent. Il lit la
configuration des profils et la pousse toutes les heures dans un dépôt Git
privé. Les agents n'ont ni Git, ni clé de dépôt : ce serait leur donner un canal
de sortie. Ce compte existe pour une seule raison : un agent qui réécrit ses
propres instructions doit laisser une trace que je peux relire.

## Les pannes

La conception ci-dessus a tenu. Ce qui n'a pas tenu, c'est tout le reste. Je les
donne dans l'ordre où je les ai trouvées, parce que l'ordre raconte quelque
chose.

**J'ai écrit des services système dont l'outil n'avait pas besoin.** Mes unités
pointaient sur un chemin de binaire faux et sur une sous-commande qui n'existe
pas. Elles ont redémarré en boucle 6 000 fois pendant que le service livré
avec l'outil tournait très bien à côté. Leçon : avant d'écrire une unité, je
vérifie si le logiciel en installe déjà une.

**Un masque ACL a coupé ma surveillance sans un mot.** J'avais donné au compte
d'audit un droit de lecture par ACL. L'agent remet périodiquement les permissions
de son dossier de configuration, et un simple changement de permissions
recalcule le masque de l'ACL et le met à zéro. L'entrée restait visible dans
`getfacl`, mais devenue sans effet. La surveillance a échoué toutes les heures
pendant deux jours. Je ne l'ai vu qu'en constatant l'absence de nouveaux commits.

**Les sorties des tâches planifiées partaient dans le vide.** Sur un serveur, la
sortie d'une tâche cron part dans un courrier local que personne ne lit. Une
tâche qui échoue toutes les heures est donc parfaitement silencieuse. J'ai
redirigé les sorties dans un fichier de journal et j'ai donné à chaque tâche une
destination en cas d'échec, vers ma messagerie.

**Une boucle de surveillance se réveillait 288 fois par
jour** pour une livraison réelle. Elle sondait un répertoire toutes les cinq
minutes. Il existait pourtant une unité de déclenchement au dépôt de fichier,
écrite mais désactivée, avec la même erreur de chemin que la mienne. Elle
surveillait en plus la condition « répertoire non vide » sur un répertoire
contenant un sous-répertoire d'archives, donc jamais vide. Corrigée en
surveillance de changement, elle se déclenche une fois par dépôt.

**L'authentification par mot de passe SSH était toujours active.** Le fichier de
configuration principal disait bien non. Mais les images serveur déposent un
fichier annexe qui réactive l'option, et le démon retient la première valeur
lue, donc celle du fichier au numéro le plus bas. J'avais modifié le mauvais
fichier et vérifié en relisant ce que je venais d'écrire, au lieu d'interroger la
configuration effective.

**La sauvegarde ne contenait pas les planifications.** Elle tournait sous le
compte d'audit, qui n'a pas le droit de lire le dossier des tâches. Une
restauration m'aurait rendu un agent complet et sans aucune de ses tâches. En la
passant sous le compte administrateur, j'ai aussi découvert qu'elle emportait
deux gigaoctets d'environnement d'exécution réinstallable. Après ajustement des
exclusions : 85 mégaoctets, planifications comprises.

## Ce que je retiens

Sur six pannes, cinq étaient silencieuses. Aucune n'aurait produit d'erreur
visible avant des semaines. C'est la vraie difficulté de ce genre de montage :
un agent qui répond correctement quand je lui parle peut très bien avoir cessé
de faire tout le reste.

Je vérifie donc maintenant les effets, pas les intentions. Je ne relis pas un
fichier de configuration pour savoir si une option est active, j'interroge le
service. Je ne regarde pas si une tâche existe, je regarde si elle a produit
quelque chose. Je ne suppose pas qu'un droit est accordé parce qu'il est écrit,
j'essaie de lire le fichier avec le compte concerné.

Et je donne à chaque chose automatique un moyen de crier. Une sauvegarde qui
échoue doit me le dire. Une surveillance qui ne surveille plus doit me le dire.
C'est moins élégant qu'une architecture propre, et c'est ce qui m'a fait gagner
le plus de temps.

## Ce que je n'ai pas encore réglé

Le répertoire d'échange reste un pont entre les deux profils. Un fichier
déposé par l'agent de veille finit lu par celui qui détient mes accès. Sa
configuration lui dit de traiter ces fichiers comme des données. Je préférerais
une barrière technique à une consigne.

Au moment de ces essais, je n'avais pas non plus de mesure du coût. Le tarif
de mon modèle n'était pas connu de l'outil, donc le journal quotidien ne pouvait
pas dire ce que la journée avait coûté. Pour une machine censée être auditable
rapidement, c'était une lacune.

## Périmètre de la mesure

profiles : 2 profils. Profils de mon agent personnel, chacun sous un compte distinct.

agentSetupFailures : 6 pannes. Pannes constatées après la séparation de mon agent personnel.

silentFailures : 5 pannes silencieuses. Sous-ensemble des pannes constatées sans erreur visible dans l'usage courant de mon agent.

serviceRestarts : 6 000 redémarrages. Boucle des unités ajoutées par erreur, pendant que le service fourni fonctionnait.

monitorDays : 2 jours. Durée pendant laquelle la surveillance échouait à chaque passage.

auditInterval : 1 heure. Intervalle prévu entre les sauvegardes de configuration par le compte d'audit.

wakeups : 288 réveils par jour. Boucle de surveillance avant remplacement du sondage par un déclenchement au changement.

pollMinutes : 5 minutes. Intervalle du sondage du répertoire avant sa correction.

backupBefore : 2 Go. Environnement d'exécution réinstallable inclus à tort dans la sauvegarde.

backupAfter : 85 Mo. Taille de la sauvegarde après exclusions, planifications comprises.
