La façon sûre de donner un accès SSH à un modèle local, c’est de ne jamais lui donner de clé. Faites-lui appeler un outil — un serveur MCP jouant le rôle de gardien — qui détient les clés (ou délivre des certificats à courte durée), n’atteint que les hôtes que vous avez listés, applique par hôte une liste de commandes autorisées et journalise chacune d’elles. Dès lors, un prompt détourné ne peut que demander une action via le gardien ; il ne peut ni usurper votre identité ni atteindre un hôte que vous n’avez pas listé. Ce que l’on comprend mal en premier : faire tourner le modèle sur votre propre matériel protège vos prompts, pas vos serveurs — « c’est local, donc c’est sûr » est faux, et n’y change rien le jour où ce modèle obtient un shell.
Les modèles locaux ont le vent en poupe. Ollama sur un poste de travail, un modèle à poids ouverts derrière votre propre endpoint, un agent de code auto-hébergé — vous les utilisez pour de bonnes raisons : confidentialité, coût, aucune limite de débit, ça marche dans l’avion. Et une fois qu’un modèle traite déjà vos prompts, l’étape évidente suivante est de le pointer vers votre infrastructure : lui faire suivre un journal, redémarrer un service, lancer la migration — et c’est là qu’arrive la vraie question.
Pourquoi « local » ne rend pas l’accès serveur sûr
Deux choses restent exactement aussi dangereuses, que le modèle tourne dans un datacenter ou sur la machine sous votre bureau.
La clé reste un identifiant au porteur. Déposez id_ed25519 dans l’environnement de l’agent pour qu’il lance ssh lui-même, et quiconque — ou quoi que ce soit — détient ces octets est vous, sur chaque hôte qui fait confiance à la clé. Faire tourner le modèle en local n’y change rien ; cela ne fait que déplacer la copie vers une machine qui se trouve être la vôtre. Et vous ne pouvez toujours pas revenir en arrière : dès que la clé est passée par le contexte du modèle — une variable d’environnement, un fichier monté, un appel d’outil, une transcription — vous ne pouvez plus prouver qu’elle n’a pas fini quelque part où elle n’aurait pas dû. La seule réponse honnête à « le modèle a-t-il vu ma clé ? » est de la renouveler sur chaque hôte.
Un modèle local se laisse tout aussi facilement tromper. L’injection de prompt n’a pas besoin d’un modèle dans le cloud. Une ligne de journal empoisonnée, un nom de fichier malveillant, un résultat d’outil piégé, un plan trop zélé — un modèle local agit sur tout cela aussi volontiers qu’un modèle hébergé. Le risque est même pire, car on fait davantage confiance aux installations locales, on les câble avec moins de garde-fous et on leur accorde un accès plus large, précisément parce que « c’est sur ma machine ». C’est le mauvais réflexe : le jugement du modèle n’est pas meilleur parce que les poids sont locaux.
L’objectif est donc le même que pour n’importe quel agent — laisser le modèle faire le travail sans jamais détenir l’identifiant, et rendre chaque action cadrée, visible et réversible.
Trois mauvaises façons de s’y prendre
Coller la clé brute. La voie directe, et la pire : aucune portée, aucune expiration, et l’irréversibilité évoquée plus haut. La clé qui déploie en préproduction peut généralement atteindre aussi la base de production, à deux sauts de là.
Émettre un jeton à longue durée de vie. Un jeton de déploiement ou un identifiant « d’automatisation » qui n’expire jamais. Cela paraît plus propre qu’une clé, mais c’est le même problème d’accès au porteur avec des étapes en plus. Si révoquer quelque chose suppose de se souvenir qu’il existe, il survivra à l’expérience qui l’a créé.
Lui donner son propre accès root et passer à autre chose. Le bon réflexe — une identité distincte — mal appliqué. Déposez une clé publique dans authorized_keys pour un utilisateur robot et vous avez bâti un accès sans aucune piste d’audit : rien ne distingue les commandes du modèle de celles de quiconque, et quand quelque chose casse à 2 h du matin, vous reconstituez sa session à partir de l’historique bash et de votre intuition.
Le fil conducteur : le modèle détient un identifiant permanent, et l’observabilité passe après.
Le schéma qui fonctionne : un gardien, pas une copie
Inversez la logique. Le modèle ne devrait jamais détenir l’identifiant, point.
- Le modèle demande ; un gardien signe. Un intermédiaire détient les clés (ou délivre des certificats à courte durée) et s’authentifie au nom du modèle. Compromettez le contexte du modèle et vous obtenez la capacité de demander des actions via l’intermédiaire — pas celle de vous usurper depuis n’importe où.
- La portée est explicite. Le modèle n’atteint que les hôtes que vous avez listés. Un nouvel hôte est une nouvelle décision, pas un comportement par défaut.
- Les commandes sont encadrées. Par hôte, décidez si le modèle obtient un shell complet, une liste de commandes autorisées, ou rien — pour que « redémarrer nginx » soit permis sur la couche web et « quoi que ce soit » jamais.
- Un humain peut regarder — en direct. Pas seulement lors du post-mortem, et avec un enregistrement qui distingue « c’est le modèle qui a fait ça » de « c’est moi ».
- La révocation est un interrupteur, pas une rotation. Comme rien n’a jamais été partagé, couper l’accès ne coûte rien.
Rien de tout cela n’est exotique — c’est à peu près ainsi que le SSH par certificats fonctionne déjà dans les équipes infra sérieuses. Le hic a toujours été que tout câbler soi-même est un projet à part entière, alors on saute vers l’une des mauvaises options ci-dessus.
Le brancher à un modèle local
MCP — le Model Context Protocol — est la manière propre de s’y prendre, et il est indépendant du client : n’importe quel client compatible MCP peut le piloter, peu importe donc que votre modèle soit Claude, un modèle à poids ouverts derrière Ollama, ou quelque chose que vous hébergez vous-même.
- Faites tourner votre modèle local à travers un client compatible MCP (un agent de code ou un client de chat qui parle MCP).
- Pointez-le vers un serveur MCP qui sert de façade au SSH — un serveur qui s’authentifie à la place du modèle au lieu de lui remettre une clé.
- N’activez que les hôtes voulus, et définissez la politique de commandes de chaque hôte (complet / liste de commandes autorisées / bloqué).
- Gardez la session en vue et laissez-la écrire dans un journal d’audit, pour que chaque commande du modèle soit attribuable et rejouable.
Le modèle reçoit des outils — ouvrir une session, lancer une commande, lire ou écrire un fichier — et c’est le gardien qui authentifie. Votre clé n’entre jamais dans l’environnement du modèle, ni sur votre machine ni ailleurs. Et comme c’est le gardien qui détient l’identifiant, pas le modèle, le même branchement se reporte dès l’instant où vous passez plutôt à un agent hébergé — Claude Code en SSH et OpenAI Codex en SSH exposent ce schéma identique avec un modèle cloud à l’autre bout.
Comment Termalin s’y prend
Termalin est un client SSH doté d’un serveur MCP intégré, si bien que ce schéma est l’option par défaut plutôt qu’un projet.
- Sur votre machine, déclarez le serveur local fourni auprès de votre agent (
claude mcp add termalin -- <path>/termalin-mcp, ou l’équivalent pour n’importe quel client MCP). Le modèle n’atteint que les hôtes que vous activez — l’accès de l’agent est désactivé par défaut — et l’authentification passe par le gardien des clés de Termalin : vous déverrouillez vos clés une fois, Termalin signe au nom du modèle, et aucun fichier de clé n’est jamais là pour que le modèle le lise. - Par hôte, vous définissez la politique — accès complet, une liste de commandes autorisées, ou bloqué — pour qu’un modèle local qui se laisse tromper ne puisse pas exécuter sur cette machine une chose que vous n’avez jamais autorisée.
- Vous le voyez se produire. Les sessions d’agent s’exécutent comme des onglets de terminal en direct ; la grille de surveillance les reflète, et les vignettes qu’un modèle pilote s’illuminent. Chaque commande est marquée dans l’enregistrement de session — la sortie seulement, jamais vos frappes — et écrite dans un journal d’audit, avec l’appareil et l’IP d’où elle provient.
- Aucune app en cours d’exécution ? Pointez le modèle vers l’endpoint MCP hébergé de Termalin avec une clé API limitée à des serveurs précis, dotée d’une expiration, soumise à une politique de commandes, et qui authentifie chaque exécution avec un certificat à courte durée — ainsi, même une clé divulguée ne peut ni atteindre un hôte non listé ni s’exécuter en dehors de ses commandes autorisées.
Dans les deux cas, la propriété que vous recherchiez tient : votre modèle local peut exploiter vos serveurs, et il n’a jamais vu de clé.
Commencez par un hôte sans intérêt
Ne commencez pas par la production. Inscrivez une machine sans enjeu — un serveur de préproduction, un VPS jouet — réglez-la sur une liste de commandes autorisées, et confiez au modèle une vraie corvée : suivre le journal jusqu’à ce que l’erreur apparaisse, corriger la configuration, redémarrer le service. Gardez la grille ouverte pendant qu’il travaille. Ce que vous apprenez dans la première heure — comment il se comporte, où il hésite, ce qu’il fait de l’ambiguïté — vous dit si le deuxième hôte sera inscrit, et avec quelle marge.
C’est le bénéfice discret du schéma du gardien : vous vous étendez un hôte à la fois, parce qu’aucune étape que vous franchissez n’est irréversible — où que le modèle s’exécute.
Termalin est un client SSH gratuit et multiplateforme doté d’un serveur MCP intégré, d’un gardien des clés et d’une politique par hôte — téléchargez-le, ou lisez comment il gère les clés en toute sécurité.