Identifiants et la frontière du fil

Une session de codage agentique a besoin d'identifiants — une clé Anthropic pour dialoguer avec Claude, un jeton GitHub pour pousser, des clés AWS pour déployer. Elle exécute aussi du code arbitraire, installe des paquets arbitraires et suit des instructions issues de fichiers qu'elle n'a pas écrits. Confier vos vrais secrets à un tel environnement, c'est ainsi que des clés finissent dans la boîte de réception d'un voleur.

Bromure Agentic Coding résout cette tension avec la frontière du fil : l'agent à l'intérieur de la VM ne voit jamais que des jetons factices d'espace réservé. Vos vrais identifiants résident chiffrés sur l'hôte macOS et sont substitués sur le fil par un proxy MITM côté hôte au dernier moment possible — après que la requête a quitté la VM, et uniquement lorsqu'elle est destinée à l'hôte auquel l'identifiant appartient. Aucun fichier, variable d'environnement ni processus à l'intérieur de la VM ne contient jamais une vraie clé d'API, un vrai jeton OAuth, un vrai secret AWS ou une vraie clé privée SSH.

Ce chapitre explique le mécanisme de bout en bout, puis passe en revue la façon dont les agents se connectent, chaque type d'identifiant pris en charge et son cycle de vie, le système d'approbation à chaque usage, le détecteur de compromission, les échappatoires pour les hôtes qui ne supportent pas l'interception, et la manière de vérifier la frontière vous-même.

Les identifiants se configurent par machine. Une machine est ce que l'éditeur de réglages appelle encore un espace de travail ; les deux mots désignent la même VM et ses réglages.

Remarque : Ce chapitre couvre les concepts et le comportement à l'exécution. Pour une référence champ par champ du panneau de réglages, voir Réglages → Identifiants. Les clés d'API et les abonnements des agents ne se règlent plus dans ce panneau ; ils se trouvent dans Préférences › Modèles (voir Modèles et fournisseurs).

La frontière du fil en un coup d'œil

Trois principes définissent le modèle :

  1. Des leurres dans la VM. Chaque identifiant que vous configurez est remplacé à l'intérieur de la VM par un leurre qui préserve la structure. Les leurres conservent la forme attendue par les validateurs — un leurre Anthropic commence par sk-ant-api03-brm-, un leurre GitHub est ghp_ plus 36 caractères — de sorte que des outils comme claude, gh et doctl les acceptent sans broncher.
  2. Les vrais uniquement sur le fil. Chaque requête HTTPS que fait la VM est tunnelisée vers le proxy hôte, qui la déchiffre, échange le leurre contre la vraie valeur, puis la rechiffre en amont. L'échange est limité à l'hôte de destination pour lequel l'identifiant a été frappé.
  3. Échec en position fermée. Si quoi que ce soit contourne le proxy, la requête ne porte qu'un leurre et l'authentification en amont échoue. Il n'existe aucun chemin par lequel un vrai secret pourrait fuir par accident.

Les leurres sont déterministes : chacun est dérivé de la vraie valeur plus un sel de 32 octets propre à l'installation, via HKDF-SHA256. La même vraie clé correspond toujours au même leurre sur votre Mac, de sorte que les clients qui empreignent leur clé (Claude Code met en cache un hachage de clé, par exemple) ne voient jamais l'identifiant « tourner » d'une session à l'autre.

IdentifiantForme du leurre dans la VM
Clé d'API Anthropicsk-ant-api03-brm-…
Clé d'API OpenAIsk-brm-…
Clé d'API xAIxai-brm-…
Clé d'API Moonshot (Kimi)sk-kimi-brm-…
Clé OpenRouter utilisée par Claude Codesk-or-v1-brm-…
Clé d'API Amazon Bedrockbedrock-brm-…
Jeton GitHubghp_ + 36 caractères (40 au total)
Jeton GitLabglpat- + 20 caractères
PAT DigitalOceandop_v1_ + hex (64 caractères au total)
Clé d'API Linearlin_api_ + 40 caractères (48 au total)
Jeton d'authentification Twilio / secret de clé d'APIbrm-twilio-… (au moins 32 caractères)
Jeton bearer MCPbrm-mcp_…
Mot de passe de registre Dockerbrm-docker-… (au moins 40 caractères)
Jeton bearer Kubernetesbrm-k8s-…
Secret de base de donnéesbrm-db-… (au moins 32 caractères)
Jeton manuel génériquebrm_…

Il n'existe aucun interrupteur marche/arrêt pour la frontière. Le proxy est l'unique voie de sortie de la VM ; l'échange est tout simplement la façon dont les identifiants fonctionnent dans cette application.

Comment fonctionne l'échange de bout en bout

Le trajet complet d'une requête authentifiée :

  1. Lancement de la session — le plan des jetons. Quand la VM d'une machine démarre, l'application construit un plan des jetons propre à la machine, qui associe chaque vrai identifiant à son leurre dérivé. Les leurres sont écrits dans la VM : variables d'environnement (ANTHROPIC_API_KEY, GH_TOKEN, LINEAR_API_KEY, …) et fichiers de configuration (~/.git-credentials, ~/.docker/config.json, ~/.kube/config, ~/.aws/config, ~/.config/doctl/config.yaml, configurations MCP). Les vraies valeurs sont chargées dans la table de substitution en mémoire du proxy, chacune associée à l'hôte de destination auquel elle appartient.
  2. La requête quitte la VM. Le trafic HTTPS de l'invité est tunnelisé sur un socket virtio (port vsock 8443) vers le proxy hôte. La VM n'a aucune autre route vers le réseau.
  3. Terminaison TLS. Le proxy présente un certificat feuille forgé par hôte — le nom d'hôte de destination comme CN et SAN, une clé EC par hôte — signé par l'autorité de certification racine de Bromure Agentic Coding. Comme le certificat public de cette autorité de certification a été installé dans le magasin de confiance de la VM au démarrage, les clients TLS de l'invité acceptent la connexion, et le proxy peut lire la requête en clair.
  4. L'échange. Le proxy recherche chaque jeton factice apparaissant dans la requête (les en-têtes, et pour les types d'identifiants ayant choisi de participer, le corps) et, si l'hôte de destination correspond à la portée de l'identifiant, le remplace par la vraie valeur.
  5. Rechiffrement en amont. La requête réécrite est réémise vers la vraie destination via URLSession d'Apple, c.-à-d. la propre pile TLS de macOS, qui valide le certificat authentique du serveur en amont. La réponse revient en flux à travers le tunnel jusqu'à l'invité.

Si la destination ne correspond pas à la portée d'un leurre, le leurre part inchangé (et échoue à l'authentification en amont) — ou, lorsque l'incohérence ressemble à une exfiltration, la requête est purement et simplement bloquée (voir Le détecteur de compromission ci-dessous).

L'autorité de certification racine de Bromure Agentic Coding

L'autorité de certification est propre à l'installation et réside dans ~/Library/Application Support/BromureAC/ca/ (cert.pem plus un key.pem en mode 0600). Son sujet est « Bromure Agentic Coding Root CA », organisation « Bromure ». Propriétés à connaître :

  • La validité de l'autorité de certification est de 10 ans. Les certificats feuilles forgés par hôte sont valides 1 an et antidatés de 24 heures, de sorte qu'un invité dont l'horloge a dérivé pendant une mise en veille/reprise les accepte quand même. Les feuilles sont mises en cache par hôte pour la durée de vie du processus de l'application.
  • Le certificat public est installé dans le magasin de confiance de chaque VM au démarrage (livré via le partage meta et appliqué avec update-ca-certificates). Il ne quitte jamais votre machine et n'est approuvé par rien d'autre que vos VM.
  • Pour faire tourner l'autorité de certification, quittez l'application et supprimez le répertoire ca/. Une nouvelle autorité de certification est frappée au prochain lancement et chaque VM récupère le nouveau certificat public à son prochain démarrage. La rotation n'invalide rien d'autre — les secrets d'espace de travail et les métadonnées de profile.json restent intacts.

Portée par hôte

Chaque entrée d'échange est liée à une portée d'hôte. La correspondance est exacte ou par sous-domaine, insensible à la casse, jamais par sous-chaîne : un identifiant limité à openai.com correspond à api.openai.com mais pas à openai.com.evil.example — un hôte sosie ne peut pas tromper le proxy pour qu'il décore sa requête d'une vraie clé. Les règles de jetons manuels peuvent délibérément utiliser un filtre d'hôte vide, ce qui signifie « injecter sur n'importe quel hôte » ; c'est un choix explicite que vous faites par entrée (voir Clés d'API génériques).

Échec en position fermée par construction

La conception ne repose jamais sur le caractère incontournable du proxy pour garantir le secret — elle repose sur l'absence des secrets :

  • Une requête qui d'une manière ou d'une autre saute le proxy porte un jeton factice ; l'API en amont le rejette.
  • Les requêtes AWS signées à l'intérieur de la VM sont signées avec une clé secrète factice ; si elles atteignaient AWS directement, elles échoueraient avec InvalidSignatureException (voir AWS ci-dessous).
  • Les octets de la clé privée SSH ne sont jamais présents dans la VM ; seules les signatures franchissent la frontière.

Gérer les identifiants dans l'éditeur d'espace de travail

Les identifiants de services — jetons git, clés cloud, registres, bases de données, clés SSH — se configurent par machine. Ouvrez les réglages de la machine (Réglages… dans le menu de la machine, ou Réglages de « machine »… depuis le menu d'une session) et sélectionnez Identifiants sous Sécurité dans la barre latérale.

Le panneau Identifiants de l'éditeur de l'espace de travail Web app : les champs de nom et d'e-mail de l'identité Git, l'état vide « Aucun identifiant pour l'instant », et les boutons Ajouter un identifiant et Importer un fichier env…

Le panneau s'ouvre sur Identité Git (un nom et une adresse e-mail écrits dans ~/.gitconfig dans la VM ; laissez les deux vides pour garder les valeurs par défaut de git — les textes indicatifs ne sont que des exemples, pas des identifiants), suivi de la liste des seuls identifiants que vous avez configurés, regroupés sous des en-têtes de catégorie (Agents, Git, Cloud, Databases, SSH, Other). Sans rien de configuré, le panneau indique Aucun identifiant pour l'instant. Deux boutons se trouvent en bas : Ajouter un identifiant ouvre un sélecteur de types d'identifiants — Git token, SSH key, AWS credentials, DigitalOcean token, Linear API key, Twilio API key, Kubernetes, Container registry, Database et Other API key — et Importer un fichier env… importe en masse depuis un .env ou un ~/.bashrc. Cliquez sur Enregistrer ; le prochain lancement de session écrit les leurres dans la VM et charge les vraies valeurs dans le proxy.

Les clés d'API des agents (Anthropic, OpenAI, xAI, Moonshot et les autres fournisseurs de modèles) ne figurent pas dans ce sélecteur : elles se règlent dans Préférences › Modèles, décrit plus bas. Le groupe Agents n'apparaît que sur un espace de travail qui conserve encore sa propre clé d'agent issue d'une version antérieure ; son élément de menu Modifier dans Modèles… ouvre Préférences › Modèles. Pour changer l'accès aux modèles, utilisez Préférences › Modèles ou le panneau Modèles de la machine.

Le verrou d'approbation par identifiant (Demander avant utilisation) et la politique d'écriture de chaque service se règlent dans le panneau Garde-fous, pas ici. Voir Réglages → Identifiants pour la référence champ par champ.

Sept fournisseurs sont pris en charge automatiquement — Anthropic, OpenAI, GitHub, GitLab, DigitalOcean, Twilio et Kubernetes n'ont besoin d'aucune règle de jeton manuelle ; leurs sections dédiées les couvrent. Tout le reste passe par Autres clés d'API.

Importer depuis un fichier env. Importer un fichier env… lit un fichier .env existant — ou un ~/.bashrc — et transforme ses variables en identifiants. L'analyseur gère KEY=VALUE et export KEY=VALUE, retire les guillemets et les commentaires de fin de ligne, et ignore délibérément tout ce qui nécessiterait une évaluation par le shell (interpolation $VAR ou substitution $(…)), si bien qu'il peut sans risque lire un vrai .bashrc. Une feuille de revue affiche ensuite les variables avec leurs valeurs masquées : les noms reconnus (GH_TOKEN/GITHUB_TOKEN, GITLAB_TOKEN, AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN, DIGITALOCEAN_ACCESS_TOKEN, LINEAR_API_KEY, TWILIO_ACCOUNT_SID/TWILIO_AUTH_TOKEN, et les clés des fournisseurs de modèles ANTHROPIC_API_KEY, OPENAI_API_KEY, XAI_API_KEY, MOONSHOT_API_KEY et KIMI_API_KEY, qui vont au fournisseur correspondant dans Préférences › Modèles — ou, pour une machine distante, dans son propre remplacement Modèles) sont associés automatiquement à leur type d'identifiant, tandis que les noms non reconnus peuvent être importés comme jetons manuels génériques avec une portée d'hôtes, séparés par des virgules, que vous fournissez. Les entrées déjà configurées sont signalées et laissées décochées, pour qu'un nouvel import n'écrase jamais un secret en silence.

Clés et abonnements des agents

Chaque agent de code — Claude Code, Codex, Grok, Kimi et omp — obtient son accès aux modèles auprès d'un fournisseur configuré dans Préférences › Modèles (⌘, puis Modèles). Le même panneau existe dans les réglages de chaque machine, sous forme de remplacement facultatif par machine. La référence complète — fournisseurs, choix de modèle par agent, remplacement par machine, OpenRouter, serveurs personnalisés et modèles sur l'appareil — se trouve dans Modèles et fournisseurs. Cette section couvre ce qui compte pour les identifiants : comment une clé ou un abonnement parvient à l'agent sans jamais entrer dans la VM.

Fenêtre des Préférences intitulée « Bromure — Préférences », page Défauts, panneau Modèles : une colonne Fournisseurs (Anthropic (Claude), OpenAI et OpenRouter avec une clé d'API et un point vert ; xAI (Grok), z.ai (GLM), Moonshot (Kimi), Amazon Bedrock, Serveur personnalisé et Sur l'appareil non configurés) et une colonne Agents (Défaut avec Tailles, Claude Code, Codex, Grok, Kimi, omp)

Cliquez sur un fournisseur dans la colonne Fournisseurs pour ouvrir sa fenêtre contextuelle. Pour chaque fournisseur, elle contient un champ Clé API ; pour les quatre fournisseurs qui proposent des abonnements, elle contient aussi les commandes de connexion.

Clés d'API

Collez la clé dans le champ Clé API de la fenêtre contextuelle. Dans les Préférences, le panneau enregistre au fil de la saisie ; dans les réglages d'une machine, la clé est enregistrée avec Enregistrer. Cycle de vie :

  • Dans la VM : la variable habituelle de l'agent (ANTHROPIC_API_KEY, OPENAI_API_KEY, XAI_API_KEY, …) contient le leurre à la forme du fournisseur (sk-ant-api03-brm-…, sk-brm-…, xai-brm-…, sk-kimi-brm-…).
  • Sur le fil : substitué par la vraie clé uniquement sur les requêtes vers les hôtes de ce fournisseur (anthropic.com, openai.com, x.ai, moonshot.ai, …).
  • Au repos : les clés, comme le reste des réglages des modèles, sont stockées chiffrées dans models.enc (voir Où résident les secrets sur l'hôte).

Les clés réglées dans Modèles n'apparaissent pas dans les panneaux Identifiants ou Garde-fous, et n'ont donc pas de ligne Demander avant utilisation. (Une clé d'agent encore stockée sur l'espace de travail lui-même depuis une version antérieure y apparaît bien et peut être soumise à approbation. L'import d'un fichier env ne crée plus de telles clés : il place les clés d'agents dans les réglages des modèles.)

Depuis la CLI, bromure-cli workspaces create --auth token|subscription|bedrock|local et bromure-cli vm run --auth token|subscription|bedrock|local choisissent toujours le mode d'authentification de l'agent principal de l'espace de travail.

Abonnements : Claude, ChatGPT, Grok et Kimi

Si vous avez un abonnement plutôt qu'une clé d'API, connectez-vous à la place. Les abonnements n'existent que pour Anthropic (Claude), OpenAI (ChatGPT, utilisé par Codex), xAI (Grok) et Moonshot (Kimi) ; z.ai, Amazon Bedrock, OpenRouter et les serveurs personnalisés ne prennent que des clés, et omp fonctionne uniquement par clé d'API. Un abonnement n'alimente que son propre agent : une connexion Claude fait tourner Claude Code, une connexion ChatGPT fait tourner Codex, et ainsi de suite.

Quelle que soit la façon dont vous vous connectez, le résultat est le même : les vrais jetons OAuth ne vivent que sur l'hôte, et l'invité tourne avec une clé bidon — un faux ANTHROPIC_API_KEY pour Claude, un ~/.codex/auth.json pré-rempli contenant un JWT bidon à expiration lointaine pour Codex (pour que le client n'essaie jamais de le rafraîchir), et des jetons de substitution dans les fichiers d'identifiants propres à Grok et Kimi. Le proxy reconnaît la valeur bidon et injecte sur le fil un jeton d'accès Authorization: Bearer valide.

Se connecter depuis Préférences › Modèles

La fenêtre contextuelle du fournisseur affiche l'un de trois états :

ÉtatCe qu'affiche la fenêtre contextuelle
Non connectéSign in with fournisseur, « Connexion interactive dans une VM temporaire — aucune clé API nécessaire. », puis « ou collez une clé API » au-dessus du champ Clé API.
ConnectéUne ligne verte « Connecté » avec la date de la connexion, Se reconnecter… et Se déconnecter….
ExpiréUn panneau orange Connexion expirée — « fournisseur a refusé la connexion enregistrée (enregistrée …). Les sessions ne peuvent plus l'utiliser tant que vous ne vous reconnectez pas. » — avec Se reconnecter et Se déconnecter….

Sign in with fournisseur lance le processus d'inscription :

  1. Une explication intitulée S'inscrire avec fournisseur indique ce qui va se passer. Cliquez sur Continuer. (L'inscription est refusée si le proxy Bromure ne tourne pas.)
  2. Une VM d'inscription jetable démarre — temporaire, isolée, sans dossiers d'espace de travail, sans secrets enregistrés et sans table de substitution des identifiants. À l'intérieur, la commande de connexion propre à l'agent s'exécute.
  3. Le navigateur par défaut de votre Mac ouvre la page de connexion du fournisseur. Connectez-vous comme d'habitude.
  4. Les jetons obtenus sont capturés sur l'hôte, chiffrés et stockés ; la VM jetable est arrêtée et supprimée.

Une connexion lancée depuis les Préférences est toujours partagée par toutes les machines. Se déconnecter… demande « Se déconnecter de fournisseur ? » — « Les espaces de travail qui utilisent cette connexion cesseront de fonctionner jusqu'à ce que vous vous reconnectiez. » — et supprime la connexion stockée. Se déconnecter… est masqué là où il ne peut pas agir.

Se connecter depuis le panneau Modèles d'une machine : portée du partage

La même fenêtre contextuelle apparaît dans le panneau Modèles propre à une machine. Une connexion lancée à cet endroit se termine par une question, Partager avec tous les espaces de travail ? :

BoutonEffet
Tous les espaces de travailStocke la connexion comme connexion partagée et supprime la connexion propre de chaque machine pour ce fournisseur, pour que chaque machine utilise réellement la nouvelle.
Cet espace de travail uniquementStocke la connexion pour cette machine uniquement.

La portée compte, car une machine lit d'abord sa propre connexion et ne se rabat sur la connexion partagée que si elle n'en a pas. Une machine qui s'est un jour connectée pour elle-même continue d'utiliser cette connexion, même après une connexion partagée plus récente, jusqu'à ce que vous choisissiez Tous les espaces de travail ou déconnectiez cette machine. Un client distant qui lance la connexion se voit poser la même question ; si personne ne répond, la connexion reste propre à cette machine.

Se connecter depuis le chat

Vous n'avez pas besoin de passer d'abord par les Préférences. Quand un agent d'une session doit se connecter, le chat affiche une carte intitulée Se connecter à fournisseur — « Bromure vous connecte sur ce Mac et garde votre compte fournisseur hors de la machine — l'agent ne voit jamais qu'une clé de substitution. » — avec un bouton Se connecter à fournisseur…, et la ligne de la session dans la barre latérale indique Connexion requise. Quand la connexion enregistrée d'un agent a été refusée, la carte d'erreur rouge propose le même bouton.

Cliquer dessus connecte sans VM jetable :

  1. Le terminal propre à la session exécute la commande de connexion de l'agent, et la page de connexion du fournisseur s'ouvre dans le navigateur de votre Mac (« Ouverture de votre navigateur pour vous connecter… »).
  2. Quand l'agent échange son code d'autorisation contre des jetons, le proxy répond lui-même à cet échange : les vrais jetons vont directement dans le magasin de l'hôte. Claude Code et Codex sont informés que l'identifiant reste sur le Mac ; Grok et Kimi reçoivent des jetons de substitution, que leurs CLI écrivent dans leurs fichiers d'identifiants.
  3. L'agent redémarre avec le substitut (« Connecté. Redémarrage de … »).

Une connexion depuis le chat remplace la connexion que lisait la machine : celle de la machine si elle en a une, sinon la connexion partagée. Si aucune connexion n'atteint le proxy en 5 minutes, la carte indique « Bromure n'a pas reçu de connexion fournisseur à temps. Vous pouvez réessayer. » Une seule connexion peut être en cours par machine à la fois.

omp n'a pas de compte auquel se connecter ; sa carte indique « omp a besoin d'un fournisseur de modèle » et propose Réglages de la machine… à la place.

Avertissement : N'exécutez pas /login (ni la commande de connexion de l'agent) à la main dans la VM pour réparer une connexion expirée. Utilisez la carte ou Préférences › Modèles, pour que les jetons soient capturés par l'hôte au lieu de rester dans la VM.

Kimi se connecte à la région internationale

La CLI de Kimi Code utilise par défaut la région de Chine continentale, qui refuse les comptes d'ailleurs. Bromure connecte Kimi à la région internationale (auth.kimi.ai, API sur api.kimi.ai) en définissant les variables de région de la CLI dans la VM d'inscription et dans chaque session. Une connexion Kimi capturée sur l'ancienne région auth.kimi.com est toujours reconnue.

Garde des jetons : une autorisation, un rafraîchisseur

Le rafraîchissement des jetons se fait entièrement côté hôte, et chaque connexion est rafraîchie par un seul propriétaire :

  • Une autorisation par emplacement. La connexion partagée et la connexion propre de chaque machine sont des emplacements distincts. Pour chaque emplacement, un seul rafraîchissement tourne à la fois, et chaque machine qui lit cet emplacement en utilise le résultat. L'invité ne détient jamais de jeton de rafraîchissement.
  • Moment du rafraîchissement. L'hôte rafraîchit environ 5 minutes avant l'expiration, auprès du point de terminaison de jetons du fournisseur (platform.claude.com pour Claude, auth.openai.com pour Codex, auth.x.ai pour Grok, auth.kimi.ai pour Kimi). Une connexion fraîchement inscrite est stockée comme déjà expirée, si bien que la première utilisation prouve que le chemin de rafraîchissement fonctionne.
  • Les clones d'automatisation partagent l'autorisation. Une machine clonée pour une automatisation pointe vers la connexion de sa machine de base au lieu de la copier.
  • Les connexions des CLI de votre Mac ne sont pas importées. Partager une autorisation avec une CLI sur l'hôte déconnecterait l'une des deux chaque fois que l'autre rafraîchit.
  • Quand aucun jeton n'est disponible pour une requête Claude, le proxy répond lui-même à l'agent au lieu de transmettre la clé bidon : une défaillance temporaire revient sous forme de 529 qu'on peut réessayer, et une connexion refusée sous forme de 401 qui vous invite à vous reconnecter depuis Bromure. La fenêtre contextuelle affiche alors Connexion expirée.

Identifiants de services

AWS

AWS reçoit le traitement le plus poussé de tous les fournisseurs, car les requêtes AWS ne sont pas authentifiées par un jeton bearer — elles sont signées (SigV4). Ouvrez Identifiants → AWS dans l'éditeur d'espace de travail ; un contrôle segmenté choisit entre Clés statiques et SSO / Identity Center.

Clés statiques et le resigneur hôte

Collez votre ID de clé d'accès et votre Clé d'accès secrète (plus un Jeton de session STS optionnel et une Région par défaut). Le cycle de vie :

  • Dans la VM : ~/.aws/config pointe vers un assistant credential_process qui fournit — via le port vsock 8445 — le vrai ID de clé d'accès apparié à une fausse clé d'accès secrète de 40 caractères, en omettant le jeton de session. Chaque SDK AWS, la CLI aws, terraform et boto3 récupèrent ceci nativement ; aucune configuration spécifique à l'outil n'est nécessaire.
  • Ce que fait l'invité : signe ses requêtes avec le faux secret, produisant une signature SigV4 syntaxiquement valide mais cryptographiquement vouée à l'échec.
  • Sur le fil : le resigneur AWS de l'hôte détecte les requêtes destinées à AWS dans n'importe quelle partition, sur son nom IPv4 ou double pile (*.amazonaws.com, *.api.aws, *.amazonaws.com.cn, *.api.amazonwebservices.com.cn, les domaines de l'European Sovereign Cloud et des partitions ISO ; y compris GovCloud, les hôtes régionaux, FIPS et les hôtes S3 de type bucket), retire la signature de l'invité, injecte le vrai X-Amz-Security-Token quand un jeton de session est présent, et re-signe avec le vrai secret avant que la requête ne quitte votre Mac. Le garde-fou AWS couvre les mêmes hôtes, et la réécriture des identifiants créés par la VM (ci-dessous) les couvre aussi, plus public.ecr.aws. Chaque re-signature réussie émet un événement d'audit credential.aws_sign avec une clé d'accès masquée, affiché comme ligne Identifiant utilisé dans la chronologie de sécurité.

Ceci est à échec fermé au sens le plus fort : la vraie clé secrète n'existe jamais dans la VM sous aucune forme, et une requête qui contourne le proxy est rejetée par AWS avec InvalidSignatureException.

Trois styles de requête ne sont pas pris en charge et renvoient une erreur claire à l'invité plutôt qu'un échec silencieux : les téléversements S3 en flux par blocs (STREAMING-AWS4-HMAC-SHA256-PAYLOAD, auxquels on répond par 501), la signature asymétrique SigV4A, et les URL présignées en chaîne de requête (qui intègrent la signature là où le resigneur ne peut pas la remplacer).

Identifiants créés par la VM

Certains appels émettent un nouvel identifiant : aws sts assume-role / get-session-token / get-federation-token, aws iam create-access-key, les identifiants de rôle d'IAM Identity Center, GetCredentialsForIdentity de Cognito, aws ecr get-login-password, et chez DigitalOcean doctl registry login, doctl kubernetes cluster kubeconfig save (et son appel d'identifiants) et doctl spaces keys create. Le proxy retient la réponse à un tel appel et remplace chaque secret qu'elle contient par un leurre avant que la VM ne la voie. Une clé AWS temporaire garde son vrai ID de clé d'accès, avec un secret et un jeton de session leurres, pour que le resigneur sache avec quelle clé l'invité a signé. Un jeton de registre ou de cluster devient un leurre qui n'est échangé contre la vraie valeur que sur ce registre ou ce cluster.

Les vraies valeurs sont enregistrées, chiffrées, dans la configuration de l'espace de travail, de sorte que les leurres stockés par la VM (dans ~/.aws, ~/.docker/config.json ou un kubeconfig) continuent de fonctionner après un redémarrage. Une clé AWS émise est re-signée avec son propre secret et son propre jeton de session. Une fois qu'elle a expiré, les requêtes signées avec elle sont refusées plutôt que re-signées avec la clé de l'espace de travail, ce qui les exécuterait sous une autre identité. Les identifiants expirés sont supprimés 30 jours après leur expiration.

Une réponse que le proxy ne peut pas réécrire entièrement n'est jamais transmise : l'invité reçoit un 502 à la place. Les appels qui définissent un secret choisi par la VM elle-même, qu'aucun leurre ne peut remplacer, sont refusés quel que soit le mode des garde-fous : iam:CreateLoginProfile, UpdateLoginProfile, CreateServiceSpecificCredential et ResetServiceSpecificCredential. Une demande de consentement AWS nomme l'appel qu'elle signerait (par exemple sts:AssumeRole), et chaque identifiant émis produit un événement credential.minted.

SSO / IAM Identity Center

Si votre organisation utilise IAM Identity Center, sélectionnez SSO / Identity Center au lieu de coller des clés à longue durée de vie :

  1. Cliquez sur Accorder l'accès à ~/.aws et approuvez l'invite d'accès au dossier (un octroi à portée de sécurité ; le dossier est lu sur l'hôte et n'est jamais monté dans la VM).
  2. Choisissez votre profil dans le sélecteur Profil SSO. L'application découvre les sections [profile …] dans ~/.aws/config qui portent sso_start_url, sso_account_id et sso_role_name, en résolvant les références [sso-session …] ; l'ID de compte et le rôle sont affichés en lecture seule.
  3. Au démarrage de la session, l'hôte résout des identifiants de rôle temporaires depuis le cache de jetons SSO (~/.aws/sso/cache). Si le jeton en cache a expiré, votre navigateur s'ouvre pour aws sso login — exécuté sur l'hôte, depuis /usr/local/bin/aws.

Les clés temporaires résolues alimentent le même resigneur que les clés statiques ; la VM ne voit toujours jamais de secret. Les identifiants se rafraîchissent automatiquement sur l'hôte environ 5 minutes avant leur expiration.

Bedrock

Amazon Bedrock est un fournisseur de modèles pour tous les agents, pas un mode d'authentification de l'un d'eux. Activez Utiliser Amazon Bedrock dans la fenêtre contextuelle Amazon Bedrock de Préférences › Modèles (ou du panneau Modèles d'une machine), puis choisissez des identifiants de modèles Bedrock par agent. Claude Code tourne nativement sur Bedrock ; les autres agents y accèdent via l'API compatible OpenAI de Bedrock. Les requêtes sont signées avec les identifiants AWS propres à chaque machine (Identifiants → AWS, statiques ou SSO) par le même chemin de re-signature, puisque les points de terminaison Bedrock sont des hôtes *.amazonaws.com — ou, si vous en collez une dans le champ Clé API Bedrock (facultative — sinon les identifiants AWS signent) de la fenêtre contextuelle, avec cette clé, que la VM ne voit que sous forme de leurre bedrock-brm-…. La fenêtre contextuelle accepte aussi une Région AWS ; laissez-la vide pour utiliser la région AWS de chaque machine. Voir Modèles et fournisseurs.

Jetons Git HTTPS (GitHub, GitLab, Bitbucket, auto-hébergés)

Les jetons d'accès personnels pour git-sur-HTTPS résident sous Jetons GitHub / Jetons GitLab / Jetons Bitbucket (collectivement, les jetons HTTPS). Chaque entrée prend un hôte, un nom d'utilisateur et le jeton ; les instances GitLab ou Gitea auto-hébergées fonctionnent en renseignant le champ hôte. Cycle de vie :

  • Dans la VM : un leurre est écrit dans ~/.git-credentials et la configuration gh/glab ; GH_TOKEN et GITLAB_TOKEN sont exportés pour que les CLI s'authentifient automatiquement. Les formes des leurres correspondent aux validateurs de chaque éditeur (ghp_ + 36 pour GitHub, glpat- + 20 pour GitLab, brm_… sinon), de sorte que les vérifications de préfixe et de longueur dans gh et glab passent.
  • Sur le fil : échangé contre le vrai jeton sur les requêtes vers l'hôte git de cette entrée.
  • Approbation : chaque entrée obtient sa propre ligne Demander avant l'usage dans le volet Garde-fous.

Si vous n'avez besoin que de git push par SSH, vous n'aurez peut-être pas besoin d'un jeton HTTPS du tout — voir Clés SSH ci-dessous.

Clés d'API génériques (Autres clés d'API / Règles de jetons manuels)

Pour toute API que l'application ne gère pas automatiquement, ajoutez une entrée sous Autres clés d'API (les règles de jetons manuels, également présentées comme Échange de jeton MITM). Cliquez sur Ajouter un jeton et fournissez :

ChampSignification
NomUne étiquette pour l'entrée.
ValeurLe vrai secret (stocké chiffré sur l'hôte).
Nom de la variable d'envLa variable sous laquelle le leurre est exporté à l'intérieur de la VM. Référencez-la depuis votre code.
Filtre d'hôte (optionnel)La portée d'hôte pour l'échange.

Deux cas limites sont délibérés :

  • Nom de variable d'env vide : rien n'est exporté ; vous copiez le leurre depuis la bannière de bienvenue de la session et le placez là où votre outillage en a besoin.
  • Filtre d'hôte vide : la vraie valeur est injectée sur n'importe quel hôte, sans demander. C'est un choix explicite toujours actif — utile pour les API à nombreux noms d'hôtes régionaux — mais cela signifie que la portée de l'identifiant ne le protège plus. Pour contrôler un secret sans portée, activez Demander avant l'usage pour lui dans le volet Garde-fous (ou donnez-lui malgré tout un filtre d'hôte).

Anthropic, OpenAI, GitHub, GitLab, DigitalOcean et Kubernetes n'ont jamais besoin d'entrées manuelles ici.

Références de secrets 1Password (op://)

Au lieu de coller un vrai secret, une valeur d'Autre clé d'API peut être une référence de secret 1Password — op://vault/item/field, ou la forme à accolades {{ op://vault/item/field }} qu'utilisent op inject et les fichiers .env.op. Seule la référence est jamais stockée sur disque ; le secret lui-même n'est jamais écrit nulle part sur l'hôte ni sur la VM. L'éditeur reconnaît la référence, l'affiche en clair (ce n'est pas un secret) et note qu'elle se résout via 1Password.

À chaque lancement d'espace de travail, Bromure résout la référence côté hôte avec la CLI 1Password (op read), frappe un leurre à partir de la chaîne de référence (de sorte que le leurre reste stable même lorsque le secret tourne), et n'exporte que ce leurre dans la VM. Le proxy MITM échange ensuite le leurre contre la valeur résolue sur le fil, exactement comme il le fait pour un secret collé — et il re-résout toutes les 2 minutes, de sorte que la rotation de l'élément dans 1Password prend effet en quelques minutes sans redémarrage.

Ceci nécessite que la CLI op soit installée et connectée — déverrouillage biométrique via l'application 1Password, ou op signin dans un terminal. Si op est introuvable, l'éditeur affiche un lien Obtenir la CLI 1Password et l'espace de travail fait apparaître les instructions d'installation au lancement ; si la résolution échoue (non connecté, ou l'élément n'existe pas), Bromure fait apparaître l'erreur pour que vous puissiez la corriger et redémarrer l'espace de travail.

Importer un fichier .env ou .env.op (Importer un fichier env… dans le panneau Identifiants) reconnaît automatiquement les valeurs op:// — sous des noms reconnus comme ANTHROPIC_API_KEY ou arbitraires comme STRIPE_KEY — et stocke chacune comme jeton manuel contenant la référence.

DigitalOcean

Collez un jeton d'accès personnel sous Identifiants → DigitalOcean (le lien Ouvrir la page des jetons DigitalOcean dans votre navigateur vous mène à la génération de jetons). Le leurre (dop_v1_ + hex, 64 caractères) est exporté sous DIGITALOCEAN_ACCESS_TOKEN et écrit dans ~/.config/doctl/config.yaml, de sorte que doctl auth init est inutile. L'échange couvre les requêtes vers digitalocean.com, plus une seconde entrée pour le blob Basic-auth base64 utilisé par docker login / doctl registry login contre registry.digitalocean.com, de sorte que les pushes et pulls de registre se résolvent aussi.

Linear

Collez une clé d'API personnelle sous Identifiants → Linear (lien : Ouvrir les paramètres d'API Linear dans votre navigateur ; les clés viennent de linear.app → Settings → API). Le leurre (lin_api_ + 40) est exporté sous LINEAR_API_KEY, que le SDK Linear, les serveurs MCP et les outils CLI lisent automatiquement ; la substitution est strictement limitée à linear.app (GraphQL sur api.linear.app et MCP sur mcp.linear.app). Une clé Linear sur l'espace de travail est aussi le prérequis des déclencheurs d'automatisation sur les tickets Linear — voir Automatisations.

Twilio

Ajoutez un identifiant Twilio API key avec le SID dans Account SID (AC…) or API Key SID (SK…) et le secret dans Auth Token / API Key secret (les deux depuis console.twilio.com). Twilio s'authentifie en HTTP Basic, où le SID est une identité — il circule dans l'URL de la requête — et seul le jeton est secret. Cycle de vie :

  • Dans la VM : TWILIO_ACCOUNT_SID contient le vrai SID et TWILIO_AUTH_TOKEN un leurre brm-twilio-…, pour que les SDK Twilio et la CLI les lisent sans configuration.
  • Sur le fil : sur les requêtes vers twilio.com, le proxy remplace à la fois le jeton leurre brut et le bloc d'authentification Basic SID:jeton pré-encodé en base64 par les vrais.
  • Approbation : via Demander avant utilisation dans le panneau Garde-fous.

Importer un fichier env… reconnaît TWILIO_ACCOUNT_SID / TWILIO_API_KEY_SID et TWILIO_AUTH_TOKEN / TWILIO_API_SECRET et les assemble en un seul identifiant Twilio.

Jetons bearer de serveurs MCP

Les serveurs MCP à transport HTTP configurés dans le volet MCP reçoivent le même traitement : le vrai jeton bearer reste sur l'hôte, un leurre brm-mcp_… est injecté dans la configuration MCP que l'agent lit, et le proxy l'échange sur le fil, limité à l'hôte du serveur. Seuls les serveurs à transport HTTP activés avec un jeton bearer non vide reçoivent une entrée d'échange.

Une courtoisie supplémentaire : pour les hôtes ayant une entrée brm-mcp_, le proxy répond aux chemins de découverte OAuth/OIDC (points de terminaison .well-known de serveur d'autorisation, de ressource protégée et de configuration OpenID) par 404. Claude Code traite alors le serveur comme préauthentifié au lieu de tenter son propre flux OAuth — qui ne pourrait de toute façon jamais aboutir à l'intérieur de la VM.

Registres de conteneurs (Docker Hub, GHCR et compagnie)

Identifiants → Registres de conteneurs gère l'authentification HTTP Basic pour docker pull/push. Des préréglages existent pour Docker Hub (docker.io), GitHub Container Registry (ghcr.io) et GitLab Container Registry (registry.gitlab.com) ; tout autre registre peut être ajouté par hôte. Cycle de vie :

  • Dans la VM : ~/.docker/config.json contient un blob d'authentification factice — le base64 de votre nom d'utilisateur apparié à un mot de passe dérivé brm-docker-… — de sorte que Docker croit être connecté.
  • Sur le fil : le proxy substitue le vrai blob base64 à l'hôte de registre correspondant. La danse des jetons du distribution-spec est également gérée : des entrées d'échange sont ajoutées pour les domaines d'authentification connus (Docker Hub s'authentifie contre auth.docker.io, le registre de DigitalOcean contre api.digitalocean.com).
  • Import : cliquez sur Importer config.json… pour récupérer des entrées depuis un ~/.docker/config.json existant sur l'hôte. Les entrées déléguées à credsStore/credHelpers sont sautées — leurs mots de passe résident dans le trousseau du système d'exploitation, pas dans le fichier — et le résumé d'import indique combien ont été sautées et pourquoi.
  • Approbation : par registre, via Demander avant l'usage dans le volet Garde-fous. Supprimer ce registre supprime une entrée.

Contextes Kubernetes

Identifiants → Kubernetes transforme les contextes kubeconfig en accès de cluster médiatisé par proxy. Cliquez sur Importer kubeconfig pour analyser un kubeconfig existant en une ligne par contexte (le current-context en premier, le type d'authentification détecté automatiquement), ou Ajouter un contexte pour saisir manuellement une URL de serveur, des identifiants, un espace de noms et une autorité de certification de cluster. Dans tous les cas, la VM reçoit un ~/.kube/config synthétique : kubectl dans l'invité dialogue avec le proxy (de confiance via l'autorité de certification de Bromure), jamais directement avec le serveur d'API.

Par type d'authentification :

  • Les contextes à jeton bearer obtiennent un espace réservé brm-k8s-… dans la VM, échangé contre le vrai jeton sur le fil.
  • Les contextes à certificat client obtiennent un certificat et une clé jetables auto-signés dans la VM ; le vrai certificat et la vraie clé sont enregistrés sur l'hôte en tant que SecIdentity et utilisés pour le mTLS en amont.
  • Les contextes à plugin exec n'exécutent jamais le plugin dans la VM. Le scruteur de plugin exec exécute la commande sur l'hôte à chaque intervalle de rafraîchissement (600 secondes par défaut, plancher 60), analyse le JSON ExecCredential et alimente le nouveau jeton dans la table d'échange. Les rafraîchissements préservent l'état de consentement de l'entrée.

Si le kubeconfig fournit l'autorité de certification propre du cluster, elle est transmise pour que le proxy puisse vérifier le serveur d'API en amont. Les champs de chemin de fichier dans un kubeconfig importé (CA, cert, clé) sont lus avec empressement au moment de l'import — les modifications ultérieures de ces fichiers sur disque ne sont pas prises en compte. Chaque contexte obtient sa propre ligne Demander avant l'usage dans le volet Garde-fous, où une politique d'écriture peut en outre retirer les verbes destructeurs (kubectl delete, AWS Delete*/Terminate*, docker push, git push) côté hôte avant qu'un seul octet ne soit transmis — une couche distincte de l'échange d'identifiants.

Bases de données HTTP (MongoDB, ClickHouse, Elasticsearch)

Identifiants → Bases de données (les sections MongoDB / ClickHouse / Elasticsearch) couvre les points de terminaison de bases de données parlant HTTPS — l'API de données Mongo, l'interface HTTP de ClickHouse, Elastic. Chaque point de terminaison prend un moteur, un hôte, un secret, un nom d'utilisateur, un type d'authentification et un ou plusieurs noms de variables d'env (séparés par des virgules) sous lesquels le leurre brm-db-… est exporté ; référencez ces variables depuis votre code ou vos chaînes de connexion.

Les identifiants de base de données sont la seule famille où l'échange balaie le corps de la requête en plus des en-têtes et des paramètres de requête, car les secrets de connexion voyagent couramment à l'intérieur de charges utiles JSON ou SQL. Le proxy corrige Content-Length après un échange de corps ; les corps multipart ou binaires sans rapport d'autres trafics ne sont jamais touchés (tous les autres échanges sont limités aux en-têtes). Les points de terminaison à Basic-auth voient aussi leur blob base64 utilisateur-et-secret échangé. Le Demander avant l'usage par point de terminaison et la politique d'écriture se définissent dans le volet Garde-fous.

Clés SSH

SSH est géré sans aucun jeton : le SSH_AUTH_SOCK de la VM est adossé à un pont ssh-agent sur vsock (port 8444). L'invité peut lister les identités et demander des signatures, mais les octets de la clé privée ne résident que sur l'hôte et ne peuvent physiquement pas être lus ni extraits depuis l'intérieur de la VM. Deux sources de clés existent, toutes deux sous Identifiants → Clés SSH :

  • La clé par défaut propre à l'espace de travail. Une paire de clés ed25519 par défaut partagée est générée au démarrage de l'application (stockée sous default-ssh/ dans Application Support) et copiée dans le répertoire d'agent de chaque nouvel espace de travail. Le volet montre la clé publique de l'espace de travail pour que vous puissiez la coller dans votre hôte git (pour GitHub : github.com/settings/keys). Vous pouvez aussi frapper une nouvelle clé depuis la CLI avec bromure-cli workspaces ssh-keygen <workspace-id|name>, qui imprime la nouvelle clé publique.
  • Clés importées. Cliquez sur Importer… / Importer un fichier… sous Clés SSH importées et pointez l'application vers un fichier de clé privée existant — RSA, ed25519 et ECDSA sont pris en charge, clés chiffrées incluses. Une clé chiffrée demande sa phrase secrète une fois à l'import ; la phrase secrète est stockée dans le trousseau macOS (service io.bromure.agentic-coding.ssh-key-passphrases) et fournie via SSH_ASKPASS au lancement, jamais journalisée. La signature par clé importée passe par un processus ssh-agent privé que l'application génère pour elle-même (ssh-agent -D sur un socket sous le répertoire temporaire) — distinct de tout le reste de votre système.
  • Clés d'un agent de l'hôte. Une clé dont la moitié privée ne peut pas quitter son appareil — une YubiKey ou une autre clé de sécurité derrière gpg-agent, Secretive, 1Password — s'ajoute plutôt avec Depuis l'agent de l'hôte…. Choisissez le socket de l'agent (vide = le SSH_AUTH_SOCK propre à l'application, qui pour une application ouverte depuis le Finder est l'agent macOS, pas celui qu'exporte votre shell ; pour gpg-agent, utilisez ~/.gnupg/S.gpg-agent.ssh), cliquez sur Charger, et cochez les clés que l'espace de travail peut utiliser. Rien n'est copié : la VM ne voit que les clés cochées — et seulement tant que l'agent les détient, si bien qu'une clé débranchée n'est pas proposée — et leurs demandes de signature sont transmises à cet agent, de sorte qu'une demande de contact ou de code PIN apparaît sur votre Mac comme d'habitude (la demande l'attend jusqu'à deux minutes). Les autres clés de l'agent restent invisibles pour la VM, et une demande de signature avec l'une d'elles est refusée.

Par clé importée, activer Demander avant l'usage dans le volet Garde-fous fait que chaque demande de signature dans la VM invite au consentement. Chaque signature — clé par défaut ou importée — émet un événement d'audit credential.ssh_sign portant l'empreinte SHA256 de la clé et s'il s'agissait d'une clé gérée, importée ou provenant d'un agent de l'hôte.

Remarque : Votre ssh-agent de connexion macOS (celui de launchd) — ou tout autre agent de l'hôte — n'est délibérément jamais exposé à la VM dans son ensemble. Seules les clés propres à l'espace de travail, les clés que vous avez explicitement importées et les clés d'agent de l'hôte que vous avez choisies une à une sont accessibles depuis une session.

Approbation à chaque usage et durées d'octroi

Tout identifiant de ce chapitre peut être marqué Demander avant l'usage — une case à cocher par identifiant dans le volet Garde-fous (étiquetée Exiger une approbation pour l'usage sur le contrôle lui-même), désactivée par défaut, décrite dans l'interface comme : « Ouvrir une boîte de dialogue de confirmation la première fois que cet identifiant est utilisé dans une session. »

Lorsqu'un identifiant contrôlé est utilisé pour la première fois dans une session, le proxy retient la requête et affiche une boîte de dialogue de consentement intitulée Autoriser « nom de l'espace de travail » à utiliser l'identifiant ? (avec le nom de votre espace de travail et l'étiquette de l'identifiant renseignés), offrant quatre boutons :

BoutonOctroi
Autoriser pendant 5 minutesLimité dans le temps ; l'identifiant circule sans autre invite pendant 5 minutes.
Autoriser pendant 1 heureLimité dans le temps, 1 heure.
Autoriser pour le reste de la sessionJusqu'à l'arrêt de la VM de la machine.
Ne pas autoriserLa requête est refusée ; le refus est mémorisé pendant 5 minutes pour qu'une tempête de nouvelles tentatives d'un agent ne produise pas une tempête de boîtes de dialogue.

Comportement à connaître :

  • Fusion. Les requêtes concurrentes nécessitant le même identifiant se rassemblent sur une seule boîte de dialogue — un agent bavard lançant douze appels d'API en parallèle produit une seule invite, et les douze suivent votre décision.
  • Le refus l'emporte. Un refus actif court-circuite avant que toute autorisation plus ancienne ne soit consultée.
  • Éphémère par conception. Les autorisations et les refus ne sont conservés qu'en mémoire et sont révoqués à l'arrêt de la VM. « Le reste de la session » ne survit jamais à un redémarrage de la VM, et rien n'est conservé d'une exécution de l'application à l'autre.
  • Sessions headless. Dans une session SSH ou headless, la demande apparaît dans le tmux de la machine plutôt que sous forme d'alerte graphique — voir Accès à distance.

Pour AWS, le portillon s'applique à chaque appel de signature côté hôte ; pour les clés SSH, aux demandes de signature ; pour tout le reste, au premier échange sur le fil de la session.

Astuce : Le portillon de consentement est par identifiant, pas par hôte. Si vous voulez qu'un jeton manuel sans portée reste sous contrôle, l'approbation est le mécanisme conçu pour cela.

La fenêtre Approbations d'identifiants

Fenêtre → Approbations d'identifiants… ouvre une vue en direct de chaque décision de consentement prise pendant l'exécution actuelle de l'application : autorisations limitées dans le temps (5 minutes / 1 heure / reste de la session) et refus mémorisés. Chaque ligne affiche le nom de l'espace de travail et le temps restant, et offre Révoquer ; Tout révoquer (⌘⌫) efface tout d'un coup. La liste se rafraîchit automatiquement toutes les 2 secondes et rétrécit naturellement à mesure que les octrois expirent.

Comme les décisions ne vivent qu'en mémoire, la fenêtre est vide après l'expiration des autorisations, après l'arrêt de la VM (autorisations limitées à la session) et après la fermeture de l'application. C'est un panneau de contrôle pour le présent, pas un journal d'audit — pour l'historique, utilisez la chronologie de sécurité et le Traçage.

Le détecteur de compromission

Les leurres jouent un double rôle : en plus de tenir lieu de secrets, ce sont des fils-pièges. Un jeton factice a exactement une famille de destinations légitimes — la portée d'hôte pour laquelle il a été frappé. Il n'y a aucune raison honnête pour que sk-ant-api03-brm-… apparaisse dans une requête vers pastebin.example. Le proxy scrute donc chaque requête sortante — en-têtes et corps, via un automate Aho-Corasick, assez peu coûteux pour tourner sur tout — à la recherche de tout leurre partant hors de sa portée.

Lorsqu'il en trouve un, il traite la requête comme une tentative d'exfiltration d'identifiant :

  1. La requête est bloquée avec un HTTP 451. Pas un seul octet n'est transmis à la destination.
  2. La VM est mise en pause immédiatement. Si la machine tournait en arrière-plan, elle est d'abord ramenée à l'écran, et son image figée se teinte de rouge.
  3. Une alerte critique apparaît, intitulée Cet environnement est peut-être compromis : « Bromure a détecté une tentative sortante de fuite d'un identifiant de session depuis « machine » vers un hôte pour lequel il n'a pas été émis. La VM a été mise en pause. » Sous Fuites détectées :, elle liste une ligne par fuite — un aperçu du jeton (comme sk-a…f9q3), le nom de l'identifiant, l'hôte pour lequel il a été émis et l'hôte auquel il a été envoyé.
  4. La détection est enregistrée comme ligne rouge Courtage d'identifiants dans la chronologie de sécurité, et, sur les installations inscrites, comme événement credential.exfiltration.

L'alerte propose quatre boutons :

BoutonEffet
Éteindre (par défaut)Arrête la VM et marque la machine comme compromise.
BloquerArrête seulement cette requête (elle a déjà reçu un 451) et reprend la VM. Rien n'est mémorisé : si l'agent réessaie, le détecteur se déclenche à nouveau et l'alerte se rouvre.
AutoriserFait confiance à l'hôte observé pour le reste de cette session uniquement et reprend la VM. Dès lors, l'identifiant est substitué et envoyé à cet hôte (et à ses sous-domaines), et les requêtes vers lui ne sont plus signalées. La décision est enregistrée comme ligne verte Courtage d'identifiants, « allowed by user for this session », et, sur les installations inscrites, comme credential.exfiltration_allowed. La liste d'autorisation est vidée à l'arrêt de la VM.
Sauvegarder pour analyseDemande un dossier, exporte disk.img (une copie du disque système de la VM), home.tar.gz (le dossier personnel de la machine) et shares/<nom>.tar.gz pour chaque dossier partagé, puis arrête la VM et marque la machine comme compromise. L'état de la RAM de la VM est abandonné.

Seul Éteindre répond à la touche Retour ; Bloquer, Autoriser et Sauvegarder pour analyse n'ont pas d'équivalent clavier, si bien que reprendre une VM peut-être hostile — et à plus forte raison lui envoyer l'identifiant — exige toujours un clic explicite. Une seule alerte s'affiche à la fois ; les détections répétées pendant qu'elle est ouverte sont ignorées (chacune reste bloquée).

Astuce : Autoriser existe pour les configurations multi-hôtes légitimes — par exemple une clé au format OpenAI qu'un outil envoie délibérément au point de terminaison compatible OpenAI d'un autre fournisseur. Si vous ne reconnaissez pas la destination, ne l'autorisez pas.

Si la machine est reflétée par un client distant, la question apparaît sur le client sous forme de demande en attente avec Éteindre, Bloquer et Autoriser (la sauvegarde pour analyse nécessite un sélecteur de dossier local, elle n'est donc proposée que sur le Mac lui-même). Seule la VM concernée reste en pause ; l'hôte continue de servir toutes les autres machines. Une demande sans réponse éteint la VM au bout de 3 minutes.

Une machine marquée comme compromise refuse de démarrer tant que vous n'y avez pas remédié. La lancer affiche « To continue, the VM disk image and the persistent home folder must be wiped. Your tokens, ssh keys, and workspace settings are preserved. » avec Effacer et lancer et Annuler (la touche Retour ne confirme pas l'effacement). Tenez compte de l'avertissement qui l'accompagne : les dossiers partagés ne sont PAS effacés ; si la compromission est venue d'un paquet ou d'un fichier dans un dossier partagé, il s'y trouve peut-être encore — examinez ces dossiers avant de reprendre le travail.

Réponse recommandée à une alerte de compromission : ouvrez l'Inspecteur de traces (⇧⌘I) ou exécutez bromure-cli trace leaks pour voir l'hôte et la requête fautifs, décidez si une dépendance de projet ou une instruction injectée par prompt en était responsable (voir Injection de prompt et Chaîne d'approvisionnement), puis effacez et relancez.

Détails de portée :

  • Les leurres sans portée sont exemptés. Un jeton manuel avec un filtre d'hôte vide est « n'importe quel hôte » par conception et ne peut pas déclencher le détecteur ; les espaces réservés bidon d'abonnement sont de même exclus.
  • Les frères de premier rang sont tolérés. La correspondance reflète la politique de portée de l'échange, avec un assouplissement : les hôtes sous le même domaine enregistré que le fournisseur de l'identifiant (l'infrastructure Claude ou Codex sous anthropic.com, par exemple) utilisent une correspondance par famille, de sorte qu'un jeton légitime api.anthropic.com vu sur mcp-tools.anthropic.com n'est pas une fausse alerte. Tout le reste est strict.
  • Les fuites à l'apparence réelle sont aussi signalées. Indépendamment des fils-pièges factices, le proxy signale les secrets non échangés, à l'apparence réelle dans le trafic sortant — valeurs Bearer ou x-api-key avec des préfixes connus (sk-ant-, ghp_, AKIA, …) ou jetons opaques de 20 caractères ou plus. Ceux-ci apparaissent comme avertissements de fuite dans l'Inspecteur de traces et dans bromure-cli trace leaks ; ils signifient généralement qu'un vrai secret a été collé dans la VM à la main, ce que la frontière du fil existe précisément pour rendre inutile.

Le détecteur lui-même est toujours actif. Ce que vous pouvez désactiver, par machine, c'est l'interruption — voir la section suivante.

Échappatoires

Certains hôtes et clients ne fonctionnent pas sous une interception complète : un serveur à AC privée auquel l'hôte ne fait pas confiance, un client qui épingle le certificat de son serveur, ou une configuration légitime qui déclenche encore et encore l'alerte de compromission. Trois réglages par machine, en bas du panneau Garde-fous, assouplissent la frontière dans ces cas sans la désactiver. Les trois s'appliquent à chaud, sans redémarrage.

RéglagePar défautCe qu'il fait
Autoriser le contournement non sécurisé par requête (X-bromure-insecure)ActivéQuand une requête vers un hôte auto-signé ou à AC privée échoue à la validation du certificat, l'agent peut la réessayer avec l'en-tête X-bromure-insecure: yes pour ignorer la validation du certificat de cet amont. L'interception, le traçage et la protection contre les fuites restent actifs, et Bromure n'injecte aucun vrai identifiant sur une telle requête — seuls les leurres de l'invité sortent. Chaque utilisation est enregistrée dans la chronologie de sécurité comme ligne TLS amont : « allowed — certificate validation skipped (X-bromure-insecure); no credentials injected ». Activé par défaut parce qu'il n'agit que lorsque l'invité envoie l'en-tête ; désactivez-le pour interdire purement et simplement l'en-tête.
Désactiver l'interception transparenteDésactivéArrête la redirection au niveau réseau qui force le HTTP/HTTPS de la VM à passer par Bromure. Les sockets bruts et les clients à certificat épinglé atteignent alors directement le vrai réseau et le vrai certificat amont. Le proxy lui-même reste : HTTP(S)_PROXY reste défini, si bien que les outils qui respectent le proxy (apt, git, pip, curl, node…) et les appels d'API de l'agent lui-même passent toujours par Bromure et conservent la substitution des identifiants, le traçage et les garde-fous. Le trafic qui ignore les réglages de proxy n'est plus couvert par les règles de sortie.
Ne pas alerter en cas d'exfiltration d'identifiantsDésactivéSupprime l'alerte de compromission et la mise en pause de la VM. La requête qui fuit est toujours bloquée avec un 451 et toujours enregistrée dans la chronologie de sécurité (« blocked — exfiltration attempt (alerts off, VM not paused) ») ; seule l'interruption disparaît.

Avertissement : Chacun de ces réglages échange un peu de protection contre de la compatibilité. Préférez le plus étroit : l'en-tête par requête pour un certificat non fiable, Autoriser dans l'alerte de compromission pour une destination de confiance, et les interrupteurs à l'échelle de la machine seulement pour une machine qui ne peut pas fonctionner autrement.

Où résident les secrets sur l'hôte

Tout ce qui est sensible est chiffré au repos avec AES-GCM sous une clé maîtresse de 256 bits propre à l'installation — le coffre à secrets. La clé maîtresse réside dans le Data Protection Keychain de macOS, limitée à l'identité de signature de l'application, avec l'accessibilité kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly et la synchronisation iCloud désactivée. Elle n'invite jamais, ne se synchronise jamais et ne quitte jamais le Mac. Si le trousseau est inaccessible (une build non signée ou non provisionnée), l'application se rabat sur un fichier de clé en mode 0600 stocké à côté du chiffré — plus faible, puisque la clé et le chiffré partagent alors un disque, mais cela maintient le chiffrement au repos fonctionnel ; une version pleinement provisionnée utilise le trousseau.

Conséquences pratiques :

  • Les sauvegardes et copies sont du chiffré. Une sauvegarde Time Machine ou un dossier Application Support copié ne contient que des blobs chiffrés ; sans l'entrée du trousseau de ce Mac, ils ne peuvent pas être déchiffrés (sauf si la clé de repli sur fichier était en usage et copiée avec).
  • Effacer l'entrée du trousseau fait tourner la clé. Les blobs chiffrés existants deviennent illisibles et vous ressaisissez vos identifiants. Les métadonnées non sensibles de profile.json ne sont pas affectées.
  • Rien n'est synchronisé nulle part. Aucun identifiant, magasin de jetons ou matériel de clé n'est téléversé, synchronisé ni sauvegardé par l'application elle-même.

Emplacements sur disque, tous sous ~/Library/Application Support/BromureAC/ sauf indication contraire :

EmplacementContenu
ca/cert.pem, ca/key.pemL'autorité de certification racine de Bromure Agentic Coding (clé en mode 0600). Supprimez le répertoire pour faire tourner.
fake-salt.binLe sel HKDF de 32 octets propre à l'installation derrière la dérivation des leurres (0600). Le supprimer fait tourner chaque leurre sur ce Mac.
claude-subscription.enc, codex-subscription.enc, grok-subscription.enc, kimi-subscription.encMagasins d'abonnements chiffrés en AES-GCM : la connexion partagée plus la connexion propre de chaque machine, 0600.
models.encLes réglages globaux des modèles de Préférences › Modèles, clés d'API des fournisseurs comprises, chiffrés avec la clé du coffre.
pii/<workspace-id>.keyLa clé propre à chaque machine derrière les substituts de la protection des données personnelles (0600).
secrets-master.keyLa clé maîtresse de repli en 0600 — présente uniquement quand le Data Protection Keychain est inaccessible.
default-ssh/id_ed25519.raw, default-ssh/id_ed25519.pubLa paire de clés SSH par défaut partagée, copiée dans les nouvelles machines.
profiles/<id>/ssh/Les clés SSH émises pour chaque machine (le répertoire de l'agent).
Trousseau : io.bromure.agentic-coding.master-keyLa clé maîtresse AES-256 du coffre (compte v1), Data Protection Keychain.
Trousseau : io.bromure.agentic-coding.ssh-key-passphrasesPhrases secrètes des clés SSH importées, un élément par fichier de profil/clé.

Les lectures côté hôte pour les imports — ~/.aws/config, ~/.aws/sso/cache/*.json, ~/.docker/config.json, fichiers kubeconfig — se produisent sur l'hôte uniquement ; aucun de ces fichiers n'est jamais monté dans une VM. Les corps de traces chiffrés (voir Traçage) utilisent la même clé de coffre.

Vérifier la frontière vous-même

La frontière du fil est conçue pour être vérifiable, non prise pour argent comptant. Depuis un shell à l'intérieur de n'importe quelle session :

1. L'environnement contient des leurres.

echo "$ANTHROPIC_API_KEY"
# sk-ant-api03-brm-…            ← a fake, not your key

env | grep -E 'TOKEN|KEY' 
# every value is brm_/ghp_/glpat_/dop_v1_/lin_api_-shaped placeholder

2. Les fichiers de configuration contiennent des leurres.

cat ~/.git-credentials          # fake tokens per git host
cat ~/.docker/config.json       # fake base64 auth blobs
grep -A2 credential_process ~/.aws/config   # helper, not a secret key

3. Et pourtant, tout fonctionne.

aws sts get-caller-identity     # succeeds — the host resigned the request
gh api user                     # succeeds — the fake was swapped on the wire

4. Le TLS à l'intérieur de la VM se termine au proxy.

openssl s_client -connect api.anthropic.com:443 -brief 2>&1 | head
# issuer: the Bromure Agentic Coding Root CA — not a public CA

5. Les clés SSH sont absentes, mais la signature fonctionne.

ssh-add -L                      # lists public keys served by the vsock agent
ls ~/.ssh/id_*                  # no private key files to find

6. Sur l'hôte, regardez les substitutions se produire. Ouvrez la chronologie de sécurité et filtrez sur Courtage d'identifiants : chaque substitution apparaît comme une ligne telle que sk-a…f9q3 → api.anthropic.com — swapped in …. Avec le traçage activé pour la machine, vous pouvez aussi exécuter :

bromure-cli trace summary        # per-request swap reports and leak warnings
bromure-cli trace leaks          # only the suspicious ones

ou ouvrez l'Inspecteur de traces (⇧⌘I), où les requêtes échangées sont annotées Jamais envoyé à la VM — échangé par le proxy.

Si vous trouvez un jour un vrai identifiant à l'intérieur d'une VM, il y est arrivé de l'une de deux façons : vous (ou l'agent, sous votre direction) l'y avez collé à la main, ou il est arrivé via un dossier partagé. La machinerie d'échange n'écrit jamais de vrais dans l'invité — et le détecteur de compromission traite les secrets à l'apparence réelle sur le fil comme une fuite précisément parce qu'ils ne devraient pas y exister.

Référence rapide

Ports vsock à la frontière invité-hôte :

PortObjet
8443Le proxy MITM HTTPS — l'intégralité de la sortie de l'invité.
8444Le pont ssh-agent derrière SSH_AUTH_SOCK.
8445L'assistant credential_process d'AWS.
8446Le canal de jetons Claude utilisé par la VM d'inscription — un port qu'il partage avec le pont d'inférence locale (ils sont mis en place dans des processus différents ; voir Modèles et fournisseurs).
8447Le canal de jetons Codex utilisé par la VM d'inscription (jetons d'accès, de rafraîchissement et d'identité).

Les deux canaux de jetons sont à sens unique : l'hôte ne peut qu'écrire des leurres dans la VM, et la VM ne peut qu'envoyer des vraies valeurs à l'hôte. Il n'existe aucune requête par laquelle la VM pourrait redemander un vrai jeton.

Commandes CLI associées (référence complète dans CLI, API et MCP) :

CommandeObjet
bromure-cli workspaces create --auth token|subscription|bedrock|localCrée un espace de travail avec le mode d'authentification de son agent principal.
bromure-cli vm run --auth token|subscription|bedrock|localDémarre une VM en choisissant le mode d'authentification d'un espace de travail créé à la volée.
bromure-cli workspaces ssh-keygen <workspace>Frapper une nouvelle clé SSH d'espace de travail côté hôte et imprimer la clé publique.
bromure-cli trace summary [workspace]Résumer le trafic tracé, y compris les échanges et les avertissements de fuite.
bromure-cli trace leaks [workspace]Afficher les requêtes tracées avec des fuites d'identifiants potentielles.