# Les autorisations d'infrastructure des agents IA pour des applications sûres

Les agents IA ne devraient pas recevoir une autorisation permanente qui signifie « appliquer des changements d'infrastructure ». Ils devraient recevoir une autorisation limitée et temporaire pour appliquer un changement examiné à un compte cible vérifié, avec une procédure de récupération qu'un opérateur a lue et acceptée.

J'ai vu des équipes prendre un plan Terraform pour un contrôle de sécurité et un bouton d'approbation pour une décision. Aucun des deux ne suffit seul. Un plan peut être régénéré contre un autre compte. Une approbation peut rester valide après la modification d'un commit. Une note de restauration peut dire « annuler » alors que le changement détruit des données ou modifie une dépendance qui n'existe plus.

La frontière utile est plus exigeante : l'agent prépare les preuves, une personne les examine et le chemin d'exécution refuse de continuer si ces preuves ne décrivent plus l'action. Cela peut sembler tatillon jusqu'au jour où un assistant récupère le mauvais profil cloud, lit un instantané d'état obsolète et envoie une commande parfaitement valide vers la production.

## L'autorisation doit lier une action, pas un intitulé de poste

Les autorisations d'infrastructure pour agents IA doivent permettre une modification concrète, et non une catégorie comme « déployer », « Terraform » ou « opérations de production ». Les catégories générales semblent pratiques parce que les humains raisonnent en rôles. Les API cloud exécutent pourtant des requêtes, et ces requêtes ont des cibles, des paramètres, des identités et des conséquences.

Une autorisation d'application utile lie au minimum les faits suivants :

- La révision source immuable et le répertoire de configuration utilisés pour créer le plan.
- L'artefact de plan examiné ou son condensat SHA-256.
- L'identité du compte cloud ou du tenant cible, telle qu'elle est signalée par l'identifiant d'exécution.
- L'identité d'exécution, le rôle, l'abonnement, le projet et, le cas échéant, la région autorisée.
- Une date d'expiration et une référence de récupération indiquant à l'opérateur ce qui se passe si l'application doit être arrêtée ou inversée.

La différence entre l'autorisation de *calculer* un changement et celle de *l'effectuer* est importante. Laissez un agent inspecter les dépôts, appeler des API en lecture seule, lancer des validations et proposer un plan. Ne considérez pas automatiquement ces activités comme la preuve qu'il peut modifier la production. L'accès de découverte expose souvent des détails opérationnels. L'accès de modification change la facture, la disponibilité et parfois les preuves encore disponibles après un incident.

Un rôle nommé `InfrastructureDeployer` n'est pas un objet d'approbation. C'est un détail d'implémentation. S'il peut appliquer n'importe quel changement dans n'importe quel compte dès qu'un processus l'obtient, votre processus d'approbation dépend du fait que chacun pense à l'utiliser correctement. Les agents sont assez rapides pour transformer ce test de mémoire en incident.

## Le plan examiné doit être exactement l'artefact appliqué

Un plan examiné n'a de valeur que si la commande d'application consomme ce même plan. Relancer `terraform plan` après l'approbation produit un nouvel artefact, même si les fichiers semblent inchangés.

La documentation des commandes Terraform établit clairement cette distinction. `terraform plan -out=FILE` écrit un fichier de plan destiné à `terraform apply FILE` ; `terraform apply` sans plan enregistré crée un nouveau plan avant de demander une confirmation. La deuxième forme convient à une session humaine interactive. Elle ne convient pas à un workflow d'agent qui affirme qu'un humain a examiné les changements proposés.

Utilisez un plan enregistré et rendez-le en JSON pour la revue. Une séquence shell minimale ressemble à ceci :

```sh
set -euo pipefail

git rev-parse HEAD > evidence/source-revision.txt
terraform init -lockfile=readonly
terraform plan -out=evidence/change.tfplan
terraform show -json evidence/change.tfplan > evidence/change.json
shasum -a 256 evidence/change.tfplan > evidence/change.tfplan.sha256
terraform providers lock -platform=darwin_arm64
```

Le condensat produit a une forme simple :

```text
f1f5f2...a94c  evidence/change.tfplan
```

Le registre d'approbation doit reprendre le condensat complet, et pas seulement joindre une capture d'écran du terminal. Le runner d'application le vérifie ensuite avant l'exécution :

```sh
shasum -a 256 -c evidence/change.tfplan.sha256
terraform apply -input=false evidence/change.tfplan
```

Cela évite un échec fréquent : l'agent ouvre une pull request, produit un plan, obtient un commentaire d'approbation, puis récupère la dernière version de la branche principale et exécute un nouveau plan. Un collègue a pu fusionner une autre modification entre ces étapes. Le plan ultérieur peut ajouter une suppression, changer une version d'image ou pointer vers un autre alias de fournisseur. Le réviseur a approuvé le graphe proposé la veille, pas ce que le runner voit maintenant.

Un plan Terraform binaire peut contenir des valeurs sensibles. Ne le copiez pas dans des tickets ou des conversations. La représentation JSON peut également révéler des informations sensibles selon les schémas et les valeurs des fournisseurs. Ne faites des suppressions qu'avec une procédure de revue que vous maîtrisez. La redaction ne doit pas retirer les adresses des ressources, les actions, l'identité cible ou les changements de dépendances. Ce sont précisément les faits dont l'approbateur a besoin.

Le modèle du plan enregistré est particulièrement solide lorsque l'environnement d'exécution est lui aussi figé. Utilisez le même fichier de verrouillage des fournisseurs, la même version de Terraform, les mêmes variables, la même configuration du backend et le même espace de travail que lors de la création du plan. Si l'une de ces entrées change, abandonnez le plan et générez un nouveau dossier de revue. Tenter de sauver une ancienne approbation transforme un contrôle raisonnable en théâtre.

## La cible nommée doit venir de l'identifiant, pas d'un libellé

Une cible appelée `prod` ne prouve presque rien. Les dépôts copient les noms de répertoires. Les espaces de travail dérivent. Les variables d'environnement restent dans les shells. Un agent peut suivre fidèlement une configuration appelée production tout en étant authentifié sur un bac à sable ou, pire encore, sur un compte de production sélectionné par un profil hérité.

Demandez à l'identité d'exécution de vérifier auprès du plan de contrôle cloud qui elle est avant la planification, puis immédiatement avant l'application. Enregistrez le résultat dans le dossier de preuves et comparez-le à la cible approuvée.

Pour une action fondée sur AWS, le contrôle peut être aussi simple que ceci :

```sh
aws sts get-caller-identity --output json > evidence/caller-identity.json
cat evidence/caller-identity.json
```

Le résultat identifie le compte et le principal :

```json
{
  "UserId": "AROAXXXXX:apply-run",
  "Account": "123456789012",
  "Arn": "arn:aws:sts::123456789012:assumed-role/InfraApply/apply-run"
}
```

Pour Google Cloud, enregistrez séparément le compte actif et le projet. Pour Azure, enregistrez l'identifiant d'abonnement et l'identifiant de tenant du contexte d'identification. Ne vous fiez pas au nom affiché d'un compte cloud, car ces noms peuvent être dupliqués. Les identifiants numériques ou globalement uniques sont moins agréables à lire, mais beaucoup plus sûrs à exécuter.

Le contrôle préalable à l'application doit utiliser le même chemin d'identification que l'application. Cela semble évident, mais les wrappers l'enfreignent souvent. Un script de planification peut utiliser un rôle assumé de courte durée tandis qu'une commande ultérieure récupère le profil par défaut d'un développeur. Un agent qui appelle un runner distant peut planifier localement, puis appliquer à distance sous une identité de service qu'il n'a jamais inspectée.

Ajoutez au runner une assertion de cible vérifiable par machine. Cet exemple refuse un compte AWS inattendu :

```sh
expected_account="123456789012"
actual_account="$(aws sts get-caller-identity --query Account --output text)"

if [ "$actual_account" != "$expected_account" ]; then
  printf 'refusing apply: expected account %s, got %s\n' \
    "$expected_account" "$actual_account" >&2
  exit 1
fi
```

Ce contrôle ne remplace pas la revue humaine. Il intercepte toute une catégorie d'erreurs avant qu'une API ne modifie l'infrastructure. Associez-le à une configuration du fournisseur qui déclare le compte ou l'abonnement autorisé lorsque le fournisseur prend cette protection en charge. Une assertion au niveau du fournisseur et une autre au niveau du runner échouent indépendamment, ce qui est exactement le but recherché.

## La dérive de l'état rend les anciennes approbations dangereuses

Un plan décrit le changement souhaité par rapport à un état observé à un moment donné. Il ne garantit pas que cet état existera encore une heure plus tard.

Un autre ingénieur peut déployer. Un autoscaler peut ajouter ou supprimer des ressources. Un service cloud peut faire tourner une pièce jointe, remplacer un nœud ou terminer une opération asynchrone. Terraform détectera souvent une partie de ces changements lors de l'actualisation de l'état, mais la bonne réponse à une différence importante n'est pas de continuer parce que le plan semblait limité auparavant. Générez un nouvel artefact et examinez le nouveau diff.

L'expiration règle une grande partie du problème. Faites en sorte qu'une approbation soit assez courte pour qu'un humain se souvienne encore de la raison pour laquelle il l'a acceptée. La durée dépend de votre processus de publication, mais elle doit couvrir une fenêtre d'exécution définie plutôt qu'une journée entière par défaut. Une fois cette fenêtre fermée, imposez un nouveau plan, répétez la vérification de la cible et demandez une nouvelle approbation.

Vous avez aussi besoin d'une règle d'invalidation. Refusez un plan si l'un des éléments suivants change après la revue :

- La révision source, l'ensemble de variables, la référence de module ou le fichier de verrouillage du fournisseur.
- L'espace de travail, le backend, le compte, l'abonnement, le tenant, le projet ou la région diffère des preuves approuvées.
- Le condensat du plan ne correspond pas au registre d'approbation.
- Un verrou d'état, une actualisation ou une précondition pertinente signale un conflit qui modifie l'action proposée.

Ne remplacez pas cette règle par « aucun changement dans la pull request ». Les sources de données externes, les valeurs par défaut des fournisseurs, l'état actuel et les identifiants se trouvent en dehors du diff. L'infrastructure comporte trop d'entrées pour qu'une approbation fondée uniquement sur le code source porte toute la décision.

Certaines équipes tentent de résoudre la dérive en autorisant l'agent à replanifier automatiquement jusqu'à obtenir un plan propre. Cette recommandation est populaire parce qu'elle réduit l'attente. Elle est mauvaise pour les comptes sensibles. La replanification automatique peut transformer une mise à jour examinée en remplacement non examiné. Autorisez-la pour un aperçu en lecture seule si vous le souhaitez, mais exigez une nouvelle revue humaine avant toute modification.

## La restauration doit décrire un état récupérable

Un chemin de restauration clair explique comment ramener le service à un état acceptable, qui peut agir, quelles données sont exposées et quand il faut s'arrêter. « Lancez Terraform destroy » et « annulez le commit » répondent rarement à cette exigence.

Les changements d'infrastructure appartiennent à différentes catégories de récupération. Les traiter de la même manière crée une fausse confiance.

Une modification de configuration réversible, comme une règle de groupe de sécurité ou un poids de load balancer, peut permettre une application inverse directe depuis une révision connue comme bonne. Le remplacement d'un groupe d'instances peut nécessiter des vérifications de capacité avant l'inversion. Une migration de base de données peut devenir irréversible après l'écriture des données. Le chemin de récupération peut alors être une migration corrective, une restauration depuis une sauvegarde vérifiée ou un indicateur de fonctionnalité qui bloque les nouvelles écritures.

Écrivez le chemin de restauration dans un langage opérationnel. Un bon enregistrement répond aux questions suivantes :

1. Quelle condition observable indique qu'il faut restaurer, par exemple des contrôles de santé en échec, une hausse du taux d'erreur ou un test de fumée défaillant ?
2. Quelle révision, quel jeu de paramètres ou quelle commande exacte ramène le service à la configuration connue comme bonne ?
3. Quel prérequis doit d'abord exister, comme un point de restauration de sauvegarde, une capacité disponible ou une fenêtre de maintenance approuvée ?
4. Qui est autorisé à agir si la session de l'agent est terminée ou si l'approbateur initial n'est pas disponible ?
5. Que ne peut-on pas restaurer automatiquement, notamment les enregistrements, les secrets, les adresses publiques ou les changements cloud manuels ?

Un chemin de récupération doit être testé avant l'incident, et non résumé par une phrase optimiste pendant celui-ci. Si une équipe qualifie un changement de réversible, exécutez l'inversion dans un environnement représentatif et consignez les conditions qui l'ont rendue possible. Les fournisseurs peuvent conserver le nom d'une ressource supprimée, les quotas peuvent empêcher sa recréation et les services dépendants peuvent mettre en cache un ancien endpoint. Ces détails apparaissent lorsque le changement est déjà sous pression.

Pour les changements destructeurs, exigez une décision séparée. Supprimer une ressource après la revue d'un plan n'est pas équivalent à la mettre à jour. L'agent doit présenter les adresses supprimées, les actions de remplacement, les paramètres de rétention et les preuves de sauvegarde dans un format qui ne puisse pas disparaître au milieu de centaines de mises à jour anodines. Si le changement concerne une base de données, un stockage d'objets, une liaison d'identité, une limite réseau ou une zone DNS, demandez au responsable de la récupération de lire le plan.

## Le runner d'application doit refuser l'ambiguïté

Le runner qui effectue la modification doit vérifier lui-même les faits de l'approbation. Un bot qui peut recevoir un message disant « vas-y » n'a aucun moyen fiable de distinguer un plan confirmé d'une instruction lancée à la légère.

Utilisez un registre d'approbation structuré. Il peut se trouver dans un système de déploiement signé, un enregistrement protégé du dépôt ou un autre espace contrôlé. Le choix du stockage compte moins que les champs et leur vérification. Ce JSON illustre la structure :

```json
{
  "change_id": "infra-2025-041",
  "source_revision": "4ad7d2f",
  "plan_sha256": "f1f5f2...a94c",
  "target": {
    "cloud": "aws",
    "account_id": "123456789012",
    "region": "us-east-1",
    "workspace": "production"
  },
  "approved_by": "operator-id",
  "expires_at": "2025-04-18T15:30:00Z",
  "rollback_ref": "runbook: payments-api capacity revert"
}
```

L'agent peut préparer cette demande, mais il ne doit pas écrire `approved_by` ni prolonger `expires_at`. Le service d'approbation doit ajouter ces faits après qu'une personne a vu le changement présenté. Le runner lit le registre, recalcule le condensat du plan, vérifie la révision source et l'identité cible, puis marque l'autorisation comme consommée avant d'envoyer la première requête d'écriture.

Consommer une approbation est important. Sans cette étape, un agent peut relancer plus tard une action approuvée alors que l'environnement a changé. Une application échouée a également besoin d'un statut explicite. Ne la marquez pas comme terminée simplement parce que le runner a lancé une commande. Enregistrez si Terraform a renvoyé un succès, si une opération d'API cloud reste en attente et si un opérateur a accepté l'état obtenu.

Gardez la surface d'écriture de l'agent limitée. Il peut avoir besoin d'appels HTTP pour des API de déploiement ou d'un accès SSH à un runner contrôlé, mais ne recevez jamais un secret cloud réutilisable dans son contexte. Sallyport conserve les identifiants API et SSH dans son coffre chiffré pendant l'action demandée et renvoie le résultat à l'agent. Cette configuration aide à empêcher la copie des identifiants, mais elle ne rend pas sûre une demande d'application vague.

## L'autorisation par appel doit encadrer la frontière dangereuse

L'autorisation par appel a sa place dans le travail d'infrastructure, mais elle ne remplace pas la revue de l'artefact. Si un agent demande une autorisation pour chaque appel à une API cloud, les opérateurs valideront une longue série d'appels sans comprendre le résultat global. C'est la fatigue liée aux approbations, et elle apprend aux utilisateurs à cliquer machinalement sur le seul contrôle disponible.

Faites intervenir l'humain là où il prend une décision utile : approuver un plan lié à une cible, puis autoriser une application limitée. Réservez les confirmations individuelles aux actions présentant un rayon d'impact inhabituel, comme la rotation de secrets, la suppression d'un objet protégé, un accès d'urgence ou une commande en dehors du contrat attendu du runner.

L'autorisation par session de Sallyport peut établir qu'un processus d'agent précis peut utiliser un canal d'action pendant son exécution courante, tandis que les clés par appel peuvent exiger une confirmation séparée pour les identifiants sensibles. C'est une frontière claire pour les identifiants. Votre workflow de déploiement doit toujours définir quel appel compte comme une application approuvée et quels identifiants justifient une friction à chaque appel.

Un humain doit voir suffisamment de preuves pour décider sans lire le trafic brut du fournisseur. Affichez les adresses des ressources regroupées par action, les remplacements et suppressions séparément, l'identité cible, la révision source, le condensat, l'expiration et la référence de restauration. Donnez ensuite accès au plan complet à la personne qui en a besoin. Masquer un changement destructeur parmi une centaine de mises à jour est un problème de présentation, pas un problème d'opérateur.

## Une application échouée exige une décision différente d'une application réussie

Terraform peut renvoyer une erreur après avoir modifié plusieurs ressources. Les plans de contrôle cloud peuvent également accepter une requête et la terminer plus tard. Considérer tout code de sortie différent de zéro comme la preuve que « rien ne s'est passé » est l'une des habitudes les plus dangereuses des opérations automatisées.

Lorsqu'une application échoue, bloquez les nouvelles tentatives automatiques. Capturez la sortie du runner, les informations du verrou d'état, l'identité cible et les ressources qui ont effectivement été traitées. Examinez ensuite l'environnement réel avant de choisir une réponse. Une nouvelle tentative aveugle peut aggraver un échec partiel, tandis qu'une restauration immédiate peut supprimer une ressource intermédiaire que le fournisseur est encore en train de créer.

Suivez cette séquence de décision :

1. Confirmez l'identité cloud actuelle et recueillez l'état réel de chaque ressource mentionnée dans l'opération échouée.
2. Déterminez si l'état souhaité peut être terminé sans danger, s'il peut être inversé sans danger ou s'il faut un plan de réparation.
3. Générez un nouveau plan à partir de l'état actuel et faites-le examiner par un opérateur comme un nouveau changement.
4. Enregistrez la décision liée à l'incident à côté de l'approbation initiale, y compris les actions manuelles que Terraform ne peut pas représenter.

C'est ici que les journaux d'audit prouvent leur utilité. Conservez ensemble la révision source, le condensat du plan, l'identité de l'approbateur, les preuves de la cible, la transcription des commandes, l'état obtenu et la décision de suivi. Une piste d'événements résistante aux altérations vaut mieux que des captures d'écran dispersées dans des conversations, car les intervenants doivent établir la séquence et non reconstruire l'intention de mémoire.

Ne promettez pas que l'automatisation annulera chaque application échouée. Certains changements nécessitent une personne qui comprend les dépendances du service, la durabilité des données et l'impact client. L'agent peut recueillir rapidement les preuves. Il ne doit pas inventer une opération de récupération parce que le pipeline attend un résultat positif.

## Rendez le premier déploiement en production volontairement banal

La première application en production pilotée par un agent doit modifier quelque chose de petit, réversible et observable. Choisissez un ajustement de configuration connu, accompagné d'une procédure de récupération déjà testée, plutôt qu'une migration, une refonte du réseau ou une rotation de secrets touchant plusieurs consommateurs.

Exécutez le workflow complet dans des conditions normales : créez le dossier de preuves, vérifiez le compte exact, examinez le plan présenté, approuvez le condensat, appliquez l'artefact enregistré, inspectez le résultat et consommez l'autorisation. Organisez ensuite un exercice d'échec contrôlé. Faites expirer une approbation, modifiez la révision source ou dirigez le runner vers un compte non approuvé, puis vérifiez qu'il refuse d'agir.

Ces tests de refus comptent davantage qu'un déploiement réussi dans le meilleur des cas. Tous les outils semblent disciplinés lorsque le compte, le plan et l'état coïncident. Le contrôle fait ses preuves lorsqu'un opérateur pressé, un artefact obsolète ou un agent désorienté lui demande de faire la mauvaise chose et qu'il s'arrête.

N'élargissez pas le modèle d'autorisation parce que le premier déploiement semble lent. Mesurez ce qui prend du temps lors de la revue. Si les utilisateurs passent du temps à comparer des identifiants de compte, améliorez l'affichage des preuves. Si les plans contiennent trop de changements sans rapport, corrigez la responsabilité des modules ou les frontières d'état. Si les notes de restauration sont faibles, demandez aux équipes de service de les rédiger et de les tester. Un accès permanent et général ne corrige pas un processus de publication maladroit ; il masque simplement sa faiblesse jusqu'à ce qu'un agent l'atteigne.
