Слушатель вебхуков Microsoft Graph

Платформа шлюза msgraph_webhook — это предстоящий слушатель событий. Таким образом Hermes получает уведомления об изменениях от Microsoft Graph — «встреча Teams завершилась», «в этот чат пришло новое сообщение», «календарь этого события был обновлено». В отличие от платформы «команды» (которая является чат-ботом, мои пользователи пишут), этот слушатель — M365 сообщает Гермесу о том, что произошло, а не человек.

Сейчас основным потребителем является конвейерный конвейер встреч Teams: Graph уведомляет, когда встреча создает стенограмму, конвейер загружает ее, и Hermes публикует краткое содержание обратно в Teams. Другие ресурсы Graph (/chats/.../messages, /users/.../events) используют тот же слушатель — пользователь конвейера появляется со своими собственными PR.

Предварительные требования

Быстрый старт

Минимальный ~/.hermes/config.yaml:

platforms:
  msgraph_webhook:
    enabled: true
    extra:
      port: 8646
      client_state: "замените-на-сильный-секрет"
      accepted_resources:
        - "communications/onlineMeetings"

Или через переменные окружения в ~/.hermes/.env (автоматически объединяются при запуске):

MSGRAPH_WEBHOOK_ENABLED=true
MSGRAPH_WEBHOOK_PORT=8646
MSGRAPH_WEBHOOK_CLIENT_STATE=<сгенерируйте-с-openssl-rand-hex-32>
MSGRAPH_WEBHOOK_ACCEPTED_RESOURCES=communications/onlineMeetings

Запустите шлюз: «Запуск шлюза Гермеса». Слушатель обеспечивает:

Откройте слушатель публично (обратный прокси, туннель для разработки, вход). Ваш URL-адрес для подписки на Graph — это ваш публичный HTTPS-источник, за которым следует /msgraph/webhook:

https://ops.example.com/msgraph/webhook

Конфигурация

Все настройки находятся в platforms.msgraph_webhook.extra:

Настройка По умолчанию Описание
хозяин 0.0.0.0 Адрес привязки HTTP-слушателя.
порт 8646 Порт привязки.
webhook_path /msgraph/webhook URL-путь, по этому графику отправляются POST-запросы.
путь_здоровья /здоровье Конечная точка помощи.
client_state Общий секрет, который график повторяется в каждом уведомлении. Сравнивается с помощью hmac.compare_digest — сгенерируйте с помощью openssl rand -hex 32.
accepted_resources [] (принимать все) Белый список путей/шаблонов ресурсов График. Завершающий * действует как префиксное совпадение. Начальный / лампы. Пример: ["communication/onlineMeetings", "chats/*/messages"].
max_seen_receipts 5000 Размер кэша дедупликации для идентификатора идентификатора. Самые старые записи удаляются при использовании лимита.
allowed_source_cidrs [] (разрешить все) Опциональный белый список исходных IP. См. ниже.

Каждая настройка также имеет эквивалентную переменную окружность (MSGRAPH_WEBHOOK_*), которая занимается конфигурацией при запуске шлюза — см. справочник заключения окружения.

Усиление безопасности

clientState — базовая проверка аутентификации

График включает код clientState, который зарегистрировала вашу подписку. Слушатель отклоняет любое)., чей clientState не соответствует, используя безопасное сравнение по времени. Этот задокументированный механизм Microsoft — относится к последствиям как к сильному общему секрету.

Если client_state не задан, слушатель принимает любой корректно сформированный POST. Не запускайте без него в продакшене.

Белый список исходных IP (продакшен-развёртывания)

Для продакшена ограничьте слушателя опубликованными диапазонами IP-адресов источников вебхуков График от Microsoft. Microsoft документирует диапазон исходящего трафика в веб-сервисе [IP-адрес и URL-адрес Office 365] (https://learn.microsoft.com/en-us/microsoft-365/enterprise/urls-and-ip-address-ranges). Настроить их как:

platforms:
  msgraph_webhook:
    enabled: true
    extra:
      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"

Пустой белый список = принять откуда угодно (по умолчанию; сохранить рабочие стенки туннелей для разработки). Неверные строки CIDR записывают предупреждения в регистрацию и отключаются. Проверяйте список IP Microsoft ежеквартально — он меняется.

Завершение HTTPS

Слушатель использует обычный HTTP. Завершите TLS на своем обратном прокси (Caddy, Nginx, Cloudflare Tunnel, AWS ALB) и проксируйте слушателя в локальной сети. Граф отказывается предоставлять данные на конечные точки, не использующие HTTPS, поэтому нет пути, по которому незашифрованный трафик от Графа мог бы вас препятствовать.

Гигиена атаки

При успехе слушатель получает 202 Accepted с пустым голосом — внутренние счётчики остаются вне ответа по проводу. Операторы могут наблюдать счётчики через /health.

Таблица кодов статусов:

Результат Статус
Уведомление(я) осуществлено или дедуплицировано 202
Рукопожатие проверок (GET с validationToken) 200 (возвращает токен)
Каждый элемент в пакете не прошёл clientState 403
Некорректный JSON / отсутствует массив value / неизвестный ресурс 400
Исходный IP не в белом списке 403
Простой GET без validationToken 400

Устранение неполадок

Проблема Что проверить
График проверки подписки не удаётся Публичный URL-адрес доступен, путь /msgraph/webhook соответствует, GET с validationToken возвращает токен дословно как text/plain в течение 10 секунд.
ПОСТ-уведомления приходят, но ничего не обрабатывается client_state соответствует тем, которые вы зарегистрировали в подписке. Запустите заново openssl rand -hex 32 и создайте новую подписку, если значение изменилось. Проверьте, что accepted_resources включает путь ресурса, который отправляет Graph.
выдает 403 Несовпадение clientState (подделка или подписка зарегистрирована с другим значением). Пересоздайте подписку с помощью hermes groups-pipeline subscribe --client-state "$MSGRAPH_WEBHOOK_CLIENT_STATE"... (поставляется с PR-окружением выполнения конвейера).
Слушатель включен, но curl http://localhost:8646/health зависит Конфликт привязки порта. Проверьте ss -tlnp \| grep 8646 и при необходимости замените port:.
Реальные запросы График от Microsoft получают 403 Белый список исходных IP слишком узок. Временно удалите allowed_source_cidrs, убедитесь, что трафик проходит, затем расширьте список, включая текущий диапазон исходящего трафика Microsoft.

Связанные документы