Comment Sallyport protège vos clés
Où une clé est gardée et quand elle s’ouvre, comment les comptes restent séparés, ce que refuse le filtre réseau et comment le journal est signé.
Sur cette page
- La clé parcourt un seul segment : de Sallyport au service
- Chaque enregistrement stocké a sa propre clé
- Les comptes ne voient jamais les données des autres
- Un agent ne peut pas retourner la passerelle contre elle-même
- Les agents se connectent avec leurs propres jetons
- Une personne décide là où vous le demandez, et toujours pour deux actions
- Chaque appel est écrit avant de s’exécuter
- Ce que deviennent les réponses que vos appels rapportent
- Redémarrages et pannes ne perdent ni ne répètent un appel
La clé parcourt un seul segment : de Sallyport au service
Un seul processus garde le coffre et le journal, et passe lui-même l’appel sortant. L’agent nomme l’action. Sallyport place la clé dans la requête et l’envoie. L’agent ne reçoit jamais la clé.
- Aucune route ne renvoie une clé. Ni au propriétaire, ni au support, ni par l’API. Vous pouvez remplacer ou supprimer une clé ; personne ne peut l’afficher.
- Une clé ne part que vers les adresses avec lesquelles elle a été enregistrée. Une nouvelle connexion, une nouvelle adresse ou un nouveau point d’émission de jetons pour une clé enregistrée sont refusés : une autre adresse demande une nouvelle clé, saisie à nouveau. Une clé du catalogue atteint aussi les hôtes d’API de son service.
- Une clé s’ouvre pour trois choses seulement : un appel d’agent autorisé à partir, la vérification que vous lancez en enregistrant une clé ou en cliquant sur « Vérifier à nouveau », et la lecture de la liste d’outils d’un serveur MCP que vous avez connecté. Chaque ouverture est écrite au journal avant l’usage de la clé.
- En mémoire, la clé reste en octets et s’efface après l’appel. Une chaîne Go ne s’efface pas, donc un test fait échouer le build si une clé devient une chaîne.
Chaque enregistrement stocké a sa propre clé
La clé racine ouvre une clé par compte. De la clé du compte, HKDF-SHA256 dérive une clé par type de données : clés de service, renouvellements OAuth, requêtes que les agents envoient, secrets de webhooks. De celle-ci vient une clé par enregistrement.
Chaque enregistrement est scellé avec ChaCha20-Poly1305 et lié à son compte, son type, son enregistrement et sa version. Changez l’un des quatre et l’enregistrement ne s’ouvre plus.
- La clé racine n’est jamais dans la base de données. C’est un fichier sur l’hôte de la passerelle. Deux des trois parts de récupération suffisent à la reconstruire.
- La clé racine est testée chaque jour. Une tâche quotidienne ouvre avec elle une vraie clé de compte, et un échec parvient aussitôt aux opérateurs.
Les comptes ne voient jamais les données des autres
La passerelle se connecte à la base avec un rôle qui ne possède aucune table et ne peut pas contourner la sécurité au niveau des lignes. Chaque requête tourne dans une transaction qui nomme le compte et les espaces de travail qu’elle peut voir.
- Un test fait échouer le build si une table ou une partition du journal n’a pas sa politique.
- Votre trafic passe par vos propres connexions. Sallyport garde un transport HTTP par compte et par hôte de service, donc la requête d’un autre compte ne réutilise jamais votre connexion.
Un agent ne peut pas retourner la passerelle contre elle-même
Sallyport appelle uniquement des services publics d’internet. Avant d’ouvrir une connexion, la passerelle résout le nom et compare chaque adresse à une liste de refus compilée dans le binaire. La configuration peut seulement allonger cette liste.
- Refusés quoi que dise la connexion : plages privées, loopback, link-local et adresses de métadonnées cloud, CGNAT, multicast, et tous les noms et réseaux de Sallyport.
- Le nom est résolu à nouveau quand l’appel s’exécute, y compris un appel qui a attendu une personne. L’adresse est vérifiée et fixée au moment de l’envoi.
- Votre clé ne suit jamais une redirection. Un 3xx revient à l’agent comme résultat. Si l’agent veut la nouvelle adresse, il fait un nouvel appel et toutes les vérifications repassent.
Les agents se connectent avec leurs propres jetons
Chaque agent a ses propres jetons, affichés une seule fois à la création. La base ne stocke qu’un HMAC-SHA-256 de chaque jeton, sous un pepper gardé hors de la base. Une copie de la base ne contient aucun jeton valable.
- Coupez un agent en un clic. « Mettre l’agent en pause », sur sa page, refuse son appel suivant, quels que soient son jeton ou sa connexion. Révoquer un jeton dans « Jetons » n’arrête que ce jeton. « Supprimer l’agent », en bas de sa page, le retire pour de bon.
- Un client MCP qui se connecte par OAuth reçoit un jeton Sallyport une fois qu’une personne a approuvé le client sur un écran de consentement. Le client ne voit jamais une clé de service.
- Une plateforme qui fait tourner des agents sur ses propres machines se connecte comme un accès pour gérer des agents, pas comme un agent. Son propre jeton n’appelle rien : le point MCP et le proxy le refusent. Elle reçoit un jeton d’une heure par machine seulement après le consentement d’une personne. Chacun de ces agents démarre sans accès, et seule une personne lui en donne. Chaque jeton agit comme l’agent propre de cette machine et prend fin avec la connexion.
- La liste des outils change selon l’agent, elle est donc marquée privée. Un client ne peut pas mettre en cache les outils d’un agent pour les montrer à un autre.
Une personne décide là où vous le demandez, et toujours pour deux actions
Par défaut, chaque appel passe sans demander. Activez « Demander à chaque appel » pour un agent et une connexion quand vous voulez voir chaque appel avant.
- La carte montre la requête que Sallyport enverra : méthode, hôte et chemin. Les mots de l’agent lui-même sont dans un bloc à part, marqué non vérifié.
- « Approuver » couvre une requête exacte. Cette approbation est liée à un condensé de cette requête, et la requête stockée est comparée à ce condensé avant l’envoi. Le bouton d’autorisation de la carte couvre davantage : le même agent, la même connexion, la même classe et le même chemin, pour une durée et un nombre d’appels fixés.
- Un DELETE ne peut pas passer pour un GET. Les en-têtes et paramètres qui changent la méthode sont retirés avant le classement de l’appel et avant le condensé.
- Une limite de débit ou de concurrence répond avec un moment où réessayer. Elle ne crée jamais de carte, car personne n’a de décision à prendre.
Chaque appel est écrit avant de s’exécuter
L’intention de l’appel et son entrée au journal partagent une transaction avec la décision d’envoyer. Les numéros de séquence viennent d’une ligne compteur qu’un rollback ne peut pas sauter. La numérotation n’a pas de trou, donc une entrée manquante se lit comme une suppression.
- Chaque entrée s’engage sur la précédente. Son hash couvre le schéma, le compte, le numéro de séquence, le hash précédent et l’événement. Le schéma s’appelle spc-chain/2.
- Chaque entrée est signée avec Ed25519. Les clés publiques, l’active et les retirées, sont publiées à
https://mcp.sallyport.cloud/.well-known/sallyport-audit-keys.json, et une clé retirée reste dans cette liste après un changement de clé. - La passerelle ne peut pas modifier son propre journal. Son rôle en base ajoute des entrées et les lit, sans droit d’en modifier une seule.
- Les événements sont stockés en JSON canonique lisible, et la chaîne est calculée sur ces octets exacts. Quiconque reçoit le fichier lit ce que vous lisez.
- « Télécharger le journal », sur l’écran « Activité », enregistre tout le journal en JSON Lines, chaque entrée avec son hash et sa signature. Il est réservé à qui audite tous les espaces de travail : un propriétaire, ou un administrateur ou un auditeur de toute l’organisation sans rôle plus restreint dans un espace.
- Chaque entrée du journal appartient à l’espace de travail de ce qu’elle concerne. L’onglet « Journal » et un webhook montrent à chacun les entrées des espaces où il est propriétaire, administrateur ou auditeur, et celles de l’organisation elle-même. Un administrateur de l’organisation qui n’est que membre dans l’espace d’un client ne lit pas les entrées de ce client.
Ce que deviennent les réponses que vos appels rapportent
Une réponse qui tient part directement à l’agent. Une réponse plus longue est stockée pour que l’agent lise la suite par morceaux.
- Une réponse stockée est lisible par l’agent dont l’appel l’a produite et par les personnes de votre compte qui ont accès au journal. Chaque lecture est écrite au journal.
- Les réponses stockées, la réponse de chaque appel et les corps de requête de plus de 1 Mio sont supprimés au bout de 30 jours. Un corps volumineux est stocké scellé sous une clé à lui.
- L’historique des appels, la requête de chaque agent et le journal sont gardés 180 jours par défaut. Modifiez-le dans « Paramètres », « Organisation », « Journal et historique des appels (jours) ».
- Une notification du navigateur nomme l’agent, le type d’action et le service, avec les identifiants du chemin remplacés. Elle ne porte jamais de valeurs d’arguments, de corps ni de clé.
Redémarrages et pannes ne perdent ni ne répètent un appel
- Un appel qui attend une personne vit dans la base. Un déploiement ne le perd pas, et l’agent reprend avec le même id d’appel.
- Si le processus s’arrête après qu’une requête est partie vers le service, l’appel est marqué comme à l’issue inconnue. Sallyport ne le relance jamais tout seul, donc un paiement ne part jamais deux fois.