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 parcourt chaque type d'identifiant pris en charge et son cycle de vie, le système d'approbation à chaque usage, le détecteur de compromission et la façon de vérifier la frontière vous-même.

Remarque : Ce chapitre couvre les concepts et le comportement à l'exécution. Pour une référence champ par champ du volet de réglages, voir Réglages → Identifiants.

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-…
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 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 de jetons. Lorsqu'une VM d'espace de travail démarre, l'application construit un plan de jetons propre à l'espace de travail, appariant chaque identifiant réel à 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 d'échange en mémoire du proxy, chacune indexée sur 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 se configurent par espace de travail. Ouvrez l'éditeur de l'espace de travail (Modifier l'espace de travail) et sélectionnez Identifiants dans la barre latérale.

Le volet Identifiants de l'éditeur d'espace de travail, montrant les champs Identité Git au-dessus de la liste des identifiants configurés, un bouton Ajouter un identifiant et un bouton Importer un fichier env

Le volet s'ouvre avec Identité Git (un nom et un e-mail écrits dans ~/.gitconfig dans la VM ; laissez les deux vides pour conserver les valeurs par défaut de git — les espaces réservés ne sont que des exemples, pas des identifiants), suivi d'une liste des seuls identifiants que vous avez configurés, regroupés sous des en-têtes de catégorie (Agents, Git, Cloud, Bases de données, SSH, Autre). Deux boutons se trouvent en bas : Ajouter un identifiant ouvre un sélecteur des types d'identifiants — jeton Git, clé SSH, identifiants AWS, jeton DigitalOcean, clé d'API Linear, Kubernetes, registre de conteneurs, base de données et Autre clé d'API — et Importer un fichier env… importe en masse depuis un .env ou un ~/.bashrc. La clé propre à l'agent principal réside dans le volet Agents, décrit ci-après. Cliquez sur Enregistrer ; le prochain lancement de session écrit les leurres dans la VM et charge les vrais dans le proxy.

Le portillon d'approbation par identifiant (Demander avant l'usage) et la politique d'écriture de chaque service se définissent dans le volet Garde-fous, pas ici — le volet Identifiants ne porte plus ces contrôles. Voir Réglages → Identifiants pour la référence champ par champ.

Six fournisseurs sont gérés automatiquement — Anthropic, OpenAI, GitHub, GitLab, DigitalOcean et Kubernetes n'ont besoin d'aucune règle de jeton manuel ; 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 environnants et les commentaires de fin, et saute délibérément tout ce qui nécessiterait une évaluation par le shell (interpolation $VAR ou substitution $(…)), de sorte qu'il est sans danger de le pointer sur un vrai .bashrc. Une feuille de révision montre ensuite les variables avec des valeurs masquées : les noms reconnus (ANTHROPIC_API_KEY, OPENAI_API_KEY, XAI_API_KEY, GH_TOKEN/GITHUB_TOKEN, GITLAB_TOKEN, AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN, DIGITALOCEAN_ACCESS_TOKEN, LINEAR_API_KEY) sont automatiquement mappés à 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ôte séparée par des virgules que vous fournissez. Les entrées déjà configurées sont signalées et laissées décochées, de sorte qu'une réimportation n'écrase jamais silencieusement un secret.

Types d'identifiants

Clés d'API de l'agent principal (Anthropic, OpenAI, xAI)

La clé de l'agent principal de l'espace de travail se définit dans le volet Agents, où chaque fiche d'agent offre un sélecteur de mode d'authentification.

Le volet Agents montrant la fiche Claude Code marquée Principal, avec les modes d'authentification jeton d'API, Abonnement (connexion interactive) avec un lien S'inscrire…, Bedrock (AWS), et une option Modèle local désactivée, plus un champ clé d'API Anthropic

Choisissez Jeton d'API et collez la clé dans le champ (Clé d'API Anthropic pour Claude Code, Clé d'API OpenAI pour Codex, la clé xAI pour Grok Build). Cycle de vie :

  • Dans la VM : exportée sous ANTHROPIC_API_KEY / OPENAI_API_KEY / XAI_API_KEY, contenant le leurre à la forme du fournisseur (sk-ant-api03-brm-…, sk-brm-…, xai-brm-…).
  • Sur le fil : échangée contre la vraie clé sur les requêtes vers les hôtes du fournisseur (anthropic.com, openai.com, x.ai respectivement).
  • Approbation : pour contrôler le premier usage de chaque session, activez Demander avant l'usage pour la clé de l'agent dans le volet Garde-fous (voir Approbation à chaque usage). Elle est désactivée par défaut.

Les autres modes d'authentification du sélecteur — Abonnement (connexion interactive), Bedrock (AWS) et Modèle local — sont couverts ci-dessous et dans Modèles locaux. Depuis la CLI, le même choix correspond à --auth token|subscription|bedrock|local sur bromure-cli workspaces create (et token|subscription|bedrock sur bromure-cli vm run pour les espaces de travail à la volée).

Abonnements Claude, Codex et Grok

Si vous disposez d'un abonnement Claude, ChatGPT (Codex) ou Grok plutôt que d'une clé d'API, l'agent s'authentifie normalement par connexion OAuth interactive — un flux de navigateur qu'une VM en bac à sable ne peut (et ne devrait) pas mener à terme avec de vrais jetons. Bromure Agentic Coding prend en charge les abonnements avec deux mécanismes. Tous deux aboutissent au même point : les vrais jetons OAuth ne résident que sur l'hôte, et l'invité s'exécute avec une clé bidon.

S'inscrire auprès de Claude / ChatGPT / Grok (recommandé)

Réglez le mode d'authentification de l'agent sur Abonnement (connexion interactive) et cliquez sur S'inscrire…. Ce qui se passe :

  1. L'application vérifie que le proxy est en cours d'exécution (l'inscription est refusée sinon) et affiche une feuille explicative intitulée S'inscrire auprès de Claude (ou ChatGPT / Grok). Cliquez sur Continuer.
  2. Une VM d'inscription jetable démarre — temporaire, isolée, sans montage de dossier d'espace de travail et sans table d'échange d'identifiants. À l'intérieur, la vraie commande de connexion s'exécute (claude login, codex login, ou l'équivalent Grok).
  3. Le navigateur par défaut de votre Mac ouvre la page de connexion du fournisseur. Connectez-vous comme d'habitude. Vous disposez d'environ 4 minutes avant l'expiration du flux.
  4. Les jetons OAuth qui en résultent sont capturés sur l'hôte, chiffrés et stockés ; la VM jetable est détruite.
  5. Si vous avez lancé l'inscription depuis un éditeur d'espace de travail, l'application demande Partager avec chaque espace de travail ? — choisissez Chaque espace de travail pour stocker l'abonnement comme valeur par défaut partagée, ou Cet espace de travail uniquement. Une inscription démarrée depuis les Préférences de l'application stocke toujours la valeur par défaut partagée sans demander.

Par la suite, l'invité de chaque session s'exécute en mode clé d'API avec un identifiant bidon déterministe — un faux ANTHROPIC_API_KEY pour Claude, un ~/.codex/auth.json amorcé contenant un JWT bidon à expiration lointaine pour Codex (de sorte que le client ne tente jamais de le rafraîchir lui-même), un ~/.grok/auth.json d'espace réservé pour Grok. Le proxy reconnaît la valeur bidon et injecte un jeton d'accès Authorization: Bearer actif (plus l'en-tête bêta OAuth, pour Claude) sur le fil.

La garde et le rafraîchissement des jetons sont entièrement côté hôte. L'hôte rafraîchit les jetons environ 5 minutes avant l'expiration auprès du point de terminaison de jetons du fournisseur (platform.claude.com/v1/oauth/token pour Claude, auth.openai.com/oauth/token pour Codex, auth.x.ai/oauth2/token pour Grok), de sorte qu'un seul rafraîchissement sert chaque VM en cours d'exécution et que l'invité ne détient jamais de jeton de rafraîchissement. Un enregistrement fraîchement capturé est délibérément stocké avec une expiration déjà passée, forçant un rafraîchissement à la première utilisation — prouvant que le chemin de rafraîchissement fonctionne avant que vous n'en dépendiez.

Les contrôles à côté du sélecteur de mode d'authentification complètent le cycle de vie : Réinscrire… répète la capture (par exemple après avoir révoqué des sessions en amont), et Oublier supprime l'abonnement stocké de l'hôte.

L'échange de jeton en session

Autrement, si l'agent se connecte lui-même à l'intérieur de la VM (vous exécutez claude login dans la session), le proxy remarque un vrai jeton OAuth d'abonnement partant vers le fournisseur et propose d'en prendre la garde. Une feuille apparaît — Échanger le jeton d'abonnement Claude ? (ou Codex) — expliquant que le vrai jeton peut rester sur ce Mac tandis qu'un leurre le remplace dans le fichier d'identifiants de la VM. Les jetons d'accès et de rafraîchissement sont échangés ensemble. Vos options :

BoutonEffet
ÉchangerLes vrais jetons passent dans le magasin de l'hôte ; le fichier d'identifiants de la VM est réécrit avec des leurres ; le proxy injecte désormais le vrai jeton sur le fil.
Pas maintenantRien ne change cette session ; l'invite revient à la prochaine session.
Jamais pour cet espace de travailArrête les invites pour cet espace de travail.

L'état par espace de travail derrière cette invite est visible dans l'éditeur sous Échange de jeton d'abonnement Claude / Échange de jeton d'abonnement Codex (non défini par défaut ; « accepté » ou « refusé » après votre choix). Le canal d'échange hôte-vers-VM est délibérément unidirectionnel : l'hôte ne peut qu'écrire des leurres dans la VM, et la VM ne peut qu'envoyer des vrais vers l'hôte — il n'existe aucun RPC par lequel la VM pourrait redemander un vrai jeton. L'agent dans la VM refuse en outre d'écrire tout identifiant qui ne porte pas le préfixe factice brm-, de sorte que même un hôte malveillant ne peut pas corrompre le fichier d'identifiants de l'invité avec une vraie valeur.

Remarque : Codex reste en mode abonnement à l'intérieur de l'invité (son mode clé d'API cible un backend différent), et les jetons de Grok voyagent via le fichier ~/.grok/auth.json plutôt que via un agent vsock. Ce sont des détails d'implémentation ; le modèle de garde est identique.

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 à *.amazonaws.com et *.amazonaws.com.cn (GovCloud, ISO, régionaux et hôtes S3 de style bucket inclus), retire la signature de l'invité, injecte le vrai X-Amz-Security-Token lorsqu'un jeton de session est présent, et resigne avec le vrai secret avant que la requête ne quitte votre Mac. Chaque resignature réussie émet un événement d'audit credential.aws_sign avec une clé d'accès masquée, visible dans Traçage.

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).

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

Bedrock (AWS) dans le sélecteur de mode d'authentification de l'agent exécute Claude Code contre AWS Bedrock en utilisant les identifiants AWS que l'espace de travail a configurés (statiques ou SSO) — c'est un mode d'authentification de l'outil principal, pas un identifiant distinct. Réglez le mode d'authentification, configurez Identifiants → AWS, et définissez éventuellement un ID de modèle Bedrock sur l'espace de travail. La signature passe par le même chemin de resigneur, puisque les points de terminaison Bedrock sont des hôtes *.amazonaws.com.

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 1Passwordop://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.

L'importation d'un fichier .env ou .env.op (Importer depuis .env… dans l'éditeur) reconnaît automatiquement les valeurs op:// — sous des noms reconnus comme ANTHROPIC_API_KEY ou arbitraires comme STRIPE_KEY — et stocke chacune comme un 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 réglages d'API Linear dans votre navigateur ; les clés viennent de linear.app → Réglages → API). Le leurre (lin_api_ + 40) est exporté sous LINEAR_API_KEY, que le SDK Linear, les serveurs MCP et les outils CLI récupèrent automatiquement ; l'échange est strictement limité à 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 pour les déclencheurs d'automatisation par ticket Linear — voir Automatisation et CLI.

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.

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 si elle était une clé gérée ou importée.

Remarque : Votre ssh-agent de connexion macOS (celui de launchd) n'est délibérément jamais exposé à la VM. Seules les clés propres à l'espace de travail et les clés que vous avez explicitement importées 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'à la fermeture de la fenêtre de session.
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 octrois et refus ne sont conservés qu'en mémoire et sont révoqués au démontage de la session. « Reste de la session » ne survit jamais à une fermeture de fenêtre, et rien n'est persisté d'une exécution de l'application à l'autre.
  • Sessions sans interface. Dans une session SSH ou sans interface, l'invite apparaît dans le tmux de l'espace de travail plutôt que comme une 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 sont qu'en mémoire, la fenêtre est vide une fois les octrois expirés, une fois les sessions fermées (octrois à portée de session) et une fois l'application quittée. C'est un panneau de contrôle du présent, pas un journal d'audit — pour l'historique, utilisez 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.
  3. Une alerte se déclenche : « Bromure a détecté une tentative sortante de divulguer un identifiant de session à un hôte pour lequel il n'a pas été frappé. La VM a été mise en pause. »

L'espace de travail est alors marqué comme compromis — le navigateur d'espaces de travail affiche Compromis — le lancement proposera d'effacer le disque et le home — et le prochain lancement exige une remédiation : « Pour continuer, l'image disque de la VM et le dossier home persistant doivent être effacés. Vos jetons, clés ssh et réglages d'espace de travail sont préservés. » Cliquez sur Effacer et lancer pour continuer. Prêtez attention à l'avertissement qui l'accompagne : les dossiers partagés ne sont PAS effacés, de sorte que si la compromission est venue d'un paquet ou d'un fichier dans un dossier partagé, elle peut encore s'y trouver — passez ces dossiers en revue 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.

Il n'y a rien à activer — le détecteur est toujours actif.

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.encMagasins OAuth d'abonnement chiffrés AES-GCM (valeur par défaut partagée plus surcharges par profil), 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 nouveaux espaces de travail.
profiles/<id>/ssh/Clés SSH frappées par espace de travail (le répertoire d'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 échanges se produire. Activez le traçage pour l'espace de travail, puis :

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.
8446L'agent d'échange de jeton d'abonnement Claude — un port qu'il partage avec le pont d'inférence locale (ils sont mis en place dans des flux différents ; gardez ceci à l'esprit lors du diagnostic d'une session qui utilise les deux — voir Modèles locaux).
8447L'agent d'échange de jeton d'abonnement Codex (jeton d'accès, de rafraîchissement et d'ID).

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

CommandeObjet
bromure-cli workspaces create --auth token|subscription|bedrock|localCréer un espace de travail avec son mode d'authentification.
bromure-cli vm run --auth token|subscription|bedrockDémarrer une VM, en sélectionnant le mode d'authentification pour un espace de travail à 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.