Secret Guard et les gateways LLM locaux : protéger les secrets quand l'agent les utilise

Un agent qui fait du travail sérieux ne se contente pas de répondre à des questions : il appelle des outils, ouvre des connexions, interroge des bases de données. Et pour cela, il a besoin de secrets — clés API, jetons, identifiants. Le problème, c'est que ces secrets entrent dans le contexte de l'agent, et de là, ils finissent dans le prompt envoyé au modèle.
Imaginez un employé à qui vous confiez la clé du coffre-fort, puis que vous laissez travailler dans le couloir : la clé reste dans ses poches, visible de quiconque passe à côté. Le gateway local fait l'inverse : le secret reste sur votre matériel, et le modèle ne reçoit qu'une copie d'essai sans aucune valeur hors de cette porte.
Comment fonctionne le redact
Secret Guard (https://github.com/luochen1990/secret-guard) est un gateway en Rust, licence MIT, qui s'installe entre votre agent et le provider. Deux étapes, une par direction :
- Redact en sortie : quand la requête passe par le gateway, chaque valeur de secret qu'il trouve est remplacée par un mock réaliste : même longueur, même charset. Pour le modèle, un token API de 32 caractères ressemble à un token API de 32 caractères — le prompt ne casse pas et la structure qui préserve le prefix caching du provider reste intacte.
- Restore en entrée : la réponse repasse par le gateway, qui remet les mock à leurs valeurs réelles. Si un appel d'outil contient un mock dans ses arguments, c'est pareil : l'agent reçoit la valeur utilisable sans que le modèle ne l'ait jamais vue.
La carte des mock est déterministe et un-à-un : le même secret produit toujours le même mock, et des mock différents ne se chevauchent jamais. C'est la propriété qui préserve le prefix cache — si les mock changeaient au hasard, chaque requête repartirait de zéro.
Les quatre stratégies par secret
Chaque secret enregistré a sa propre politique, et c'est là que tout se joue : il n'existe pas de « cache tout », il y a le choix par cas d'usage.
| Stratégie | Comportement | Quand l'utiliser |
|---|---|---|
redact/restore (par défaut) | Remplace en sortie, remet en entrée | L'outil a besoin de la valeur réelle |
reject | Retourne 503 si le secret est présent dans la requête | Ce secret ne doit jamais sortir, même masqué |
placeholder | Remplace par [REDACTED:{id}] et déclenche une alerte canary s'il réapparaît | Vous voulez juste savoir s'il circule, et où |
monitor | Laisse passer, journalise les traversées | Audit, sans changer le comportement |
Protocoles pris en charge
Le gateway relaie OpenAI Chat Completions, Anthropic, Gemini, Ollama et Responses. Le redact/restore complet fonctionne sur les protocoles OpenAI, Anthropic et Responses, y compris le passage croisé entre protocoles (streaming inclus). Gemini et Ollama sont aujourd'hui en pass-through byte-exact : la redaction pour eux est dans la feuille de route, et si un secret inconnu passait quand même en clair, le gateway répond 503 — l'échec est fermé, pas silencieux.
Mise en place en cinq étapes
cargo install --git https://github.com/luochen1990/secret-guard
cd /opt/secret-guard
secret-guard register --name "stripe" --value "sk_live_xxx"
secret-guard run --port 18787
- Installez le binaire (rustc 1.96+ requis ; il y a aussi un module NixOS
services.secret-guard). - Enregistrez les secrets avec
secret-guard register: ils atterrissent danssecret-guard.state.toml, en clair. Placez-le là où vous le protégez : c'est le fichier à gitignorer et à sauvegarder chiffré. - Démarrez le gateway :
secret-guard run --port 18787. L'interface web de gestion est surhttp://127.0.0.1:8787. - Pointez le client vers le gateway : pour Claude Code, définissez
ANTHROPIC_BASE_URL=http://127.0.0.1:18787et unANTHROPIC_AUTH_TOKENfactice — le gateway relaie avec ses propres identifiants. - Vérifiez : demandez au modèle de répéter une clé enregistrée. Si ça marche, il répond avec le mock — la valeur réelle n'est pas dans le contexte.
Si ça ne va pas : la première chose à vérifier est que le client pointe bien vers le gateway (un curl sur le port 18787), puis que le registre contient le secret — un secret non enregistré n'est jamais intercepté, et le détecteur de suspects optionnel (jamais actif par défaut) signale seulement des valeurs suspectes, sans jamais les enregistrer tout seul.
Et les limites ?
Soyez honnête sur ce que ça couvre et ce que ça ne couvre pas :
- Le modèle ne voit jamais la valeur réelle, mais il peut tenter de la faire sortir par injection de prompt ou par un appel d'outil mal construit : les stratégies
rejectetplaceholderexistent précisément pour ces cas, au prix d'un blocage. - Le fichier d'état est en clair : la protection dépend de l'endroit où vous le mettez, pas du gateway.
- C'est une v0.1.0 : les propriétés critiques (pass-through byte-exact, réversibilité, déterminisme, absence de collisions, routage multi-provider) sont couvertes par des tests property-based et end-to-end, mais la validation sur les providers réels d'Anthropic, Gemini et Ollama est déclarée comme encore à faire dans la feuille de route.
- Configuration par secret : il n'existe pas d'auto-protection ; c'est vous qui déclarez ce qui est un secret, et pour ce que vous ne savez pas en être, le détecteur de suspects est le seul sentinelle.
La comparaison avec les alternatives (LiteLLM, LLM Guard, PasteGuard) est dans le dépôt, dans docs/comparison.md, sur sept dimensions.
Le pattern à retenir
L'idée n'est pas un mot de passe plus long : c'est une frontière. Le secret vit sur votre matériel, le modèle ne voit qu'une ombre réaliste, et la valeur réelle traverse la frontière dans les deux sens sans jamais s'arrêter au milieu. Si vos agents touchent aujourd'hui des données réelles — clients, commandes, documents — cette frontière vaut plus qu'une bonne politique écrite.
Pour comprendre ce qui passe vraiment sur le réseau quand l'IA est locale, lisez Confidentialité : ce qui circule vraiment sur le réseau quand l'IA est locale ; et pour le cadre plus large sur les agents qui travaillent en local, Agents ML qui tournent en local.
Sources
En résumé
Secret Guard est un gateway local en Rust qui intercepte les requêtes de votre agent et remplace les secrets par des mock réalistes avant qu'ils n'atteignent le provider, puis les remets à leurs valeurs réelles dans la réponse. Chaque secret a sa propre stratégie (redact, reject, placeholder, monitor), les protocoles OpenAI, Anthropic et Responses ont la redaction complète, Gemini et Ollama sont en pass-through pour l'instant. Le modèle ne voit jamais les valeurs réelles, le prefix cache reste intact, et l'échec est fermé (503) plutôt que silencieux. C'est une v0.1.0 avec les limites qui vont avec, mais le pattern — une frontière entre l'agent et les secrets — est ce qu'une activité qui fait tourner des agents sur de vraies données devrait avoir dès le départ.
Article généré par IA
Dans ces parcours
Vous avez aimé cet article ?
Abonnez-vous à la newsletter pour recevoir de nouveaux tutoriels et guides.

