Слушатель вебхуков Microsoft Graph
Платформа шлюза msgraph_webhook представляет собой входящий обработчик событий. Через неё VibeOS получает уведомления об изменениях от Microsoft Graph — «встреча Teams завершена», «в чате появилось новое сообщение», «событие календаря обновлено». В отличие от платформы teams (бота, с которым общаются пользователи), этот механизм предназначен для того, чтобы M365 сообщала VibeOS о произошедших событиях, а не для общения с людьми.
Сейчас основным потребителем является конвейер обработки сводок встреч Teams: Graph уведомляет, когда для встречи появляется стенограмма, конвейер загружает её, и VibeOS публикует сводку обратно в Teams. Другие ресурсы Graph (/chats/.../messages, /users/.../events) используют тот же слушатель — конвейеры-потребители появятся с собственными PR.
Предварительные требования
- Учётные данные приложения Microsoft Graph — Зарегистрируйте приложение Microsoft Graph
- Публичный HTTPS-URL, доступный Microsoft Graph (Graph не вызывает частные конечные точки). Для тестирования подходит туннель разработчика; для продакшена нужен реальный домен с валидным сертификатом.
- Надёжный общий секрет для использования в качестве значения
clientState. Сгенерируйте с помощьюopenssl rand -hex 32и поместите в~/.vibeos/.envкакMSGRAPH_WEBHOOK_CLIENT_STATE.
Быстрый старт
Минимальный ~/.vibeos/config.yaml:
platforms:
msgraph_webhook:
enabled: true
extra:
host: 127.0.0.1
port: 8646
client_state: "замените-на-надёжный-секрет"
accepted_resources:
- "communications/onlineMeetings"
Или через переменные окружения в ~/.vibeos/.env (автоматически объединяются при запуске):
MSGRAPH_WEBHOOK_ENABLED=true
MSGRAPH_WEBHOOK_PORT=8646
MSGRAPH_WEBHOOK_CLIENT_STATE=<сгенерируйте-с-openssl-rand-hex-32>
MSGRAPH_WEBHOOK_ACCEPTED_RESOURCES=communications/onlineMeetings
Примечание: хост привязки считывается из extra.host в config.yaml (см. пример выше); переменной окружения MSGRAPH_WEBHOOK_HOST не существует.
Запустите шлюз: vibeos gateway run. Слушатель предоставляет:
POST /msgraph/webhook— уведомления об изменениях от GraphGET /msgraph/webhook?validationToken=...— проверка подписки Graph (квитирование)GET /health— проверка готовности со счётчиками принятых/дублированных уведомлений
Опубликуйте слушатель публично (обратный прокси, туннель разработчика, ingress). Ваш URL для уведомлений в подписках Graph — это ваш публичный HTTPS-источник, за которым следует /msgraph/webhook:
https://ops.example.com/msgraph/webhook
Конфигурация
Все настройки находятся в platforms.msgraph_webhook.extra:
| Параметр | По умолчанию | Описание |
|---|---|---|
host | 0.0.0.0 | Адрес привязки HTTP-слушателя. Привязка не к loopback требует allowed_source_cidrs; loopback (127.0.0.1 / ::1) — самый простой вариант для туннеля разработчика / обратного прокси. |
port | 8646 | Порт привязки. |
webhook_path | /msgraph/webhook | Путь URL, на который Graph отправляет POST-запросы. |
health_path | /health | Конечная точка готовности. |
client_state | — | Общий секрет, который Graph повторяет в каждом уведомлении. Сравнивается с помощью hmac.compare_digest — сгенерируйте с openssl rand -hex 32. |
accepted_resources | [] (принимать все) | Белый список путей/шаблонов ресурсов Graph. Замыкающий * означает совпадение по префиксу. Начальный / допускается. Пример: ["communications/onlineMeetings", "chats/*/messages"]. |
max_seen_receipts | 5000 | Размер кэша дедупликации для ID уведомлений. Самые старые записи удаляются при достижении лимита. |
allowed_source_cidrs | [] | Обязательно для привязки не к loopback. Оставляйте пустым только если слушатель привязан к loopback и находится за локальным туннелем / обратным прокси. |
Большинство параметров также имеют эквивалентную переменную окружения (MSGRAPH_WEBHOOK_*), которая объединяется с конфигурацией при запуске шлюза (исключение — host, он доступен только в конфиге — см. примечание выше) — смотрите справочник по переменным окружения.
Усиление безопасности
clientState — основная проверка подлинности
Каждое уведомление Graph включает строку clientState, с которой была зарегистрирована ваша подписка. Слушатель отклоняет любое уведомление, чей clientState не совпадает, используя безопасное по времени сравнение. Это документированный механизм Microsoft — относитесь к этому значению как к надёжному общему секрету.
Если client_state не задан, слушатель отказывается запускаться.
Белый список IP-адресов источников (продакшен-развёртывания)
В продакшене ограничьте слушатель опубликованными Microsoft диапазонами IP-адресов источников вебхуков Graph. Microsoft документирует диапазоны исходящего трафика в веб-сервисе IP-адресов и URL Office 365. Настройте их так:
platforms:
msgraph_webhook:
enabled: true
extra:
host: 0.0.0.0
client_state: "..."
allowed_source_cidrs:
- "52.96.0.0/14"
- "52.104.0.0/14"
# ...добавьте текущие диапазоны исходящего трафика категорий "Common" + "Teams" Microsoft 365
Или как переменную окружения:
MSGRAPH_WEBHOOK_ALLOWED_SOURCE_CIDRS="52.96.0.0/14,52.104.0.0/14"
Привязка к не-loopback хосту, такому как 0.0.0.0, :: или LAN-IP, без allowed_source_cidrs будет отклонена при запуске. Если вы используете туннель разработчика или обратный прокси на той же машине, привяжите VibeOS к 127.0.0.1 или ::1 и оставьте белый список пустым. Некорректные строки CIDR логируют предупреждение и игнорируются. Пересматривайте список IP-адресов Microsoft ежеквартально — он меняется.
Терминация HTTPS
Слушатель работает по обычному HTTP. Завершайте TLS на вашем обратном прокси (Caddy, Nginx, Cloudflare Tunnel, AWS ALB) и проксируйте трафик к слушателю по локальной сети. Graph отказывается доставлять уведомления на конечные точки, не использующие HTTPS, поэтому незашифрованный трафик от самого Graph до вас не дойдёт.
Гигиена ответов
При успехе слушатель возвращает 202 Accepted с пустым телом — внутренние счётчики не попадают в ответ по сети. Операторы могут наблюдать счётчики через /health, который защищён теми же правилами IP-адресов, что и путь вебхука.
Таблица кодов состояния:
| Результат | Статус |
|---|---|
| Уведомление(я) приняты или дедуплицированы | 202 |
Проверка подписки (GET с validationToken) | 200 (возвращает токен) |
| Все элементы в пакете не прошли проверку clientState | 403 |
Некорректный JSON / отсутствует массив value / неизвестный ресурс | 400 |
| IP-адрес источника не в белом списке | 403 |
Простой GET без validationToken | 400 |
Устранение неполадок
| Проблема | Что проверить |
|---|---|
| Не удаётся проверить подписку Graph | Публичный URL доступен, путь /msgraph/webhook совпадает, GET с validationToken возвращает токен дословно как text/plain в течение 10 секунд. |
| Уведомления POST-ятся, но ничего не обрабатывается | client_state совпадает с тем, что было указано при регистрации подписки. Заново выполните openssl rand -hex 32 и создайте новую подписку, если значение изменилось. Проверьте, что accepted_resources включает путь ресурса, который отправляет Graph. |
| Каждое уведомление возвращает 403 | Несовпадение clientState (подделка или подписка зарегистрирована с другим значением). Пересоздайте подписку с помощью vibeos teams-pipeline subscribe --client-state "$MSGRAPH_WEBHOOK_CLIENT_STATE" ... (поставляется с PR для конвейера времени выполнения). |
Слушатель отказывается запускаться на 0.0.0.0 | Установите allowed_source_cidrs на текущие диапазоны исходящего трафика вебхуков Microsoft или привяжите VibeOS к 127.0.0.1 / ::1 за туннелем или обратным прокси. |
Слушатель запускается, но curl http://localhost:8646/health зависает | Конфликт привязки порта. Проверьте ss -tlnp | grep 8646 и измените port: при необходимости. |
| Реальные запросы Graph от Microsoft получают 403 | Белый список IP-адресов источников слишком узок. Расширьте список, включив текущие диапазоны исходящего трафика Microsoft. Если вы всё ещё тестируете путь через туннель, привяжите VibeOS к loopback и позвольте туннелю обрабатывать публичный доступ. |
Связанные документы
- Зарегистрируйте приложение Microsoft Graph — предварительное требование регистрации приложения в Azure
- Переменные окружения → Microsoft Graph — полный список переменных окружения
- Настройка бота Microsoft Teams — другая платформа, позволяющая пользователям общаться с VibeOS в Teams