Безопасный способ дать локальной модели доступ по SSH — никогда не давать ей ключ. Пусть она вызывает инструмент — MCP-сервер в роли хранителя, — который держит ключи (или выпускает краткосрочные сертификаты), дотягивается только до перечисленных вами хостов, применяет для каждого хоста список разрешённых команд и записывает каждую из них. Тогда перехваченный промпт может лишь запросить действие через хранителя; он не может присвоить вашу личность или дотянуться до хоста, которого вы не внесли в список. Первое, в чём ошибаются: запуск модели на своём собственном железе защищает ваши промпты, а не ваши серверы — «это локально, значит, безопасно» неверно и никак не влияет на то, что произойдёт, когда у этой модели окажется оболочка.
Локальные модели сейчас на подъёме. Ollama на рабочей станции, модель с открытыми весами за вашим собственным эндпоинтом, самостоятельно размещённый кодовый агент — вы запускаете их по хорошим причинам: приватность, стоимость, отсутствие лимитов по запросам, работает и в самолёте. А как только модель уже обрабатывает ваши промпты, очевидный следующий шаг — направить её на вашу инфраструктуру: пусть почитает хвост лога, перезапустит службу, выполнит миграцию — и вот тут-то и встаёт настоящий вопрос.
Почему «локально» не делает доступ к серверу безопасным
Две вещи остаются ровно настолько же опасными, работает ли модель в дата-центре или на машине у вас под столом.
Ключ по-прежнему работает на предъявителя. Положите id_ed25519 в окружение агента, чтобы он сам мог запускать ssh, — и кто (или что) ни держал бы эти байты, он — это вы, на каждом хосте, который доверяет ключу. Запуск модели локально этого не меняет; он лишь переносит копию на машину, которой вы владеете. И вернуть ключ обратно вы всё так же не можете: стоит ему пройти через контекст модели — переменная окружения, примонтированный файл, вызов инструмента, транскрипт — и вы больше не докажете, что он не оказался там, где не должен. Единственный честный ответ на вопрос «видела ли модель мой ключ?» — сменить его на каждом хосте.
Локальную модель всё так же можно сбить с толку. Инъекции в промпт не нужна облачная модель. Отравленная строка лога, вредоносное имя файла, напичканный ловушками результат инструмента, не в меру ретивый план — локальная модель отрабатывает их все так же охотно, как и облачная. Если на то пошло, риск даже выше, потому что локальным установкам доверяют больше, собирают их с меньшим числом ограничителей и дают им более широкий доступ — именно потому, что «это на моей машине». Это неверный инстинкт: суждения модели не становятся лучше оттого, что веса лежат локально.
Так что цель та же, что и для любого агента: позволить модели делать работу, ни разу не держа учётные данные, и сделать каждое действие ограниченным по охвату, видимым и обратимым.
Три способа сделать это плохо
Вставить ключ как есть. Прямой путь — и худший: ни ограничения охвата, ни срока действия, плюс та самая необратимость выше. Ключ, который разворачивает на staging, обычно дотягивается и до продакшен-базы в двух прыжках.
Выпустить долгоживущий токен. Токен для деплоя или «автоматизационные» учётные данные, которые не истекают никогда. Выглядит опрятнее ключа, но это та же проблема предъявителя, только с лишними шагами. Если для отзыва нужно помнить, что токен вообще существует, он переживёт эксперимент, ради которого был создан.
Дать ей собственный root-вход и забыть. Правильный инстинкт — отдельная личность — исполненный неправильно. Добавьте публичный ключ в authorized_keys для бот-пользователя — и вы построили доступ без всякого следа аудита: ничто не отличает команды модели от чьих-либо ещё, а когда что-то сломается в два часа ночи, вы будете восстанавливать её сессию по истории bash и по наитию.
Общая нить: модель держит постоянные учётные данные, а наблюдаемость — дело десятое.
Работающий паттерн: хранитель, а не копия
Переверните. Модель вообще никогда не должна держать учётные данные.
- Модель просит; подписывает хранитель. Посредник держит ключи (или выпускает краткосрочные сертификаты) и аутентифицируется от имени модели. Скомпрометируйте контекст модели — и вы получите возможность запросить действия через посредника, а не возможность выдать себя за вас откуда угодно.
- Охват задан явно. Модель дотягивается только до перечисленных вами хостов. Новый хост — это новое решение, а не значение по умолчанию.
- Команды под контролем. Для каждого хоста решайте, что получает модель: полную оболочку, список разрешённых команд или ничего — так что «перезапусти nginx» разрешено на веб-уровне, а «что угодно вообще» — никогда.
- Человек может наблюдать — в реальном времени. Не только при разборе постфактум, причём в записи «это сделала модель» отличается от «это сделал я».
- Отзыв — это переключатель, а не смена ключей. Поскольку ничем ни разу не делились, выключить доступ ничего не стоит.
Ничего экзотического тут нет — примерно так уже работает SSH на сертификатах в серьёзных инфраструктурных командах. Загвоздка всегда была в том, что собрать это самому — целый проект, поэтому люди перескакивают к одному из плохих вариантов выше.
Как подключить это к локальной модели
MCP — Model Context Protocol — это аккуратный способ сделать это, и он не привязан к клиенту: управлять им может любой клиент с поддержкой MCP, так что неважно, Claude ли ваша модель, модель с открытыми весами за Ollama или что-то, что вы размещаете сами.
- Запустите локальную модель через клиент с поддержкой MCP (кодовый агент или чат-клиент, который умеет MCP).
- Направьте её на MCP-сервер, который стоит перед SSH — такой, что аутентифицируется за модель, а не выдаёт ей ключ.
- Включите только нужные хосты и задайте для каждого политику команд (полный доступ / список разрешённых / блокировка).
- Держите сессию на виду и пусть она пишется в журнал аудита, чтобы каждую выполненную моделью команду можно было отнести к ней и воспроизвести.
Модель получает инструменты — открыть сессию, выполнить команду, прочитать или записать файл, — а аутентификацией занимается хранитель. Ваш ключ никогда не попадает в окружение модели — ни на вашей машине, ни где-либо ещё. А поскольку учётные данные держит хранитель, а не модель, та же связка переносится в тот момент, когда вы вместо этого потянетесь за облачным агентом: Claude Code по SSH и OpenAI Codex по SSH используют ровно этот же паттерн с облачной моделью на другом конце.
Как это делает Termalin
Termalin — это SSH-клиент со встроенным MCP-сервером, так что этот паттерн здесь — поведение по умолчанию, а не отдельный проект.
- На вашей машине зарегистрируйте встроенный локальный сервер у своего агента (
claude mcp add termalin -- <path>/termalin-mcpили аналог для любого MCP-клиента). Модель дотягивается только до включённых вами хостов — доступ агента выключен по умолчанию, — а аутентификация идёт через хранителя ключей Termalin: вы один раз разблокируете ключи, Termalin подписывает от имени модели, и никакого файла с ключом, который модель могла бы прочитать, там нет. - Для каждого хоста вы задаёте политику — полный доступ, список разрешённых команд или блокировка, — так что сбитая с толку локальная модель не выполнит на этой машине то, чего вы никогда не разрешали.
- Вы видите это своими глазами. Сессии агента идут как живые вкладки терминала; сетка наблюдения отражает их, а плитки, которыми управляет модель, подсвечиваются. Каждая команда отмечена в записи сессий — только вывод, никогда ваши нажатия клавиш — и записана в журнал аудита вместе с устройством и IP, откуда она пришла.
- Приложение не запущено? Направьте модель на облачный эндпоинт MCP у Termalin с API-ключом, который ограничен конкретными серверами, имеет срок действия, подчиняется политике команд и подтверждает каждый запуск краткосрочным сертификатом — так что даже утёкший ключ не дотянется до хоста вне списка и не выполнит ничего за рамками разрешённых команд.
Так или иначе, нужное вам свойство сохраняется: ваша локальная модель может управлять серверами, ни разу не увидев ключа.
Начните с одного скучного хоста
Не начинайте с продакшена. Добавьте машину с низкими ставками — staging-сервер, игрушечный VPS, — переведите её на список разрешённых и дайте модели настоящее дело: читать хвост лога, пока не покажется ошибка, починить конфиг, перезапустить службу. Держите сетку открытой, пока она работает. То, что вы узнаете за первый час — как она себя ведёт, где медлит, что делает с неоднозначностью, — и подскажет, подключать ли второй хост и с какой длиной поводка.
В этом и есть негромкая выгода модели с хранителем: вы расширяетесь по одному хосту за раз, потому что ни один ваш шаг не из тех, что нельзя отыграть назад, — где бы модель ни работала.
Termalin — это бесплатный кроссплатформенный SSH-клиент со встроенным MCP-сервером, хранителем ключей и политикой агента для каждого хоста — скачайте его или почитайте, как он безопасно обращается с ключами.