sentinelx-cloud-core
Управляйте вашими Linux-серверами из Claude.ai или ChatGPT безопасно. SentinelX предоставляет вашему LLM разрешённый к аудиту шелл: он может выполнять только те команды, которые вы явно разрешили; доступ к файловой системе ограничен per-path allowlist, и каждое действие фиксируется. Нет входящих портов — только один исходящий WebSocket. Модель безопасности — это суть. Предоставление LLM неограниченного шелла на сервере, которым вы руководите, — именно то, чего SentinelX избегает: allowlist является реальной границей доверия, поэтому агент не может запустить — или изобрести — ничего, чего вы не разрешили. Это агент, который устанавливаете на хосте; структурированные редактирования файлов и управление сервисами идут вместе с ним.
Установка (многие начинают с этого):
curl -fsSL https://get.sentinelx.app | sudo bash
SentinelX также указан в каталоге приложений ChatGPT — пользователи ChatGPT могут подключить его в один клик, без необходимости настраивать собственный MCP URL. Этот репозиторий также является исходником агента — читайте дальше, если хотите провести аудит или внести вклад.
Архитектура
Internet
│
┌────────────────┐ │ ┌─────────────────┐
│ Claude.ai or │ MCP over HTTPS │ WebSocket │ Your Linux box │
│ ChatGPT │ ◄───────────────────► │ ◄──────────────► │ │
│ │ (OAuth via Google) │ │ ┌───────────┐ │
└────────────────┘ │ │ │ agent │ │
┌───────────────────────┐ │ │ (this) │ │
│ mcp.sentinelx.app │ │ └─────┬─────┘ │
│ (SentinelX hub — │ │ │ │
│ closed source) │ │ shell, edit, │
└───────────────────────┘ │ service mgmt │
└─────────────────┘
Агент — это коробка справа. Во время установки агент открывает один исходящий WebSocket к хабу и поддерживает соединение постоянно. Входящие порты отсутствуют, проброс портов отсутствует, обратного туннеля нет.
Что запускается где
| Компонент | Где | Что делает |
|---|---|---|
| sentinelx-cloud-core (этот репозиторий) | /opt/sentinelx-cloud-core на вашем хосте | Принимает MCP-вызовы инструментов от хаба, выполняет их локально и возвращает вывод |
| Хаб | mcp.sentinelx.app (управляется Pensa) | Аутентификация, маршрутизация по нескольким хостам, транспорт MCP |
| Конфигурация | /etc/sentinelx/config.yaml | Allowlist: какие команды, сервисы и пути агент примет |
| Идентификация | /etc/sentinelx/identity.json | JWT регистрации агента, используется для аутентификации рукопожатия WebSocket |
Поддерживаемые платформы: любая современная Linux-дистрибуция с systemd (проверено на Ubuntu 22.04/24.04 и Debian 12). Агент также без изменений запустим внутри WSL2 на Windows — полезно для разработчиков, которые хотят, чтобы SentinelX управлял их окружением WSL совместно с любыми другими Linux-хостами.
Инструменты, доступные агенту
Агент представляет операции своей хост-системы как инструменты MCP вашему LLM через хаб:
| Инструмент | Что делает |
|---|---|
| sentinel_exec | Выполнить разрешённую команду оболочки |
| sentinel_script_run | Запуск однократного bash- или python3-скрипта |
| sentinel_edit | Структурированное редактирование файлов (замена, по регулярному выражению, замена-блок, запись, добавление, префикс) |
| sentinel_edit_upload_* | Трёхступенчатая загрузка для крупных редактирований файлов |
| sentinel_move | Переместить/переименовать файл или директорию |
| sentinel_copy | Скопировать файл или директорию |
| sentinel_delete | Удалить файл или директорию |
| sentinel_chmod | Изменить разрешения файла |
| sentinel_chown | Изменить владельца/группу файла |
| sentinel_service | управление единицами через systemctl: start/stop/restart/reload/status |
| sentinel_restart | Короткий путь к sentinel_service restart |
| sentinel_upload_file | Одноразовая загрузка файла на хост |
| sentinel_upload_* | Трёхступенчатая порционная загрузка больших файлов |
| sentinel_read | Прочитать содержимое файла с опциональным диапазоном строк |
| sentinel_list | Структурированное перечисление содержимого каталога (имя, тип, размер, mtime) |
| sentinel_search | Рекурсивный поиск по содержимому с использованием regex и фильтрами по glob |
| sentinel_capabilities | Возвращает allowlist хоста и определения сервисов |
| sentinel_help | Краткое резюме агента плюс количество разрешённых команд, сервисов и плейбуков |
| sentinel_state | Внутреннее состояние агента, для отладки |
| sentinel_ping | Быстрая проверка соединения |
sentinel_read, sentinel_list и sentinel_search — это файловые примитивы только для чтения. sentinel_edit и мутирующие примитивы (sentinel_move, sentinel_copy, sentinel_delete, sentinel_chmod, sentinel_chown) — это операции записи. Все они дают LLM структурированный доступ к файловой системе без запуска внешних инструментов через exec (например, вызов cat/ls/mv/rm), и все они защищены тем же самым path allowlist (file_ops в конфигурации, см. ниже), а не списком разрешённых команд. Каждый путь в allowlist имеет уровень доступа: r (только чтение) или rw (чтение плюс запись). Записывающие операции, которые перезаписывают или удаляют существующий файл/каталог, сначала создают резервную копию с отметкой времени.
Дополнительно хаб предоставляет ряд интеграций на своей стороне (Cloudflare DNS, Resend email, Telegram) как MCP-инструменты, которыми ваш LLM может пользоваться вместе с инструментами агента — эти интеграции живут на хабе, а не в этом репозитории. См. таблицу интеграций на sentinelx.app.
Конфигурация (/etc/sentinelx/config.yaml)
Стартовый конфиг генерируется во время установки. Редактируемый. Перезагружается при перезапуске сервиса. Схема:
# Команды, которые агент может выполнять через операцию `exec`. Префиксное соответствие этому списку; пустой/отсутствующий означает запрет по умолчанию.
allowed_commands:
- uptime
- df -h
- free
- systemctl
- sudo systemctl
- journalctl
# См. config.example.yaml для полного стартового списка (проверка файлов,
# сети, контейнеры, git и пр.) плюс опциональные категории
# (Cloudflare tunnels, WireGuard, Android tooling, firewalling, SSH).
# Юниты служб, которыми агент может управлять через `service` / `restart`.
# Каждый юнит явно перечисляет разрешённые действия.
services:
nginx:
actions: [status, start, stop, restart, reload]
docker:
actions: [status, restart]
# Агент сам по себе, чтобы LLM могла перезагрузить политику после редактирования конфигурации.
# Перезапуск повторно читает /etc/sentinelx/config.yaml. Только консервативные
# действия — нет start/stop, поскольку агент не может удалённо запустить себя после остановки.
sentinelx-cloud-core:
actions: [status, restart, is-active, is-enabled]
# postgresql:
# actions: [status, start, stop, restart, reload]
# Необязательное: именованные плейбуки, которые LLM может читать или исполнять.
# Поддерживаются две формы и могут сосуществовать в одном мапе:
#
# 1) Диагностический плейбук — фиксированная последовательность разрешённых команд,
# агент может выполнить их по порядку. Удобно для_prompt-ов типа "дай quick health snapshot".
#
# 2) Процедурный плейбук — структурированный рецепт для LLM, который следует,
# выраженный через поля `description` / `when` / `steps` / `requires` / `notes`.
# Агент сам по себе не выполняет шаги — LLM читает их через `capabilities` и затем вызывает обычные
# инструменты (`sentinel_exec`, `sentinel_edit`, `sentinel_service`) самостоятельно.
#
# См. `config.example.yaml` для полной справки.
playbooks:
# Диагностический плейбук (форма 1)
health:
description: "Show system health summary"
commands:
- "uptime"
- "df -h /"
- "free -m"
# Процедурный плейбук (форма 2) — проводит LLM через процесс расширения
# allowlist'а самого агента. Удобно, если пользователь хочет "позволить run htop здесь",
# и LLM знает точный порядок действий (изменение конфигурации, перезапуск сервиса,
# проверка capabilities).
add_allowed_command:
description: "How to add a new command to this host's allowlist"
when: "User asks to allow a new command on this host"
steps:
- "Read /etc/sentinelx/config.yaml with sentinel_exec"
- "Insert under allowed_commands with sentinel_edit (sudo, validator_preset=yaml)"
- "Restart the agent: sentinel_service restart sentinelx-cloud-core"
- "Verify with sentinel_capabilities"
# Логирование
log:
path: /var/log/sentinelx/core.log
level: INFO
# SSRF-защита для file_url. Имя хоста должно быть в этом allowlist и резолвиться
# в публично доступный IP (нет loopback, RFC1918, link-local и т.д.). Значение по умолчанию пустое — file_url выключен.
# Только добавляйте хосты, которыми вы управляете — сторонние хосты (github.com, pypi,
# любые CDN) подвергнут агент риску компрометации цепочки поставок.
security:
trusted_fetch_hosts:
- drop.pensa.ar
- get.sentinelx.app
file_url_timeout_seconds: 15
# Файловые примитивы (sentinel_read/list/search + edit, move, copy,
# delete, chmod, chown). Ограничены тем же path-allowlist, отдельно от
# allowlist команд выше. Пустой/отсутствующий — все файловые примитивы
# фактически отключены (они возвращают path_not_allowed для любого ввода).
#
# Каждый элемент объявляет уровень доступа:
# r = операции только для чтения (read, list, search) могут трогать этот поддерево
# rw = операции только для чтения И операции записи (edit, move, copy, delete,
# chmod, chown) могут трогать этот поддерево
#
# Путь разрешён только если, после канонизации (разрешены симлинки,
# убран '..'), он попадает под один из этих элементов. Канонизированная
# резолюция затем проверка префикса — это защищает от path traversal и escapes через
# симлинки. Пустой allowlist = примитивы файловой системы отключены.
#
# Историческая совместимость: старый `allowed_read_paths:` также принимается и
# трактуется как набор записей `r` (с предупреждением об устаревании).
file_ops:
paths:
- path: /etc/nginx
access: r
- path: /var/log
access: r
- path: /home/youruser/projects
access: rw
max_read_bytes: 65536 # на чтение; большие файлы возвращаются усечёнными
max_list_entries: 1000 # на список
max_search_results: 200 # на поиск
Агент совершенно запускает команды только с префиксом в allowed_commands. Так, разрешение git позволяет LLM выполнять git status, git log и т. п.; разрешение ls достаточно для охвата ls -lah /var/log. По умолчанию конфигурация ограничительная — смотрите config.example.yaml для полного стартового списка с разумными категориями.
Существует две независимые allowlist’ы, и они защищают разные операции:
allowed_commandsограничивает выполнение команд черезexec(и команды внутриscript_run).file_ops.pathsограничивает каждую файловую примитиву — чтение/перечисление (sentinel_read,sentinel_list,sentinel_search) на любом записиrилиrw, а запись (sentinel_edit,sentinel_move,sentinel_copy,sentinel_delete,sentinel_chmod,sentinel_chown) — только наrw.
Так что каталог, указанный как r, позволяет LLM просматривать его, но не изменять; каталог, помеченный как rw, позволяет и то, и другое. Каталог, не перечисленный ни в одном из списков, недоступен для всех файловых примитивов (LLM придётся использовать exec, который регулируется allowed_commands).
Единственное явное исключение: sentinel_edit с sudo=true НЕ ограничено path-allowlist. Точка доверия для редактирования через sudo — это политика sudo-оператора, а не path allowlist — именно это позволяет плейбуку add_allowed_command редактировать конфигурацию ROOT-владельца. Канонизация путей всё равно выполняется (без обхода traversal и обходов через симлинки); только членство в rw обходится для пути with sudo. Это исключение и его остаточный риск задокументированы в THREAT_MODEL.md (§4.2.1).
Модель безопасности
- Нет входящих портов. Только исходящий WebSocket к хабу.
- Идентификация по JWT.
identity.jsonподписан хабом при enrollment. Компрометация одного хоста не предоставляет доступ к другим. - Allowlist-защита. Всё, что не в
config.yaml, возвращаетcommand_not_allowed. Агент не будет синтезировать новые команды. Это реальная граница безопасности — не unix-пользователь и не политика sudo. Когда команда отклонена, агент возвращает классифицированную ошибку, которая направляет LLM к нужному инструменту, а не к угадыванию. - Файловая система. Любые структурированные файловые операции затрагивают только пути в
file_ops.paths. Чтение/перечисление (sentinel_read,sentinel_list,sentinel_search) работают наrиrw; запись (sentinel_edit,sentinel_move,sentinel_copy,sentinel_delete,sentinel_chmod,sentinel_chown) — только наrw. Пути канонизируются — симлинки разрешены,..сопоставляются — до проверки префикса, поэтому обход путей или выход за пределы allowlist невозможны. Пустой allowlist = примитивы отключены. Записывающие операции, которые перезаписывают или удаляют целевой файл/папку, делают резервную копию с отметкой времени. Исключение сsentinel_editиsudo=true— документировано в THREAT_MODEL.md §4.2.1. - Неавторизованный пользователь с passwordless sudo. Агент работает от имени
sentinelx, не от имени root. По умолчанию установщик предоставляетsentinelxpasswordless sudo для управления сервисами и редактирования системных файлов — но всё равно можно делать только то, что разрешено в вашем allowlist. Чтобы запускать без sudo, установитеSENTINELX_SKIP_SUDO=1во время установки. - SSRF-защищённый
file_url. При вызовеupload_fileпо URL агент валидирует имя хоста противsecurity.trusted_fetch_hosts, резолвит его в IP и отклоняет адреса типа loopback / RFC1918 / link-local. Перенаправления отключены, HTTPS по умолчанию, таймаут 15 сек. Allowlist по умолчанию пуст —file_urlфактически отключён до тех пор, пока оператор не включит конкретные хосты. - Защита от path-traversal загрузок. Все аргументы
target_pathрезолвятся вupload_baseчерезsafe_path_under();..и абсолютные пути, выходящие за пределы, отклоняются заранее. - Без телеметрии. Агент не сообщает ничего о вашем хосте или активности никому, кроме хаба, к которому вы явно подключены.
Для более глубокого обзора смотрите THREAT_MODEL.md (активы, противники, границы доверия, меры по каждому виду угроз) и SECURITY.md (отчёт о уязвимостях + политика раскрытия).
Локальная разработка
git clone https://github.com/pensados/sentinelx-cloud-core
cd sentinelx-cloud-core
python3 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
pytest # юнит-тесты
Чтобы запустить агент против хаба, отличного от продакшна:
SENTINELX_HUB_URL=wss://localhost:8000/agent/connect \
python3 -m sentinelx_core --identity-file /tmp/dev-identity.json
Vendored: pensa-safe-edit
Фактическое редактирование файлов для sentinel_edit выполняется небольшим модулем stdlib-only, встроенным в src/sentinelx_core/vendored/pensa_safe_edit.py. Он вызывается внутри процесса через Python API (без вызова shell=True), поэтому в пути редактирования не используется внешний шелл. Он работает через временные файлы и атомарное переименование, делает резервную копию перед изменением, сохраняет метаданные файла и может запускать необязательный валидатор перед коммитом (json/yaml/toml/python/sh/nginx/systemd presets) — если валидация не прошла, исходный файл остаётся без изменений. Он по-прежнему зарегистрирован как точка входа в pip как консоль-скрипт для автономного/ручного использования.
Связано
- sentinelx-cloud-installer — bash + Python инсталлятор
- sentinelx-cloud-protocol — спецификация формата передачи данных
Лицензия
Apache License 2.0 — смотрите LICENSE.