Proxy d'identifiants — technique
Comment fonctionne le proxy.
Ce contre quoi il protège. Ce contre quoi il ne protège pas.
Cette page s'adresse aux réviseurs de sécurité, aux testeurs d'intrusion et aux ingénieurs évaluant le modèle de menace du proxy. Elle décrit ce que fait le proxy au niveau du protocole, où se trouvent les identifiants en mémoire et quelles surfaces d'attaque subsistent.
Architecture
Le proxy est un proxy HTTPS MITM basé sur CONNECT. Un agent IA configure HTTPS_PROXY pour qu'il pointe vers lui. Lorsque l'agent effectue une requête HTTPS, le proxy intercepte la connexion TLS, inspecte les en-têtes de requête pour les références d'identifiants, les résout par rapport au coffre-fort Clavitor et transmet la requête avec les identifiants injectés à l'API en amont.
Le proxy écoute par défaut sur 127.0.0.1:1983 — le modèle sidecar où le proxy et l'agent partagent un hôte. Pour les déploiements partagés (un proxy servant plusieurs agents sur un réseau privé, un sidecar de conteneur pour plusieurs charges de travail, un hôte proxy dédié), l'interface d'écoute est configurable via CLAVITOR_PROXY_LISTEN.
Le proxy est un binaire Go autonome. Pas de CGO. Toute la cryptographie du protocole Clavitor passe par une implémentation canonique en Rust compilée en WebAssembly et chargée via wazero au démarrage.
Gestion TLS
Le proxy génère une autorité de certification racine ECDSA P-256 auto-signée lors de la première exécution, persistée dans le répertoire du binaire avec le mode 0600. Pour chaque hôte en amont, un certificat feuille est frappé à la demande, signé par cette AC, et mis en cache en mémoire avec une éviction bornée (1 000 hôtes). Les certificats feuilles sont valides pendant 24 heures et régénérés de manière transparente à la marque des 23 heures pour éviter l'expiration en milieu de session.
L'agent doit faire confiance au certificat CA du proxy. Exportez-le avec clavitor-proxy ca.
Les connexions en amont utilisent TLS 1.3 minimum avec négociation ALPN pour HTTP/2 et HTTP/1.1. Le pool de certificats système est utilisé pour la vérification en amont. Pas d'épinglage de certificat — le proxy fait confiance à ce en quoi le système d'exploitation a confiance.
Les identifiants ne sont jamais mis en cache, jamais écrits sur disque et jamais conservés plus d'une requête HTTP.
| Phase | Où se trouve l'identifiant | Durée |
|---|---|---|
| Au repos dans le coffre-fort | Chiffrement AES-GCM dans la base de données du coffre-fort | Jusqu'à suppression |
| En transit vers le proxy | Réponse JSON chiffrée TLS de l'API du coffre-fort | Un aller-retour HTTP |
| Déchiffré dans le proxy | Mémoire du processus (chaîne Go sur le tas) | Une requête HTTP |
| Injecté dans la requête en amont | Octets chiffrés TLS sur le fil vers l'amont | Une requête HTTP |
Le proxy conserve la clé de déchiffrement des identifiants de l'agent (16 octets) en mémoire pendant toute sa durée d'exécution. Elle est chargée à partir de la configuration sidecar chiffrée (format CLV1) au démarrage et effacée lors d'un arrêt propre. La clé ne quitte jamais le processus.
La configuration sidecar est chiffrée avec AES-128-GCM et HMAC-SHA256 en utilisant des clés déterministes dérivées d'une graine statique. Il s'agit d'une obfuscation, pas d'une confidentialité — la frontière de sécurité réside dans les permissions de fichier (0600) et la possession du fichier. Le format CLV1 est partagé entre le proxy, la CLI et l'extension de navigateur.
Modes de résolution
Mode 1 — espace réservé explicite
L'agent inclut une référence clavitor://Entry/field dans un en-tête de requête. Le proxy recherche l'entrée dans le coffre-fort par son nom, la récupère, déchiffre le champ nommé et substitue l'espace réservé par la valeur réelle.
Si la recherche renvoie zéro ou plus d'un résultat, le proxy renvoie 502 avec un code d'erreur stable. L'espace réservé n'est jamais supprimé et transmis tel quel.
Mode 2 — correspondance d'URL
Lorsqu'aucun espace réservé n'est présent, le proxy demande au coffre-fort les entrées dont le champ URL correspond à l'hôte en amont. S'il existe exactement une correspondance avec une forme de champ reconnue, le proxy injecte automatiquement les identifiants.
Zéro correspondance → passage (aucune attente d'identifiant). Correspondances multiples → 502 avec instructions de désambiguïsation. Forme de champ inconnue → 502.
L'arbre de décision est déterministe : espace réservé présent → résoudre ou échouer. Pas d'espace réservé → correspondance d'URL ou passage. Il n'y a pas de chemin de repli silencieux où une résolution échouée entraîne une requête vers l'amont sans identifiants.
Par défaut, le coffre-fort voit l'ID d'agent du proxy à chaque requête. Les limites de débit, les vérifications de portée et les entrées d'audit sont attribuées au proxy.
Lorsque plusieurs agents partagent une instance de proxy, l'espace réservé peut inclure un ID d'agent : clavitor://agentid@Entry/field. Le proxy envoie cet ID d'agent au coffre-fort, qui applique les portées et les limites de débit de cet agent et enregistre l'accès à son nom. L'ID d'agent est la valeur hexadécimale de 32 caractères affichée sur la page de détails de l'agent dans l'interface utilisateur du coffre-fort.
# Without agent ID — attributed to the proxy Authorization: Bearer clavitor://OpenAI/key # With agent ID — attributed to agent 0102030405060708090a0b0c0d0e0f10 Authorization: Bearer clavitor://0102030405060708090a0b0c0d0e0f10@OpenAI/key
| Déploiement | Modèle d'identité | Isolation |
|---|---|---|
| Un proxy par agent | ID du proxy = ID de l'agent (par défaut) | Complet — binaire, configuration, portée, limites de débit séparés |
| Proxy partagé, pas d'ID d'agent dans l'URL | Tous les agents partagent l'ID du proxy | Portée et limites de débit partagées |
Proxy partagé + agentid@ dans l'URL | Identité par agent | Portée, limites de débit et audit par agent |
L'ID d'agent dans l'URL n'est pas un mécanisme d'authentification — le jeton CVT du proxy authentifie la connexion. L'ID d'agent détermine l'attribution : quelles portées s'appliquent, quelles limites de débit comptent, quelle piste d'audit enregistre l'accès. Le coffre-fort rejette les ID d'agent inconnus avec un échec bruyant.
Sécurité réseau
Protection SSRF
Par défaut, le proxy bloque les connexions en amont vers les réseaux privés (RFC 1918), les métadonnées d'instance cloud (169.254.169.254), les boucles locales, les réseaux locaux et les plages NAT de type carrier-grade. Le DNS est résolu en premier ; toutes les IP retournées sont validées avant l'établissement de la connexion TCP, fermant la fenêtre TOCTOU de re-liaison DNS.
Remplacez avec CLAVITOR_PROXY_ALLOW_PRIVATE=true pour les agents qui accèdent légitimement à des API privées.
Épinglage de cible
L'hôte cible CONNECT est capturé à l'établissement du tunnel et utilisé pendant toute la durée de vie du tunnel. Les requêtes ultérieures dans le tunnel ne peuvent pas être redirigées vers un autre hôte en manipulant l'en-tête Host. Une divergence entraîne un 502.
Cela empêche un agent d'établir un tunnel vers api.openai.com puis d'envoyer des requêtes à internal-service.corp.
Gestion des en-têtes
Les en-têtes de saut en saut sont supprimés des requêtes et des réponses conformément à la RFC 7230 §6.1 : Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, Proxy-Connection, TE, Trailers, Transfer-Encoding, Upgrade.
Set-Cookie est supprimé des réponses en amont pour empêcher les systèmes en amont d'insérer des cookies dans le client HTTP de l'agent.
Les corps de requête et de réponse transitent sans mise en mémoire tampon. Les corps de requête sont limités à 64 Mo par défaut (CLAVITOR_PROXY_MAX_BODY_MB). Les corps de réponse transitent sans limite stricte ; un avertissement de journal est émis lorsque Content-Length dépasse 100 Mo.
En mode de correspondance d'URL, le proxy mappe les étiquettes de champ du coffre-fort aux en-têtes HTTP :
| Étiquette de champ | En-tête injecté |
|---|---|
key, apikey, api_key, token, secret, bearer, access_token | Authorization: Bearer <value> |
x-api-key, api-key | X-API-Key: <value> |
username + password (appariés) | Authorization: Basic base64(user:pass) |
| Tout le reste | Rejeté — ERR-PROXY-052 |
En mode espace réservé, l'agent contrôle quel champ est résolu et où il va. Le mappage ci-dessus ne s'applique qu'au mode de correspondance d'URL.
Chaque échec produit un code stable ERR-PROXY-NNN. Ces codes font partie de l'interface publique du proxy — les agents et les opérateurs peuvent les faire correspondre pour l'alerte et le débogage.
| Plage | Catégorie |
|---|---|
001–019 | Configuration (config, init, génération CA, WASM) |
020–029 | Cycle de vie du démon |
030–049 | Résolution d'espace réservé (URI clavitor://) |
050–069 | Injection par correspondance d'URL |
070–089 | Amont / TLS |
Les champs d'identité sont inaccessibles
Les entrées du coffre-fort prennent en charge trois niveaux de chiffrement. Les champs relevant du Chiffrement du coffre-fort sont des métadonnées en clair. Les champs relevant du Chiffrement des identifiants sont déchiffrés avec la clé de l'agent. Les champs relevant du Chiffrement de l'identité sont chiffrés avec une clé que le serveur et le proxy n'ont jamais vue. Seul le propriétaire du coffre-fort, via sa clé matérielle de sécurité, peut les déchiffrer.
Si un espace réservé fait référence à un champ relevant du Chiffrement de l'identité, le proxy renvoie ERR-PROXY-035. Pas de repli, pas de résultat partiel. Le champ est architecturalement inaccessible depuis le proxy.
Ce contre quoi le proxy ne protège pas
Le modèle de menace du proxy est une compétence compromise ou une injection de prompt qui amène un agent authentifié à récolter des identifiants. Les limites de débit par agent du coffre-fort, les quotas d'entrées uniques et le verrouillage en deux étapes sont les principales défenses. Le proxy ajoute un point d'application au niveau réseau où les identifiants sont résolus par requête et jamais conservés par l'agent.
Le proxy s'exécute sur la même machine que l'agent. Un attaquant ayant un accès root peut lire la mémoire du processus, attacher un débogueur ou intercepter le trafic de boucle locale. Le proxy est une couche d'injection d'identifiants, pas une frontière de sécurité matérielle.
Si l'API en amont renvoie l'identifiant dans sa réponse (par exemple, un point de terminaison "whoami"), l'agent le voit. Le proxy injecte les identifiants dans les requêtes, pas dans les réponses. Il ne filtre pas ce qui revient.
Journalisation
Le proxy enregistre une ligne par CONNECT accepté et émet des lignes d'erreur pour les échecs. Il n'enregistre jamais :
- Valeurs d'identifiants déchiffrées
- URL de requête complètes (les chaînes de requête peuvent contenir des secrets — seuls le schéma, l'hôte et le chemin sont enregistrés)
- Corps de requête ou de réponse
- Clé de déchiffrement des identifiants ou contenu de la configuration sidecar
Lorsque le proxy détecte qu'une réponse 400 de l'amont contient des mots-clés liés à l'authentification (unauthorized, invalid token, etc.), il enregistre un indice de diagnostic suggérant que l'identifiant injecté peut être obsolète. La réponse est transmise inchangée.
Cryptographie
Toute la cryptographie du protocole Clavitor — déchiffrement de champ AES-GCM, dérivation de clé HKDF, encodage base62, frappe de jeton CVT, empaquetage/dépaquetage de configuration CLV1 — s'exécute dans un seul module WebAssembly (clavis_crypto.wasm) chargé via wazero, un runtime WASM pur Go. Pas de CGO. Pas de réimplémentation Go des primitives Clavitor.
Le module WASM est compilé à partir de la même crate Rust (clavis-crypto) utilisée par le navigateur, la CLI et les extensions de navigateur. Une seule source de vérité, un seul binaire, une seule surface d'audit.
Le proxy utilise crypto/tls de Go pour le fil TLS et crypto/ecdsa pour la génération de certificats MITM. Ce sont des préoccupations de transport, pas des opérations du protocole Clavitor.
Les secrets (clé de déchiffrement des identifiants, ID d'agent, ID de périphérique, URL du coffre-fort) résident dans la configuration sidecar CLV1 chiffrée, écrite une fois lors de clavitor-proxy init. Les boutons de commande opérationnels résident dans les variables d'environnement :
| Variable | Défaut | Objectif |
|---|---|---|
CLAVITOR_PROXY_LISTEN | 127.0.0.1 | Interface d'écoute. Définir sur 0.0.0.0 pour les déploiements partagés, ou sur l'IP d'une interface spécifique. |
CLAVITOR_PROXY_PORT | 1983 | Port d'écoute |
CLAVITOR_PROXY_ALLOW_PRIVATE | false | Autoriser les connexions aux réseaux RFC-1918 / privés |
CLAVITOR_PROXY_MAX_BODY_MB | 64 | Limite de taille du corps de requête |
CLAVITOR_PROXY_WRITE_TIMEOUT | 300 | Délai d'attente d'écriture de réponse en secondes |
CLAVITOR_CONFIG | (répertoire de l'exécutable) | Remplacer le chemin de configuration sidecar |
Les boutons de commande opérationnels ne sont pas des secrets. Ils n'appartiennent pas à la configuration chiffrée. Ils appartiennent là où les outils de déploiement les gèrent déjà — l'environnement.
Examinez cela vous-même.
La cryptographie est un artefact WASM unique et auditable. Le modèle de menace est documenté. Si vous trouvez quelque chose que nous avons manqué, nous voulons en être informés.