Настройка аутентификации наблюдаемости

Экспортер Agent 365 требует резолвера токенов для аутентификации при экспорте телеметрии. В этом руководстве описан процесс настройки для агентов, созданных с использованием пакета SDK агентов Microsoft 365, включая как агенты с поддержкой Agent 365, так и агенты пользовательских обработчиков на .NET, Python и Node.js.

Для установки дистрибутивов, общей конфигурации и сценариев без пакета SDK агентов см. раздел Дистрибутив Microsoft OpenTelemetry.

Overview

Существует четыре сценария аутентификации, в зависимости от типа вашего агента и способа получения токенов. Получение токенов может осуществляться через поток On-Behalf-Of (OBO) или Service-to-Service (S2S). Выберите сценарий, который соответствует вашей конфигурации:

Сценарий Description
Agent 365, использующий OBO Встроенный AgenticTokenCache дистрибутив автоматически осуществляет получение токенов по делегированному маршруту. Пользовательский резолвер не требуется. Для этого маршрута требуется делегированное Agent365.Observability.OtelWrite разрешение и согласие администратора, что a365 setup all не настраивается для blueprint agents.
Agent 365, использующий S2S Агент получает токен только для приложения, используя цепочку агентной идентичности (getAgenticApplicationToken + Microsoft Authentication Libraries (MSAL)). Требуется пользовательский TokenResolver вариант и опция S2S endpoint. Экземпляр зарегистрированного агента не требует разрешения на наблюдаемость или согласие администратора, поэтому это рекомендованный подход для blueprint агентов, настроенных на a365 setup all.
Пользовательский обработчик с использованием OBO Агент получает пользовательский токен через Azure Bot OAuth с областью действия API наблюдаемости. Требуется пользовательскоеTokenResolver, OAuth соединение Azure Bot и делегированное Agent365.Observability.OtelWrite разрешение с согласия администратора.
Пользовательский обработчик с использованием S2S Агент получает токен приложения, используя учетные данные клиента. Требуется пользовательский TokenResolver. Регистрация приложения должна быть стандартной (не агентской). Стандартные регистрации приложений не являются инстансами зарегистрированных агентов, поэтому им требуется Agent365.Observability.OtelWrite разрешение приложения с согласия администратора.

Agent 365, использующий OBO

Агенты с поддержкой Agent 365 получают запросы с идентификацией агента (agenticAppId, agenticUserId) от платформы Agent 365. Используя OBO, встроенный AgenticTokenCache дистрибутив автоматически обрабатывает получение токенов по делегированному маршруту, так что вам не нужен кастомный резолвер токенов.

Предпосылки

  • Регистрация приложения Microsoft Entra: Принципал сервиса (регистрация приложения) с идентификатором клиента, секретом клиента и идентификатором арендатора.

  • Делегированные права API: Add Agent365.Observability.OtelWrite (Dedeleated) и предоставление согласия администратора. a365 setup all Команда не добавляет это разрешение для агентов blueprint. Глобальный администратор может добавить его и получить согласие администратора, выполнив следующую команду:

    a365 setup permissions custom --resource-app-id 9b975845-388f-4429-889e-eab1ef63949c --scopes Agent365.Observability.OtelWrite
    

    Для получения дополнительных опций, включая Центр администрирования Microsoft Entra, см. раздел «Предоставить разрешение».

Tip

Чтобы избежать делегированного разрешения на наблюдаемость и согласия администратора, используйте Agent 365 с поддержкой S2S для blueprint agents, настроенных с a365 setup all.

Setup

На каждом цикле ваш агент вызывает функцию RegisterObservability с контекстом цикла. Встроенный кэш использует делегированный токен пользователя из обработчика AgenticUserAuthorization для выполнения обмена по OBO, получая токен с областью действия Agent365.Observability.OtelWrite.

Для получения подробных инструкций по настройке, включая пакеты, конфигурацию и примеры кода, см. Кэш токенов агентов с приложениями Agent Framework.

Agent 365, использующий S2S

Agent 365-совместимые агенты также могут использовать аутентификацию S2S (service-to-service) вместо OBO. Этот путь рекомендуется для агентов чертежей, настроенных на a365 setup all. Агент получает токен, используя собственный идентификатор субъект-службы через двухэтапную агентную цепочку идентичности:

  1. Позвоните getAgenticApplicationToken(tenantId, agentId) , чтобы получить токен учетных данных клиента по пути Federated Managed Identity (FMI).
  2. Вызовите MSAL acquireTokenForClient с помощью токена приложения как clientAssertion и область api://9b975845-388f-4429-889e-eab1ef63949c/.defaultприменения.

Note

Федеративная управляемая идентичность (FMI) — это архитектура, в которой управляемая идентичность участвует в федерации рабочих идентичностей через федеративные учетные данные, позволяя обмениваться токенами и осуществлять аутентификацию без использования секретов на основе доверительных отношений между идентичностями.

Дистрибутив Microsoft OpenTelemetry по умолчанию ориентирован на делегированный маршрут, поэтому необходимо ввести пользовательский TokenResolver вариант и установить опцию S2S endpoint для вашего языка, например UseS2SEndpoint = true, useS2SEndpoint: trueили a365_use_s2s_endpoint=True.

Предпосылки

  • Регистрация агента 365: Экземпляр агента должен быть зарегистрирован в Агенте 365. Команда a365 setup all регистрирует экземпляры агентов blueprint. Создание идентичности Microsoft Entra само по себе не регистрирует экземпляр агента.
  • Учетные данные Blueprint для обмена FMI: используйте секрет или управляемую идентичность клиента blueprint, чтобы получить токен Federated Managed Identity (FMI) для api://AzureADTokenExchange/.default, затем обменяйте его на токен Observability для экземпляра агента.
  • Совпадение значений идентичности: ID агента и идентификатор арендатора в багаже и URL экспорта должны совпадать с клиентским идентификатором экземпляра агента и арендатором из токена только для приложения.

Note

Агент, зарегистрированный в Agent 365, может экспортировать по маршруту S2S с токеном только для приложения, который не Agent365.Observability.OtelWrite имеет роли. Для этого не требуется разрешение на Observability или согласие администратора. Незарегистрированные личности, включая стандартные регистрации в приложениях, всё равно требуют роли Agent365.Observability.OtelWrite в приложении и согласия администратора.

Шаг 1. Конфигурация среды

В следующих примерах кода показано, как задать необходимые параметры подключения, арендатора, клиентских учетных данных и среды экспортера наблюдаемости перед активацией пользовательского потока токена S2S.

Обработчик AgenticUserAuthorization не требуется. S2S использует ручную агентную цепочку идентификации (get_agentic_application_token + MSAL acquire_token_for_client) для получения токена с областью действия для ресурса наблюдаемости.

CONNECTIONSMAP__0__SERVICEURL=*
CONNECTIONSMAP__0__CONNECTION=SERVICE_CONNECTION

CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID=<your-client-id>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET=<your-client-secret>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID=<your-tenant-id>

ENABLE_A365_OBSERVABILITY=true
ENABLE_A365_OBSERVABILITY_EXPORTER=true

Шаг 2. Настройка дистрибутива с помощью пользовательского резолвера токенов

Следующие примеры показывают, как включить экспорт Agent 365 и зарегистрировать пользовательский TokenResolver, чтобы экспортер мог получать токены S2S для каждого агента и арендатора.

from microsoft.opentelemetry import use_microsoft_opentelemetry

_token_cache: dict[str, str] = {}

def token_resolver(agent_id: str, tenant_id: str) -> str | None:
    return _token_cache.get(f"{agent_id}:{tenant_id}")

use_microsoft_opentelemetry(
    enable_a365=True,
    a365_token_resolver=token_resolver,
    a365_use_s2s_endpoint=True,
    a365_enable_observability_exporter=True,
)

Шаг 3. Получение и кэширование токена S2S

В каждом входящем сообщении получайте токен S2S через цепочку агентной идентичности и кэшируйте его для резолвера.

import asyncio
from msal import ConfidentialClientApplication
from microsoft.opentelemetry.a365.core import BaggageBuilder, InvokeAgentScope, InvokeAgentScopeDetails, Request

OBSERVABILITY_S2S_SCOPE = "api://9b975845-388f-4429-889e-eab1ef63949c/.default"

async def get_agentic_s2s_token(connection, tenant_id: str, agent_id: str) -> str:
    # Step 1: Get agentic application token (client_credentials + fmi_path)
    app_token = await connection.get_agentic_application_token(tenant_id, agent_id)
    if not app_token:
        raise ValueError(f"Failed to get agentic app token for agent {agent_id}")

    # Step 2: Exchange for observability-scoped token
    cca = ConfidentialClientApplication(
        client_id=agent_id,
        authority=f"https://login.microsoftonline.com/{tenant_id}",
        client_credential={"client_assertion": app_token},
    )
    result = await asyncio.to_thread(
        lambda: cca.acquire_token_for_client(scopes=[OBSERVABILITY_S2S_SCOPE])
    )
    if not result or "access_token" not in result:
        raise ValueError(f"Token acquisition failed: {result}")
    return result["access_token"]

# In your message handler : use SDK helpers to get agent/tenant from the activity:
@AGENT_APP.activity("message")
async def on_message(context: TurnContext, _state: TurnState):
    # get_agentic_instance_id reads from recipient (SDK convention)
    agent_id = context.activity.get_agentic_instance_id()
    tenant_id = context.activity.get_agentic_tenant_id()

    # Acquire S2S token and cache BEFORE creating spans
    connection = CONNECTION_MANAGER.get_connection("SERVICE_CONNECTION")
    token = await get_agentic_s2s_token(connection, tenant_id, agent_id)
    _token_cache[f"{agent_id}:{tenant_id}"] = token

    # Wrap spans in BaggageBuilder so the exporter can resolve the token
    request = Request(content=user_message, session_id=None)
    with BaggageBuilder().tenant_id(tenant_id).agent_id(agent_id).build():
        invoke_scope = InvokeAgentScope.start(request, InvokeAgentScopeDetails(), agent_details)
        with invoke_scope:
            invoke_scope.record_input_messages([user_message])
            invoke_scope.record_output_messages([response])

Это важно

Для S2S требуется ручной двухступенчатый процесс (get_agentic_application_token + MSAL acquire_token_for_client). AgenticUserAuthorization.get_token() возвращает токен, предназначенный для 5a807f24-.../.default (Bot Framework), а не для ресурса наблюдаемости api://9b975845-.../.default: конечная точка S2S отклоняет его с кодом 401 InvalidAudience.

  • Используйте context.activity.get_agentic_instance_id() и get_agentic_tenant_id() для чтения агента и арендатора из активности (чтение производится по конвенции SDK через recipient).
  • Получите и кэшируйте S2S токен перед созданием спанов. BatchSpanProcessor экспортера может выполнить сброс до завершения обработчика: если токен еще не кэширован, экспорт завершится ошибкой.
  • Оберните все области действия A365 в BaggageBuilder, чтобы экспортер знал, для какого агента и арендатора определять токены. Без baggage спаны незаметно отбрасываются с сообщением "Не найдено ни одного спана с идентификацией арендатора/агента".

Это важно

Перед тем как ваш резолвер вернёт и кэширует последний токен наблюдаемости:

  • Проверьте, что токен предназначен только для приложения. Примите idtyp=app. Если idtyp отсутствует, принимаем только токен с непустым roles притязанием или непустым oid утверждением, равным sub. Отклоняйте жетоны с scp притязанием или другой idtyp ценностью.
  • Проверьте, что aud это 9b975845-388f-4429-889e-eab1ef63949c или api://9b975845-388f-4429-889e-eab1ef63949c, и что токен не истек.
  • Никогда не отправляйте assertion промежуточного чертежа, токен чертежа или пользователя или токена OBO в Observability.
  • Кэшируйте последний токен и обновите его до истечения срока действия. Экспортер вызывает резолвер один раз для каждого идентификатора арендатора и агента в каждой экспортной партии.

Для полных реализаций, использующих дистрибутив, см. образцы Agent 365 для Node.js, Python и .NET.

Пользовательский обработчик с использованием OBO

Агенты пользовательского обработчика используют стандартные регистрации приложений с подключениями Azure Bot OAuth, а не агентную цепочку идентификации. Используя OBO, агент получает пользовательский токен через Azure Bot OAuth, который уже содержит область действия для API наблюдаемости A365, назначенную Bot Framework Token Service. Один вызов getToken или GetTurnTokenAsync возвращает токен с правильной областью действия, поэтому exchangeToken не требуется.

Предпосылки

Регистрация приложений Microsoft Entra с делегированными правами API. Добавьте Agent365.Observability.OtelWrite (делегировано) и дайте согласие администратора.

Это важно

agentId в кэше токенов должен совпадать с идентификатором клиента в регистрации приложения — а не с agenticAppId действия, которого нет для агентов пользовательского обработчика. URL-адрес экспорта включает agentId, а несовпадение вызывает ошибку HTTP 403.

Шаг 1. Настройка среды и приложения

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

# .env
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID=<your-client-id>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET=<your-client-secret>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID=<your-tenant-id>

CONNECTIONSMAP__0__CONNECTION=SERVICE_CONNECTION
CONNECTIONSMAP__0__SERVICEURL=*

# Auth handler config : TYPE is required, name is uppercased by load_configuration_from_env
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__OBOCONNECTIONPROFILE__TYPE=UserAuthorization
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__OBOCONNECTIONPROFILE__SETTINGS__AZUREBOTOAUTHCONNECTIONNAME=oboConnectionProfile
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__OBOCONNECTIONPROFILE__SETTINGS__SCOPES=api://9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite

ENABLE_A365_OBSERVABILITY=true
ENABLE_A365_OBSERVABILITY_EXPORTER=true

Это важно

load_configuration_from_env переводит все ключи переменных среды в верхний регистр. Имя обработчика устанавливается как OBOCONNECTIONPROFILE, и вы должны ссылаться на него с точно таким же регистром в вызовах auth_handlers и get_token(). При отсутствии TYPE возникает Auth handler ... not recognized or not configured во время выполнения.

Шаг 2. Настройка дистрибутива для OBO

В приведенных ниже примерах показано, как включить экспорт Agent 365, оставить экспортер на конечной точке OBO и зарегистрировать пользовательский TokenResolver, который возвращает делегированные токены во время экспорта.

from microsoft.opentelemetry import use_microsoft_opentelemetry

_token_cache: dict[str, str] = {}

def token_resolver(agent_id: str, tenant_id: str) -> str | None:
    return _token_cache.get(f"{agent_id}:{tenant_id}")

environ["ENABLE_A365_OBSERVABILITY_EXPORTER"] = "true"

use_microsoft_opentelemetry(
    enable_a365=True,
    a365_token_resolver=token_resolver,
    a365_use_s2s_endpoint=False,  # OBO uses /observability endpoint
    a365_enable_observability_exporter=True,
)

Note

В режиме OBO необходимо наличие jwt_authorization_middleware на aiohttpApplication (проверяет входящий JWT (JSON Web Token) от Bot Framework). Путь S2S/эмулятора не должен включать это промежуточное ПО.

from microsoft_agents.hosting.aiohttp import jwt_authorization_middleware
app = Application(middlewares=[jwt_authorization_middleware])

Шаг 3. Получение токена OBO

В приведенных ниже примерах показано, как запросить делегированный OBO-токен из настроенного подключения Azure бот OAuth, а затем кэшировать его по клиенту приложения и арендаторам для экспортера.

from microsoft_agents.hosting.core import (
    AgentApplication, Authorization, MemoryStorage, TurnContext, TurnState,
)
from microsoft_agents.activity import load_configuration_from_env
from microsoft_agents.authentication.msal import MsalConnectionManager
from microsoft_agents.hosting.aiohttp import CloudAdapter

# Auth handlers are loaded from .env via load_configuration_from_env (see Environment config above)
agents_sdk_config = load_configuration_from_env(environ)

STORAGE = MemoryStorage()
CONNECTION_MANAGER = MsalConnectionManager(**agents_sdk_config)
ADAPTER = CloudAdapter(connection_manager=CONNECTION_MANAGER)
AUTHORIZATION = Authorization(STORAGE, CONNECTION_MANAGER, **agents_sdk_config)

AGENT_APP = AgentApplication[TurnState](
    storage=STORAGE, adapter=ADAPTER, authorization=AUTHORIZATION, **agents_sdk_config,
)

CLIENT_ID = environ.get("CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID", "")
TENANT_ID = environ.get("CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID", "")

# Message handler : get_token returns a token already scoped to the observability API.
# The Azure Bot Token Service performs the OBO exchange internally based on the
# OAuth connection's configured scope. No manual MSAL exchange_token call is needed.
@AGENT_APP.activity("message", auth_handlers=["OBOCONNECTIONPROFILE"])
async def on_message(context: TurnContext, _state: TurnState):
    token_response = await AGENT_APP.auth.get_token(context, "OBOCONNECTIONPROFILE")
    # token_response.token has aud=<a365-observability-app-id>,
    # scp=Agent365.Observability.OtelWrite
    _token_cache[f"{CLIENT_ID}:{TENANT_ID}"] = token_response.token

Это важно

Azure portal prerequisite: Set the Scopes for the Azure Bot OAuth connection named oboConnectionProfile to api://9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite. Без этой настройки токен назначается аудитории самого бота (api://botid-...), и экспорт завершается ошибкой HTTP 401 InvalidAudience.

Note

AGENT_APP.auth.get_token() возвращает правильно обозначенный токен напрямую — вызов не exchange_token() требуется. Служба токенов Bot Framework обрабатывает обмен OBO, когда область подключения OAuth нацелена на ресурс наблюдаемости A365.

Пользовательский обработчик с использованием S2S

Пользовательские агенты движка могут использовать S2S (учётные данные клиента) для получения токена только для приложения, используя учетные данные подключения к сервису. Этот метод использует стандартные учетные данные MSAL клиента — не требуется агентская цепочка идентичности.

Предпосылки

  • Регистрация приложения Microsoft Entra: Регистрация приложения должна быть стандартным (пользовательским движком). Регистрации приложений с поддержкой Agent 365 не могут использовать обычный client_credentials для ресурса наблюдаемости (AADSTS82001).
  • Права заявки: Add Agent365.Observability.OtelWrite (Заявка, не делегирована) и предоставление согласия администратора. Стандартные регистрации приложений не являются инстансами агента, зарегистрированных в Agent 365, поэтому им нужна эта роль в S2S.

Это важно

agentId Для кэширования вы используете, должно быть, это ServiceConnectionClientId. URL-адрес экспорта: /observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces — несоответствие вызывает HTTP 403.

Шаг 1. Настройка среды и приложения

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

# .env
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID=<your-client-id>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET=<your-client-secret>
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID=<your-tenant-id>

CONNECTIONSMAP__0__CONNECTION=SERVICE_CONNECTION
CONNECTIONSMAP__0__SERVICEURL=*

ENABLE_A365_OBSERVABILITY=true
ENABLE_A365_OBSERVABILITY_EXPORTER=true

Шаг 2. Настройка дистрибутива для S2S

Следующие примеры демонстрируют, как включить экспорт Agent 365, настроить экспортер для конечной точки S2S и зарегистрировать пользовательский TokenResolver для разрешения токена при экспорте.

from microsoft.opentelemetry import use_microsoft_opentelemetry

_token_cache: dict[str, str] = {}

def token_resolver(agent_id: str, tenant_id: str) -> str | None:
    return _token_cache.get(f"{agent_id}:{tenant_id}")

use_microsoft_opentelemetry(
    enable_a365=True,
    a365_token_resolver=token_resolver,
    a365_use_s2s_endpoint=True,  # S2S uses /observabilityService endpoint
    a365_enable_observability_exporter=True,
)

Шаг 3. Получение токена S2S

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

# Force agentId to ServiceConnection ClientId (custom engine agents have no agenticAppId)
agent_id = os.environ.get("CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID")
tenant_id = os.environ.get("CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID")

connection = CONNECTION_MANAGER.get_connection("SERVICE_CONNECTION")
token = await connection.get_access_token(
    resource_url="https://login.microsoftonline.com",
    scopes=["api://9b975845-388f-4429-889e-eab1ef63949c/.default"],
)
_token_cache[f"{agent_id}:{tenant_id}"] = token

Шаг 4. Задание baggage для экспорта span

Экспортер Agent365 требует указания багажа (идентификатор арендатора и идентификатор агента) в контексте span. Без этого багажа экспортер сбрасывает spans и ведёт сообщение No spans with tenant/agent identity found..

from microsoft.opentelemetry.a365.core import BaggageBuilder, InvokeAgentScope

# Baggage must wrap the span as a context manager
with BaggageBuilder().tenant_id(tenant_id).agent_id(agent_id).build():
    invoke_scope = InvokeAgentScope.start(request, InvokeAgentScopeDetails(), agent_details)
    with invoke_scope:
        invoke_scope.record_input_messages([user_message])
        invoke_scope.record_output_messages([response])