RE:NODE

Доступ ИИ к серверу без утечки секретов

Автор Команда RE:NODE
15 мин чтения


Дать ИИ-ассистенту полезный доступ к серверу и не отдать ему пароли можно, но только если доступ изначально рассчитан на это. Root-ключ SSH или полный ключ API панели, вставленный в чат, отдаёт всё ассистенту, истории чата и каждому, кто эту историю прочитает. Работает другое: узкий доступ. Ссылка или подключение, которое видит устройство сервера, но не его секреты; которое умеет только то, что вы разрешили; которое само заканчивается, когда вы перестаёте им пользоваться; которое можно отключить одним щелчком и которое оставляет запись о своих действиях. Для единственной задачи, где секрет действительно нужен, - положить пароль в файл .env - правильный инструмент записывает значение и никогда не читает файл обратно. Вот весь замысел, а остальная часть статьи разбирает каждую деталь и её пределы.

AI-функции нашей панели построены ровно на этих правилах, поэтому, когда в статье описано, как тот или иной шаг делает RE:NODE, это просто конкретный пример принципа. Сами принципы работают у любого хостера.

Что ассистенту на самом деле нужно от сервера#

Большая часть того, что нужно ассистенту для помощи, не секретна. Чтобы починить падающее приложение на Node, ему нужны среда выполнения и версия, команда запуска, порт, который сервер должен занять, последние несколько сотен строк вывода консоли и дерево каталогов. Чтобы подключить базу данных, нужны хост, порт, имя базы и имя переменной окружения, которую читает ваш код. Чтобы добавить домен, нужен адрес, на который должна указывать A-запись.

Пароль для этого не нужен. Он нужен ровно один раз, в момент, когда попадает в конфигурационный файл, а после этого его не должен читать никто, ни человек, ни модель. На этом различии держится остальная статья:

  • Контекст - это то, чем является сервер: среда выполнения, порты, структура файлов, логи, имена переменных. Его безопасно показывать, и именно он делает ассистента полезным.
  • Секреты - значения, дающие доступ: пароли баз данных, API-токены, секреты OAuth-клиентов, ключи подписи, учётные данные SMTP. Для чтения не нужны никогда, для записи нужны один раз.
  • Права - то, что ассистент может менять: файлы, консоль, запуск и остановка. Полезная вещь, но включать её нужно по желанию и ненадолго.

Если инструмент не отличает эти три вещи, ему приходится отдать ассистенту все или ни одной. Поэтому ответ «просто дайте ему SSH» неверен, даже если вы полностью доверяете модели. Более широкий довод - агент пишет, человек проверяет - мы разобрали в статье ИИ-агенты для работы с серверами.

Где секреты утекают на самом деле#

Стоит назвать путь утечки конкретно, потому что почти всегда он не связан с тем, что модель ведёт себя плохо.

  1. Переписка. Всё, что прочитал ассистент, становится частью разговора. Разговоры хранит провайдер, они синхронизируются между устройствами, их отправляют коллегам ссылками, вставляют в тикеты и скриншотят для форумов. Пароль от базы, один раз показанный в результате работы инструмента, теперь лежит во всех этих местах.
  2. Контекстные файлы. Агенты вроде Claude Code и Cursor записывают заметки и сводки в репозиторий: CLAUDE.md, AGENTS.md, файлы планов. Если секрет был в контексте, он может попасть в закоммиченный файл, а оттуда в каждый клон.
  3. Круговой обмен. Ассистент, которого просят поменять одну строку в .env, часто читает файл целиком, правит его в памяти и записывает всё обратно. Если при чтении значения были скрыты, при записи все настоящие значения заменятся заглушками, и приложение сломается. Если скрыты не были, каждое значение прошло через переписку.
  4. Долгоживущие учётные данные. Ключ, вставленный в чат в марте, работает и в октябре, если только кто-то не вспомнил его сменить. Никто не вспоминает.

Самое маловероятное из всего этого - что модель сама решит украсть ваш пароль. Секреты уходят обычными путями: через логи, историю и файлы. Общую гигиену разбирает наша статья про переменные окружения и секреты, а разделы ниже посвящены тому, как закрыть эти четыре пути, когда читатель - ИИ.

Что панель скрывает#

В RE:NODE всё, что ассистент получает через ссылку доступа или наш MCP-эндпоинт, сначала проходит через редактор секретов. Он работает в три слоя, потому что каждый по отдельности что-то пропускает, а другие это ловят.

СлойЧто он ловит
По имени переменнойВсё, что называется как TOKEN, PASSWORD, KEY, SECRET, AUTH, SALT
По формеКлючи GitHub, Slack, OpenAI и AWS, JWT, пароли в URL, длинные случайные строки
По значениюНастоящие секреты сервера и пароли баз данных, вычищенные из готового вывода

Слой имён справляется с очевидным случаем: DB_PASSWORD=... в переменной запуска показывает имя, а значение скрывает. Слой формы ловит токен, который всплыл в неожиданном месте: в трассировке стека, где напечатана строка подключения с user:password@host, или в токене GitHub, который небрежный установочный скрипт вывел в консоль. Слой значений - страховка: панель знает, какие у этого сервера настоящие секреты, поэтому ищет в готовом выводе именно эти строки и убирает их везде, под любым именем.

Пароли баз данных в вывод не попадают вообще. Ассистент получает хост, порт, имя базы и пользователя - этого достаточно, чтобы написать код подключения и имя переменной, из которой его читать, а пароль вы подставляете сами или через инструмент только для записи, описанный ниже.

Мы говорим об этом прямо, потому что так же о себе говорит код. Три слоя делают утечку намного менее вероятной, но не невозможной, а поставщик, который утверждает обратное, не проверял это на реальном выводе консоли.

В доступе на чтение есть и намеренный пробел: ссылка по умолчанию показывает списки каталогов, но не содержимое файлов. Ассистент видит, что config/database.php существует, но прочитать его не может, пока вы не дадите ссылку с правом действовать, и даже тогда чтение идёт через тот же редактор секретов.

Запись секрета без чтения: set_env#

Проблему кругового обмена, описанную выше, решает чистый приём: слияние выполняется на стороне сервера, а файл ассистенту не отправляется вообще. Для этого в наших MCP-инструментах есть set_env. Он принимает путь к .env, набор ключей, которые нужно задать, и список ключей, которые нужно удалить. Панель сама читает файл, заменяет или добавляет указанные строки, оставляет все остальные байты на месте, записывает файл обратно и возвращает только имена тронутых ключей.

Вызов со стороны ассистента выглядит так:

set_env arguments
{  "server": "1a2b3c4d",  "path": "/.env",  "set": {    "DATABASE_URL": "postgres://app:the-real-password@db-host:5432/app",    "SESSION_SECRET": "a-long-random-string"  },  "unset": ["OLD_API_KEY"]}

А в ответ приходит не больше вот этого:

code
/.env - updated: DATABASE_URL; added: SESSION_SECRET; removed: OLD_API_KEY.Values are not echoed. Restart the server for the app to read them.

Детали, которые делают инструмент безопасным, а не просто удобным:

  • Он устроен только на запись. Нет режима, в котором он возвращает значение, поэтому нечего неправильно настроить.
  • Он правит только файлы с именем `.env` или `.env.something`. Всё остальное идёт через обычные файловые инструменты.
  • Остальные строки не затрагиваются. Комментарии, порядок, пустые строки и окончания строк остаются как были. Если ключ встречается дважды, заменяется каждое вхождение, потому что то, какое из них учитывает ваш загрузчик, должно содержать новое значение.
  • Значения - однострочные. Значение с переводом строки отклоняется, а не молча разбивает файл.
  • Он есть только в ссылках с правом действовать. Ссылка на чтение не может записать ничего, включая .env.

Есть одна честная оговорка. Если вы напечатали пароль в чате, чтобы ассистент передал его в set_env, пароль оказался в переписке, потому что вы сами его туда положили. set_env не даёт утечь остальным секретам файла и не даёт обратной записи их уничтожить, но не может вернуть то, что вы уже напечатали. Для особо ценных учётных данных лучше другой порядок: пусть ассистент задаст все несекретные ключи, а единственный пароль вы добавите сами в файловом менеджере, либо значение будет сгенерировано на сервере и никому не показано.

.env
# Set by the assistant through set_env - safe to discussNODE_ENV=productionPORT=25601DATABASE_HOST=db-hostDATABASE_NAME=app# Added by hand in the file manager - never in a chatDATABASE_PASSWORD=

Порт и хост выше - заглушки; используйте значения, которые панель показывает для вашего сервера.

Области доступа: что ссылка может и чего не может#

Доступ должен быть минимальным из достаточных для задачи. В RE:NODE есть два вида ссылок доступа, они создаются кнопкой Connect AI в панели над консолью, а вид зависит от того, для чего вы назначили ассистента.

СсылкаЧто она можетПо умолчанию
ReadКонтекст сервера, подсказки для задач, конец консоли, списки каталоговДа
Can actВсё перечисленное, а также запуск, остановка, перезапуск, принудительное завершение, ввод в консоль и правка файловТолько для "Manage this server"

Варианты General, Set up a new project, Fix my repository, Connect a database и Add a domain создают ссылку на чтение. Ссылку с правом действовать создаёт только "Manage this server". Вариант "Server won't start" ссылку не создаёт вовсе: он копирует готовую подсказку с концом консоли, а этого ассистенту часто хватает, чтобы разобраться со сбоем.

Некоторые вещи недоступны ни через одну ссылку, какого бы вида она ни была:

  • удаление, переименование или переустановка сервера
  • изменение команды запуска и переменных
  • базы данных и их пароли
  • резервные копии и расписания
  • пользователи и субпользователи
  • данные SFTP и ключи API

Запись через ссылку - только текст, не более 1 МБ на файл и никогда внутри .git/. Каждая ссылка ограничена 60 запросами в минуту, 20 действиями в минуту и 6 действиями с питанием в минуту. Для ассистента, делающего реальную работу, этого с запасом, а для того, кто застрял в цикле и без конца перезапускает ваш сервер, это жёсткий тормоз.

Если вы предпочитаете подключить ассистента к аккаунту, а не вставлять ссылку, у панели есть размещённый MCP-эндпоинт со входом по OAuth 2.1. Вы добавляете URL и один раз подтверждаете доступ на странице согласия:

bash
$ claude mcp add --transport http renode https://panel.renode.space/api/client/mcp

На странице согласия вы выбираете, какие серверы открыть (все свои или выборочно) и уровень: Files (чтение и правка файлов, консоль) или Manage (то же плюс запуск, остановка и перезапуск). Базы данных, резервные копии, расписания, пользователи, запуск и настройки не предлагаются никогда. Токены доступа живут час; токены обновления живут 30 дней и продлеваются при использовании. Повторно использованный токен обновления отзывает весь грант, поэтому украденный токен, которым воспользовались после настоящего клиента, сам себя отключает. Мы разрабатывали и проверяли это с Claude Code и пользовательскими коннекторами Claude.ai; другие клиенты с поддержкой удалённого MCP должны работать, но отдельно мы их не проверяли.

Тот же принцип минимальных прав применим и к людям, а модель панели для этого описана в статье про субпользователей и минимальные права.

Срок действия и ротация#

Обычно беда с токенами доступа не в том, что их крадут в первый день, а в том, что они всё ещё действуют на двухсотый. Поэтому ссылки доступа не спрашивают срок и их не нужно удалять. Они заканчиваются сами:

СсылкаСрок простояПредельный срок
Read7 дней после последнего использования90 дней с создания
Can act24 часа после последнего использования30 дней с создания

Каждое использование сдвигает срок простоя вперёд, поэтому ссылка, которой ассистент активно пользуется, продолжает работать, а забытая умирает в течение недели, или в течение суток, если она могла что-то менять. Предельный срок означает, что даже ссылка, которой пользуются постоянно, в итоге закончится.

Ротация устроена так же. Новая ссылка для того же сервера и той же цели заменяет предыдущую; искать и удалять старую не нужно. На сервере может быть не более пяти активных ссылок, из них не более двух с правом действовать, а при превышении самая старая закрывается.

Сам URL показывается один раз. Панель хранит только его хеш, поэтому копия базы данных не содержит рабочей ссылки. Если вы её потеряли, создайте новую - старая отзывается в том же шаге.

Ещё два правила закрывают пробелы, которые обычно обнаруживаются позже:

  • Ссылка не надёжнее доступа её создателя. Если вы были субпользователем и ваш доступ убрали, все созданные вами ссылки перестают работать сразу, при каждом обращении.
  • Любой отказ - это простой 404. Срок истёк, ссылка отозвана, создатель потерял доступ, сервер приостановлен - ответ один и тот же. Тот, кто пробует ссылку, ничего не узнаёт о причине и о том, работала ли она вообще.
иначе 404действие в журналевыводсекреты скрытыАссистентClaude, ChatGPTСсылка доступахеш проверенДоступ создателяпроверка каждый разПрава и лимитычтение или действиеВаш серверРедактор секретовимя, форма, значение
Каждый запрос проходит одни и те же проверки

Отзыв доступа#

Срок действия решает вопрос с забытыми ссылками. Отзыв нужен для тех, которые должны исчезнуть сейчас: вы вставили ссылку не в тот чат, у коллеги украли ноутбук или вы просто закончили работу.

Всё находится в одном месте: Account, затем Connected AI. Там перечислены все OAuth-подключения с кнопкой Disconnect и все активные ссылки доступа, созданные вашим аккаунтом, на любых серверах, с кнопкой Revoke. Для каждой ссылки показано, сколько действий она совершила и когда использовалась в последний раз. Это самый быстрый способ заметить ссылку, к которой всё ещё обращаются, хотя вы считали работу законченной.

Отозванная ссылка отвечает 404 при следующем же запросе. Отключённое OAuth-подключение теряет доступ так же. Менять пароль для этого не нужно, но если ассистент мог действовать, а вы не знаете, что он сделал, прочитайте следующий раздел, прежде чем решить, что на этом всё.

Проверка того, что сделал ассистент#

После любого инцидента встаёт вопрос «что изменилось?», и ответ должен прийти из записи, которую ассистент не писал. В RE:NODE каждое действие, выполненное через ссылку или OAuth-подключение, порождает то же событие активности, что и соответствующая кнопка в панели. Файл, отредактированный через ассистента, - это строка server:file.write; перезапуск - событие питания; вызов set_env - запись файла, в которой фиксируются файл и имена ключей, но никогда не значения.

Эти строки записываются на аккаунт, создавший ссылку или одобривший подключение, потому что именно его полномочиями пользовался ассистент. Дополнительно каждая строка хранит, через какую дверь пришло действие - ссылку доступа, OAuth-грант или ключ API, - чтобы поддержка могла их различать. Создание и отзыв ссылок тоже события: server:ai.link.create и server:ai.link.revoke. Подключение и отключение OAuth-клиента записываются на аккаунт.

Как этим пользоваться на практике:

  1. До того как выдать ссылку с правом действовать, сделайте резервную копию на вкладке Backups. Журнал активности покажет, что изменилось, а резервная копия позволит это откатить.
  2. Во время держите консоль открытой, чтобы видеть перезапуски и ошибки по мере появления.
  3. После сравните число действий на странице Connected AI с ожидаемым. Ссылка, которая должна была сделать три правки, а показывает сорок действий, заслуживает чтения журнала.
  4. Если что-то не так, сначала отзовите ссылку, затем прочитайте журнал активности за период, пока она действовала, и только потом восстанавливайте или исправляйте.

Журнал ничего не останавливает, он говорит, что нужно исправить. Поэтому он стоит рядом с областями доступа, лимитами и сроком действия, а не вместо них.

Чек-лист перед тем, как вставить ссылку#

Вся статья списком, который можно пройти меньше чем за минуту:

  1. Нужно ли ассистенту что-то менять? Если нет, используйте ссылку на чтение. Большинству диагностики права не нужны.
  2. Если ему нужно действовать, сначала сделайте резервную копию.
  3. Не пишите пароли в чат. Пусть ассистент задаёт несекретные ключи через set_env, а секрет добавьте сами.
  4. Никогда не вставляйте в разговор пароль SFTP, ключ API панели или пароль базы данных. Если вставили, смените его.
  5. Вставляйте ссылку только в тот разговор, которому она нужна. Общий разговор делится и ссылкой.
  6. Когда задача выполнена, отзовите ссылку на странице Connected AI.
  7. Взгляните на журнал активности и число действий. Если что-то из этого удивляет, разберитесь, прежде чем идти дальше.

Если вы деплоите из GitHub, есть ещё одно место, где прячутся секреты: репозиторий. Закоммиченный .env предварительная проверка на вкладке GitHub называет по имени, не открывая его. Как значения окружения должны попадать на сервер вместо этого, описано в нашем руководстве по деплою приложения на Node из GitHub.

FAQ#

Может ли ИИ увидеть пароль от моей базы данных?

Через ссылки панели или MCP-эндпоинт - нет. Пароли баз данных скрыты из любого вывода, и ни одна ссылка не открывает настройки базы. Ассистент получает хост, порт, имя базы и пользователя, чего хватает для написания кода. Если вы сами напечатаете пароль в чат, он окажется в переписке, как и всё остальное, что вы печатаете.

Достаточно ли скрытия секретов, чтобы безопасно делиться любым сервером?

Нет. Оно делает утечки намного менее вероятными, но секрет в неожиданном формате может проскочить. Сочетайте его со ссылкой только на чтение, где это возможно, отзывайте ссылки, закончив работу, и меняйте любые учётные данные, которые заметили в переписке.

Какие ассистенты работают со ссылкой доступа?

Ссылка доступа - это URL, поэтому подойдёт любой ассистент, умеющий его открыть, включая Claude и ChatGPT. Размещённый MCP-эндпоинт и вход по OAuth разработаны и проверены с Claude Code и пользовательскими коннекторами Claude.ai. Cursor подхватывает правила сервера из контекстных файлов, которые интеграция с GitHub может добавить в ваш репозиторий.

Что будет, если моя ссылка попадёт к кому-то другому?

Он получит ровно то, что разрешает ссылка, в пределах её лимитов, пока она не истечёт или вы её не отзовёте. Ссылка на чтение показывает контекст и логи со скрытыми секретами; ссылка с правом действовать может ещё и править файлы и перезапускать сервер, поэтому такие ссылки умирают после 24 часов простоя. Отзовите её на странице Connected AI, и со следующего запроса она отвечает 404.

Может ли ссылка удалить мой сервер или тронуть резервные копии?

Нет. Удаление, переустановка, переименование, резервные копии, расписания, пользователи, настройки запуска и базы данных находятся за пределами любой ссылки и любого уровня OAuth, поэтому всегда требуют вашего присутствия в панели.

Нужно ли удалять старые ссылки?

Нет. Ссылки на чтение истекают через 7 дней после последнего использования, а ссылки с правом действовать - через 24 часа, с предельными сроками 90 и 30 дней. Новая ссылка для той же цели заменяет старую. Отзывать ссылку по завершении задачи всё равно правильная привычка.

Это было полезно?