API ВЕГА
English

rustsdcmcp

Асинхронный Rust-сервер Model Context Protocol для HPE Juniper Security Director Cloud

проект mechub — автоматизация сетевой безопасности с суверенным управлением

Неофициальный проект сообщества. Это независимый проект сообщества, не связанный с Hewlett Packard Enterprise или Juniper Networks и не одобренный ими. Названия продуктов и товарные знаки используются только для обозначения систем, с которыми взаимодействует программное обеспечение.


rustsdcmcp предоставляет клиентам MCP доступ к HPE Juniper Security Director Cloud (SDC) через ограниченный и поддающийся аудиту набор инструментов. SDC — это портал HPE Juniper SASE для инфраструктуры SRX, поэтому сервер взаимодействует с плоскостью управления, а не с отдельным межсетевым экраном. Если rustjunosmcp работает с отдельными устройствами SRX по NETCONF, то rustsdcmcp обращается к управляющему ими порталу через HTTPS REST.

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

Текущий статус

В main сервер rustsdcmcp предоставляет 80 инструментов MCP (в версии v0.3.1 было 78, в v0.2.0 — 74): 60 инструментов чтения с ограниченным доступом и 20 инструментов управления изменениями. Набор охватывает ту часть API SDC, которая отвечает за управление устройствами SRX и их политиками; остальная часть API продукта намеренно не входит в область охвата.

Любое изменение можно выполнить только по схеме «подготовка → независимое утверждение → применение». Область действия токена, заданная шаблоном wildcard, намеренно не предоставляет инструментов записи, поэтому при создании токена каждый такой инструмент необходимо указывать явно.

Проверка в реальной среде SDC вышла далеко за рамки операций только для чтения. 2026-08-07 в тестовом тенанте был выполнен полный цикл prepare → approve → apply для развертывания политики, которая затем была применена к управляемому vSRX. Так обнаружилось поведение совместного управления, описанное в #23: в иерархиях, которыми управляет SDC, при развертывании удаляются объекты, на которые не ссылается импортированная в SDC политика. Интерфейсы, маршрутизация, system и экземпляр управления не затрагивались. Полное описание границ воздействия и наблюдавшихся изменений приведено в docs/operations.md. Форматы JobStatus и DeviceStatusEntry проверены по ответам реальных запросов предварительного просмотра и развертывания.

2026-08-12 в реальной среде были проверены средства чтения сертификатов и лицензий, BulkSyncDevices и конечные точки шаблонов. Синхронизация устройств импортирует данные в SDC, а не отправляет их на устройство. При этом она только сверяет инвентарные данные и не сбрасывает состояние device_config_state: OUT_OF_BAND_CHANGED.

Последняя проверка свойств безопасности путей чтения в реальной среде проводилась 2026-08-07 для коммита ea81805d2b4b97df9bdd3f70423e047524896a3d с mecmcp v0.5.0. После этого транспорт и предварительная проверка области действия были заменены в коммитах e28d0cc и 369f9bb, поэтому результаты той проверки больше не характеризуют текущий main; возможности повторить проверку в реальном тенанте SDC не было. 2026-10-06 для коммита 2036523 с mecmcp v0.26.0 вместо этого повторно запустили автоматизированный набор интеграционных тестов: cargo test --workspace, 258 пройдено, 0 ошибок. Набор проверяет, что:

  • запросы без bearer-токена отклоняются (crates/rustsdcmcp/tests/http_boundary.rs::router_requires_bearer);
  • запросы к тенантам, не входящим в область действия, отклоняются (crates/rustsdcmcp/tests/http_boundary.rs::out_of_scope_tenant_is_refused);
  • точно соблюдаются ограничения области действия для инструментов и тенантов, а инструменты чтения и записи разделены (crates/rustsdcmcp/src/server.rs, модульные тесты области действия; crates/rustsdcmcp/tests/tool_contract.rs);
  • секретные ключи удаляются из ответов (crates/rustsdcmcp-core/src/redact.rs, модульные тесты).

Остальные свойства, проверенные при аудите в реальной среде 2026-08-07, на текущем main повторно не проверялись. Этот запуск тестов не заменяет проверку в реальном тенанте и не подтверждает её результаты заново.

Наблюдаемые форматы ответов и оставшиеся вопросы по конечным точкам перечислены в docs/sdc-api/README.md.

Загрузка

К текущему выпуску v0.3.1 прикреплён установочный архив LXC (rustsdcmcp_0.3.1_amd64.tar.gz) с контрольной суммой и подписью cosign. Скачайте и проверьте его либо соберите приложение из одобренного исходного кода, как описано ниже.

Для этой версии опубликован образ контейнера linux/amd64 по адресу ghcr.io/mechubsec/rustsdcmcp:0.3.1. Его можно скачать без аутентификации.

Сборка из одобренного исходного кода

В rust-toolchain.toml закреплена версия инструментальной цепочки сборки 1.99.0; заявленная в Cargo.toml минимальная поддерживаемая версия MSRV — 1.89. Перед сборкой, тестированием или упаковкой операторы должны закрепить рабочую копию на коммите, который планируется выпустить. Обычно для этого используют тег выпуска:

approved_commit=$(git rev-parse v0.3.1^{commit})
git checkout --detach "$approved_commit"
test "$(git rev-parse HEAD)" = "$approved_commit"
cargo build --release --locked
cargo test --workspace --locked
scripts/build-package.sh
cp examples/sdc.example.json /secure/operator/path/sdc.json

В этой конфигурации credential_env задаёт имя внешней переменной процесса; само учётное значение нельзя хранить в JSON. Для локального пакета, привязанного к конкретному коммиту, проверьте созданный архив и встроенный в него BUILD-INFO из каталога одобренного коммита. Не используйте шаблоны поиска файлов по всему каталогу dist/: в контрольной сумме записано только имя архива:

artifact_dir="dist/$approved_commit"
mapfile -t archives < <(find "$artifact_dir" -maxdepth 1 -type f -name 'rustsdcmcp_*_amd64.tar.gz' -print)
test "${#archives[@]}" -eq 1
archive="${archives[0]}"
(cd "$artifact_dir" && sha256sum -c "$(basename "$archive").sha256")
package_root=$(tar -tzf "$archive" | sed -n '1s#/.*##p')
test -n "$package_root"
tar -xOf "$archive" "$package_root/BUILD-INFO" | grep -Fx "git_commit=$approved_commit"

Быстрый запуск в Docker

Инструкции по запуску опубликованного образа контейнера см. в HOW-TO-SETUP-DOCKER.md.

Быстрый запуск LXC на Debian 13

Инструкции по сборке LXC с нуля см. в HOW-TO-SETUP-LXC.md.

Требования:

  • Debian 13 AMD64; рекомендуется использовать непривилегированный LXC.

  • Минимальная конфигурация: 1 vCPU, 512 MiB RAM, 512 MiB swap и 4 GiB дискового пространства.

  • Рабочие DNS и синхронизация времени, а также исходящий HTTPS-доступ к

api.sdcloud.juniperclouds.net.

  • Доступ root или эквивалентный доступ оператора внутри LXC.

Скачайте подписанный архив выпуска v0.3.1 (или соберите его из одобренного исходного кода — см. раздел «Сборка из одобренного исходного кода» выше) и установите проверенный пакет:

set -euo pipefail
mapfile -t archives < <(find . -maxdepth 1 -type f -name 'rustsdcmcp_0.3.1_amd64.tar.gz' -print)
test "${#archives[@]}" -eq 1
archive="${archives[0]}"
sha256sum -c "$archive.sha256"
package_root=$(tar -tzf "$archive" | sed -n '1s#/.*##p')
test -n "$package_root"
tar -xzf "$archive"
sudo "$package_root/packaging/lxc/install.sh"

Создайте файлы конфигурации и учётных данных, не раскрывая секрет:

sudo install -o root -g rustsdcmcp -m 0640 \
  /etc/rustsdcmcp/sdc.json.example /etc/rustsdcmcp/sdc.json
sudoedit /etc/rustsdcmcp/sdc.json
sudo install -o root -g root -m 0600 /dev/null \
  /etc/rustsdcmcp/credentials.env
sudoedit /etc/rustsdcmcp/credentials.env

В sdc.json должен быть указан HTTPS-адрес SDC, выбранный локальный псевдоним тенанта и полученный оператором идентификатор тенанта SDC в expected_tenant_id. Файл с учётными данными должен содержать одну строку присваивания в формате, совместимом с shell, используя имя из credential_env, например SDC_API_TOKEN=.... Никогда не помещайте реальное значение в README или JSON.

Создайте первоначальное разрешение только на чтение для ровно 14 инструментов. Файл назначения перенаправления должен заранее иметь права доступа 0600; результатом будет одноразовый bearer-токен.

/secure/local/path/rustsdcmcp-sdc-read-token">

sudo /usr/local/bin/rustsdcmcp token add \
  --tokens-file /etc/rustsdcmcp/tokens.json \
  --device-mapping /etc/rustsdcmcp/sdc.json \
  --name sdc-read \
  --devices production \
  --tools get_sdc_tenant_scope,list_sdc_devices,get_sdc_device,list_sdc_firewall_policies,get_sdc_firewall_policy,list_sdc_nat_policies,get_sdc_nat_policy,list_sdc_resources,get_sdc_resource,get_sdc_preview_status,get_sdc_deploy_status,get_sdc_preview_device_result,get_sdc_deploy_device_result,get_sdc_change_set \
  --actor-type human > /secure/local/path/rustsdcmcp-sdc-read-token

Запустите службу и подключайтесь к ней через аутентифицированный SSH-туннель:

sudo systemctl enable --now rustsdcmcp.service
sudo systemctl --no-pager --full status rustsdcmcp.service
sudo ss -ltnp 'sport = :30032'
ssh -N -L 30032:127.0.0.1:30032 root@your-deployment-host

Ожидается, что служба будет прослушивать только адрес 127.0.0.1:30032. Пока туннель активен, локальный клиент MCP использует адрес http://127.0.0.1:30032/mcp. Для каждой установки задаётся собственный SSH-хост; сервер никогда не публикуется напрямую.

Обязательства по безопасности

  • Внешние учётные данные хранятся с ограничительными правами доступа к файлам и никогда не помещаются в JSON.

  • При запуске настроенная идентификация сверяется с expected_tenant_id.

  • Bearer-токены содержат точные области действия для инструментов и арендаторов.

  • Размеры запросов, ответов и страниц ограничены.

  • Атрибуция аудита не раскрывает учётные данные, а значения целевых объектов редактируются с помощью HMAC.

  • Для внесения изменений требуется контроль по схеме «подготовка → утверждение → применение» с участием двух субъектов.

  • Инструмента для прямого развёртывания нет; записывать данные без аутентификации невозможно.

  • Область действия токена * не даёт доступа ни к одному инструменту записи. Параметр --tools '*' открывает только поверхность чтения; при выпуске токена каждый инструмент записи необходимо указать явно.

Подробные инструкции по развёртыванию, восстановлению, срокам хранения аудита и процессу внесения изменений приведены в docs/operations.md.

--lab-mode

Параметр --lab-mode отменяет требование второго участника. Он предназначен для лабораторной среды, где контроль двумя участниками был бы лишь формальностью. По умолчанию режим отключён; его не следует включать там, где важна безопасность инфраструктуры.

Что меняется и что остаётся без изменений:

  • Отмена требования применяется автоматически при создании набора изменений. Отдельного инструмента для отмены нет, а процесс остаётся таким же, как в production: подготовка → применение.

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

  • Утверждающий не подменяется фиктивной записью. Для набора изменений, созданного с отменой требования, указываются approver: null и approval_waiver: "lab-mode", а также хеш отмены требования, рассчитанный по (change_set_id, plan_digest, owner, approved_at). Криптографически такую запись можно отличить от настоящего утверждения двумя участниками, и впоследствии её нельзя переименовать. Это важно, если потребуется доказать, какие изменения действительно прошли с разделением обязанностей.

  • Если режим включён, при запуске сервер выдаёт заметное предупреждение.

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

Включение режима

Добавьте флаг в конфигурацию системной службы. При установке пакета используйте drop-in-файл, а не редактируйте поставляемый unit-файл: иначе обновление может незаметно удалить изменение:

sudo systemctl edit rustsdcmcp

При замене ExecStart нужно указать его полностью. Поэтому скопируйте поставляемую команду и добавьте флаг, а не сокращайте её. Если убрать аргументы --audit-*, вместе с включением lab mode отключатся редактирование целевых значений с помощью HMAC и структурированный аудит в journald:

[Service]
# Перед заменой очистите поставляемый ExecStart; иначе systemd добавит новую команду к существующей.
ExecStart=
ExecStart=/usr/local/bin/rustsdcmcp \
    --device-mapping /etc/rustsdcmcp/sdc.json \
    --transport streamable-http \
    --host 127.0.0.1 \
    --port 30032 \
    --tokens-file /etc/rustsdcmcp/tokens.json \
    --audit-format json \
    --audit-journald \
    --audit-redact devices=hmac \
    --audit-hmac-key-file /etc/rustsdcmcp/audit-hmac.key \
    --lab-mode

Перед применением сверьте конфигурацию с packaging/systemd/rustsdcmcp.service: поставляемые аргументы являются эталоном, а этот пример может устареть.

sudo systemctl daemon-reload && sudo systemctl restart rustsdcmcp

Убедитесь, что настройка вступила в силу. В двух записях о запуске используются разные варианты написания: --lab-mode в предупреждении и lab_mode в строке с итоговой конфигурацией. Проверьте наличие обоих вариантов и читайте журнал с достаточными правами для просмотра системной службы:

sudo journalctl -u rustsdcmcp -b | grep -E 'lab.mode'
{"level":"WARN","fields":{"message":"--lab-mode: two-person control is DISABLED. …"}}
{"level":"INFO","fields":{"message":"change-control configuration resolved","lab_mode":true,…}}

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

После подготовки набора изменений с отменой требования prepare_sdc_policy_deploy сразу возвращает "state": "approved", "approver": null и "approval_waiver": "lab-mode". Для вызова apply_sdc_change_set отдельное утверждение не требуется.

Для разового запуска вместо системной службы передайте --lab-mode в командной строке тем же способом.

Приоритет настроек

--lab-mode входит в общий стандарт CLI для наборов изменений в mecmcp, наряду с --state-file и --approval-timeout-secs. Для двух последних явно заданный флаг имеет приоритет; в противном случае значение берётся из sdc.json (changeset_state_file, approval_ttl_secs).

--lab-mode задаётся только через CLI. В sdc.json намеренно нет соответствующего поля: ослабление меры безопасности должно требовать явного указания в конфигурации службы, доступной оператору, а не наследоваться из файла, который могли изменить несколько месяцев назад. Вопрос о том, допускает ли общий стандарт использование значения из конфигурации продукта, пока остаётся открытым (mecmcp#267); этот сервер придерживается более консервативного подхода.

Готовность к развёртыванию

Пакет для Debian 13 был установлен и проверен в полном цикле — от установки до запуска — из архива с привязкой к коммиту, собранного CI для ea81805d2b4b97df9bdd3f70423e047524896a3d. Служба запускается через поставляемый unit-файл rustsdcmcp.service от имени пользователя без прав root, привязывается только к loopback-интерфейсу, обеспечивает проверку bearer-токена и при запуске сверяет область действия арендатора с работающим SDC.

Важно учитывать ограничение пакета: директивы IPAddressAllow и IPAddressDeny в unit-файле действуют только в том случае, если среда выполнения хоста позволяет systemd подключить программу cgroup BPF. На проверенном развёртывании установщик сообщил NOT ENFORCED, поэтому исходящий трафик пришлось ограничивать вне unit-файла. Остальные директивы изоляции при этом продолжали действовать. Ориентируйтесь на результат проверки для своего хоста — не предполагайте заранее ни один из вариантов. Инструкции по развёртыванию, восстановлению, срокам хранения аудита и способам ограничения исходящего трафика в разных средах выполнения приведены в docs/operations.md.

Конкретные хосты, адреса и идентификаторы контейнеров намеренно не публикуются: каждый оператор указывает собственные значения.

Дорожная карта

Сведения о текущем покрытии, запланированном расширении и функциях, заблокированных из-за отсутствия поддержки в upstream API, см. в ROADMAP.md. Предложения по улучшению можно отправлять как issues на GitHub.

Связь с mecmcp

mecmcp — независимая от поставщика основа на Rust, общая для семейства MCP-серверов mechub. Этот репозиторий использует её, а не создаёт отдельную ветку. В main все восемь общих пакетов — mecmcp-audit, mecmcp-auth, mecmcp-changeset, mecmcp-redact, mecmcp-runtime, mecmcp-secret, mecmcp-server и mecmcp-transport — закреплены на версии v0.27.0.

Блокирующая проблема совместимости устранена. В предыдущих версиях этого раздела указывалось, что выпуск заблокирован до замены 59 временных объявлений совместимости единым согласованным upstream-релизом. Это требование выполнено: локальный слой compat/ удалили в #36 при переходе на mecmcp 0.7.2, а сам журнал совместимости удалили в 369f9bb при переходе на 0.8.0. Временных символов совместимости больше нет, как и журнала, который нужно было бы вести.

Происхождение API

Поверхность API закреплена по экспорту OpenAPI 3 от Juniper, который хранится в репозитории в docs/sdc-api/. Это авторитетный перечень поддерживаемых API SDC и оставшихся открытых вопросов.

Основные источники:

Передача аудита в хранилище событий

Журнал аудита не хранится только на этом хосте. Сервер следует общему стандарту семейства: AUDIT-FORWARDING-STANDARD.md.

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

Вывод записей (уже реализовано)

--audit-format json \
--audit-log-file /var/lib/rustsdcmcp/audit.jsonl

Формат JSON обязателен. Формат text предназначен для чтения в терминале и не подходит для разбора программными средствами. Файл предназначен для оператора и должен ротироваться — сервер никогда не обрезает его.

Транспорт

Записи напрямую добавляются в ssdf.audit в SSDF в виде строк, связанных хешами, в соответствии с объединённым контрактом SSDF для свидетельств. Благодаря этому можно обнаружить удаление или изменение записи. Механизм реализован: при настройке пересылки свидетельств сервер при запуске связывает EvidenceService и EvidenceHttpTransport (crates/rustsdcmcp/src/main.rs). Этот конвейер обработки свидетельств SSDF добавлен в рамках mecmcp#292.

Более простой вариант с syslog был разработан, но отклонён: он работает, однако записи в нём не связаны хешами. Все остальные звенья этой цепочки изначально обеспечивают защиту от подмены: дайджесты планов связывают их с одобрениями, в одобрениях указан отдельный субъект, а token_verified_fields отделяет подтверждённые источником данные от заявленных. На последнем этапе цепочки несвязанные записи лишили бы систему этой гарантии именно там, где она необходима аудитору. Обоснование такого решения приведено в стандарте.

Интерпретация результата

token_verified_fields содержит названия полей происхождения данных, которые подтвердил токен.

Остальные поля этой группы — client_name, model_id и session_id — заявлены клиентом и ничем не аутентифицированы. Не следует считать их равноценными.

Поле request_id связывает событие транспорта, событие обработчика и, в Junos, комментарий к фиксации изменений на устройстве.

Лицензия

Лицензия — MIT.