Политика инструментов AI-агентов: безопасность, MCP-серверы и секреты в self-hosted среде

Политика инструментов AI-агентов: безопасность, MCP-серверы и секреты в self-hosted среде

Когда в системе три AI-агента (Hermes, Codex, Claude Code), каждый со своим набором инструментов, вопрос безопасности перестаёт быть академическим. Он становится ежедневным: какой инструмент кому доступен, кто может читать логи, кто имеет право перезапускать сервисы, и где вообще лежат секреты, чтобы ни один агент случайно не вывалил API-ключ в ответ пользователю.

За несколько месяцев эксплуатации multi-agent системы на своём сервере я выработал набор правил, которые держат стек безопасным, не превращая его в бесполезную песочницу. Ниже — практическая политика инструментов: от секретов до MCP-серверов и бриджа между агентами.

Почему «просто не храни секреты в репозитории» недостаточно

Классический совет — «используй .env и не коммить секреты». Для AI-агентов этого мало. Проблема в том, что агент может прочитать секрет из файла, переменной окружения или лога и передать его дальше — в ответе пользователю, в сгенерированном коде, в заметке Obsidian или в отладочном выводе.

В моём vault действует жёсткое правило: никаких секретов в Markdown-заметках. Ни API-ключей, ни токенов Telegram, ни OAuth-кодов, ни SSH-приватных ключей, ни кук, ни сессионных файлов. Vault синхронизируется между агентами, читается инструментами поиска, индексируется — если туда попадёт секрет, его увидят все.

Что делать вместо этого:

  • Секреты живут в отдельных файлах за пределами vault. В моём случае это /opt/data/.secrets/ с ограниченными правами (0600) и владельцем, отличным от UID контейнеров агентов.
  • Переменные окружения передаются через Docker Compose. Каждый контейнер получает только те переменные, которые нужны именно ему. Hermes не видит GitHub-токен Codex, и наоборот.
  • Проверка vault на секреты — часть регулярного аудита. Команда bronevik-vault-status среди прочего проверяет, что в vault нет путей, похожих на секреты. Если находит — алерт.

Это базовый слой. Без него всё остальное не имеет смысла.

MCP-серверы: принцип наименьших привилегий

Model Context Protocol позволяет агенту взаимодействовать с внешними системами через инструменты. Но каждый MCP-сервер — это поверхность атаки. Подключить «широкий» сервер, который отдаёт агенту всю файловую систему, git с правами на reset и force-push, или shell с bash -c — значит свести безопасность к надежде на то, что модель не ошибётся.

Правила, которые я применяю:

1. tools.include вместо широкого доступа

В конфигурации Hermes каждый MCP-сервер настраивается не через «включить все инструменты», а через явный allowlist:

mcp_servers:
  bronevik-knowledge:
    command: "..."
    tools:
      include:
        - fs_read_text_file
        - fs_search_files
        - fs_list_directory
        - fs_directory_tree

Агент видит ровно те инструменты, которые перечислены — не больше. Если нужен новый инструмент, он добавляется явно, с осознанным решением.

2. Разделение прав на чтение и запись

Obsidian vault и рабочие директории агентов — это разные зоны доверия:

  • Vault (/workspace/bronevik-knowledge): read-write для добавления знаний, но без move_file и без выхода за пределы vault.
  • Workspace (/workspace/agent-workbench): read-write для временных файлов и сборки, но без доступа к секретам.
  • Хост (через maintenance bridge): строго ограниченный набор именованных действий.

Это не три отдельных MCP-сервера, а три разных политики доступа в рамках одной архитектуры.

3. По одному внешнему сервису за раз

Подключение Google Drive, базы данных, внешнего SaaS — каждое новое подключение добавляется отдельным MCP-сервером, с собственным токеном и только теми инструментами, которые реально нужны. Никаких «подключу всё сразу, потом разберусь». После каждого изменения — перезапуск Hermes, hermes mcp test, проверка списка инструментов и триггер бэкапа.

Agent Bridge: безопасная делегация между агентами

В моём стеке Hermes оркестрирует задачи, а Codex и Claude Code выполняют инженерную работу — правят код, чинят конфиги, анализируют логи. Коммуникация между ними идёт не через прямой shell, а через agent bridge — промежуточный слой с жёстко ограниченным набором действий.

Почему не прямой claude mcp serve или codex mcp-server? Потому что они отдают shell и запись файлов без контекстных ограничений. Агент может случайно или по неверной инструкции сделать то, что не должен.

Agent bridge работает в двух режимах:

  • Audit bridge — read-only инструменты для инспекции: просмотр статуса, чтение логов, проверка бэкапов. Агент видит, но не трогает.
  • Maintenance bridge — scoped-действия через allowlist: перезапуск конкретных сервисов, запуск бэкапа, перезагрузка Docker-контейнера. Не systemctl restart *, а «можно рестартить hermes-agent.service и ttyd-codex-fast.service, и всё».

Ключевое правило: контекстные пути — только внутри /workspace. Никаких /etc, /root, /home или путей с секретами. Если агенту нужно прочитать конфиг сервиса, этот конфиг должен быть доступен в разрешённом пути или скопирован туда явно.

Web Shells: операторский доступ, не инструмент агента

Отдельная тема — ttyd web-терминалы для Codex и Claude Code. Это операторские поверхности для меня, человека, а не инструменты для Hermes.

Правила:

  • Работают только ttyd-codex-fast.service и ttyd-claude-fast.service.
  • Оба слушают исключительно 127.0.0.1 — никаких открытых портов в сеть.
  • Публичный доступ идёт через Cloudflare Tunnel + Cloudflare Access с аутентификацией.
  • Hermes не имеет автоматического доступа к этим терминалам. Если Hermes нужно что-то передать Codex, это идёт через agent bridge, а не через программное управление web-шеллом.

Типичная ошибка — дать оркестратору возможность открывать shell в контейнере агента и печатать команды. Это стирает границу между оркестрацией и исполнением и создаёт риск неконтролируемой эскалации.

Мониторинг здоровья: проверка политики на практике

Политика инструментов бесполезна, если её нельзя проверить автоматически. У меня для этого есть bronevik-vault-status — скрипт, который проверяет:

  • Чистоту vault: git_dirty_count=0 — все изменения закоммичены.
  • Целостность структуры: все обязательные заметки на месте, .obsidian конфигурация присутствует.
  • Отсутствие битых wikilink’ов — если агент сослался на несуществующую заметку, это видно сразу.
  • Отсутствие секретоподобных путей — если кто-то случайно сохранил ключ или токен в Markdown.
  • Все файлы имеют frontmatter (кроме README), чтобы навигация и индексация работали предсказуемо.

Если overall=ok — система в порядке. Если нет — сначала чиним, потом работаем дальше.

Кроме vault, стоит проверять и конфигурацию инструментов. После любых изменений в MCP-серверах или agent bridge: рестарт Hermes → hermes mcp test → проверка hermes tools list — убедиться, что список инструментов соответствует политике, и никакие лишние не просочились.

Контроль версий и воспроизводимость

Безопасность инструментов — это ещё и воспроизводимость. Если агент обновился, список инструментов изменился, появилось новое поведение — нужно иметь возможность откатиться.

В моём стеке образы Docker закреплены на конкретных дайджестах:

  • nousresearch/hermes-agent@sha256:c6637f... — не :latest.
  • ghcr.io/outsourc-e/hermes-workspace@sha256:2d2ba... — не плавающий тег.
  • bronevik/agent-tools:2026-06-07 — датированный тег, не :latest.

Версии CLI в agent-tools тоже зафиксированы: Codex CLI 0.137.0, Claude Code 2.1.167. Никаких автообновлений без ручного триггера и последующей проверки инструментов.

Что в итоге

Политика инструментов AI-агентов — это не разовая настройка, а непрерывная практика:

  1. Секреты живут отдельно от знаний. Vault и workspace не должны содержать ключей, токенов или приватных файлов.
  2. MCP-серверы настраиваются через allowlist. Каждый инструмент добавляется явно, с пониманием зачем.
  3. Agent bridge — узкий и проверяемый. Именованные действия вместо generic shell.
  4. Web-шеллы — только для человека. Агенты общаются через bridge, не через терминал.
  5. Регулярный аудит. bronevik-vault-status и проверка списка инструментов после изменений.
  6. Закреплённые версии. Дайджесты и датированные теги вместо плавающих latest.

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