Configuração da autenticação de observabilidade

O exportador do Agente 365 requer um resolvedor de token para autenticar ao exportar telemetria. Este guia aborda a instalação de agentes criados com o SDK de Agentes do Microsoft 365, abrangendo agentes habilitados para Agente 365 e agentes de mecanismo personalizados em .NET, Python e Node.js.

Para a instalação da distribuição, a configuração geral e os cenários sem o SDK do Agente, consulte Microsoft OpenTelemetry Distro.

Overview

Há quatro cenários de autenticação, dependendo do tipo de agente e de como ele adquire tokens. A aquisição de tokens pode usar o fluxo On-Behalf-Of (OBO) ou serviço a serviço (S2S). Escolha o cenário que corresponde à configuração:

Scenario Description
Agente habilitado para o Microsoft 365 via OBO O componente integrado da distro, AgenticTokenCache, gerencia automaticamente a aquisição de tokens na rota delegada. Nenhum resolvedor personalizado é necessário. Essa rota precisa da permissão delegada Agent365.Observability.OtelWrite e do consentimento do administrador, que a365 setup all não configura para agentes de blueprint.
Agente habilitado para 365 usando S2S O agente adquire um token exclusivo do aplicativo usando a cadeia de identidade agêntica (getAgenticApplicationToken + Microsoft Authentication Libraries (MSAL)). Exige um TokenResolver personalizado e a opção de endpoint S2S. Uma instância de agente registrado não precisa de permissão de Observabilidade ou consentimento de administrador, então essa é a abordagem recomendada para agentes blueprint configurados com a365 setup all.
Motor personalizado com OBO O agente obtém um token de usuário por meio do Azure Bot OAuth, com escopo voltado para a API de observabilidade. É necessário um customTokenResolver, uma conexão OAuth do Azure Bot e a permissão delegada Agent365.Observability.OtelWrite com consentimento do administrador.
Motor personalizado usando S2S O agente adquire um token somente de aplicativo usando credenciais de cliente. Requer TokenResolver personalizado. O registro de aplicativo deve ser do tipo padrão (não agêntico). Registros padrão de aplicativos não são instâncias de agente registradas, então precisam da permissão de aplicativo Agent365.Observability.OtelWrite com consentimento do administrador.

Agente habilitado para 365 usando OBO

Agentes habilitados para o Agent 365 recebem solicitações com identidade agêntica (agenticAppId, agenticUserId) da plataforma Agent 365. Ao usar OBO, o recurso interno da distro AgenticTokenCache gerencia a aquisição de tokens automaticamente na rota delegada, então você não precisa de um resolvedor de token personalizado.

Pré-requisitos

  • Registro de aplicativo Microsoft Entra: Um principal de serviço (registro de app) com ID de Cliente, Segredo do Cliente e ID do locatário.

  • Permissões delegadas da API: Adicionar Agent365.Observability.OtelWrite (Delegado) e conceder consentimento do administrador. O a365 setup all comando não adiciona essa permissão para agentes blueprint. Um Administrador Global pode adicioná-la e conceder consentimento do administrador executando o seguinte comando:

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

    Para mais opções, incluindo o centro de administração do Microsoft Entra, veja Conceder a permissão.

Dica

Para evitar a permissão delegada de Observability e o consentimento do administrador, use o Agente 365 habilitado usando S2S para agentes blueprint configurados com a365 setup all.

Configuração

Em cada turno, seu agente chama a função RegisterObservability com o contexto do turno. O cache interno usa o token delegado do usuário do manipulador AgenticUserAuthorization para realizar uma troca OBO, adquirindo um token com escopo para Agent365.Observability.OtelWrite.

Para obter instruções completas para configuração, incluindo pacotes, configuração e exemplos de código, consulte Cache de tokens agêntico com apps do Agent Framework.

Agente habilitado para Microsoft 365 via S2S

Os agentes habilitados para o Agent 365 também podem usar a autenticação S2S (serviço a serviço) em vez de OBO. Esse caminho é recomendado para agentes blueprint configurados com a365 setup all. O agente obtém um token usando sua própria identidade da entidade de serviço por meio de uma cadeia de identidade agêntica de duas etapas:

  1. Ligue getAgenticApplicationToken(tenantId, agentId) para obter um token de credenciais de cliente com o caminho Federated Managed Identity (FMI).
  2. Chame MSAL acquireTokenForClient com o token do app como clientAssertion e o escopo api://9b975845-388f-4429-889e-eab1ef63949c/.default.

Note

A FMI (Identidade Gerenciada Federada) é uma arquitetura em que uma identidade gerenciada participa da federação de identidade de carga de trabalho por meio de credenciais de identidade federadas, habilitando a troca de tokens e a autenticação sem segredo com base nas relações de confiança entre identidades.

A distribuição OpenTelemetry da Microsoft utiliza por padrão a rota delegada, então você deve fornecer um TokenResolver personalizado e definir a opção de endpoint S2S para sua linguagem de programação, como UseS2SEndpoint = true, useS2SEndpoint: true ou a365_use_s2s_endpoint=True.

Pré-requisitos

  • Registro do Agente 365: A instância do agente deve estar registrada no Agente 365. O a365 setup all comando registra instâncias do agente blueprint. Criar uma identidade Microsoft Entra sozinha não registra uma instância de agente.
  • Credencial Blueprint para troca de FMI: Use um segredo do cliente blueprint ou identidade gerenciada para obter o token Federated Managed Identity (FMI) para api://AzureADTokenExchange/.default, e depois troque-o pelo token de Observabilidade da instância do agente.
  • Valores de identidade correspondentes: O ID do agente e o ID do tenant no baggage e a URL de exportação devem corresponder ao ID do cliente da instância do agente e ao tenant no token somente de aplicativo.

Note

Uma instância registrada no Agente 365 pode exportar pela rota S2S com um token somente de aplicativo que não tem a função Agent365.Observability.OtelWrite. Não precisa de permissão de observabilidade ou consentimento do administrador. Identidades não registradas, incluindo registros de aplicativo padrão, ainda precisam da Agent365.Observability.OtelWrite função do aplicativo e do consentimento do administrador.

Etapa 1: Configuração do ambiente

Os exemplos de código a seguir mostram como definir as configurações necessárias de ambiente de conexão, locatário, credencial de cliente e exportador de observabilidade antes de habilitar o fluxo de token S2S personalizado.

Nenhum AgenticUserAuthorization manipulador é necessário. O S2S usa a cadeia manual de identidade agêntica (get_agentic_application_token + MSAL acquire_token_for_client) para obter um token com escopo do recurso de observabilidade.

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

Etapa 2: Configurar a distribuição com resolvedor de token personalizado

Os exemplos a seguir mostram como habilitar a exportação do Agent 365 e registrar um TokenResolver personalizado para que o exportador possa obter tokens S2S para cada agente e locatário.

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,
)

Etapa 3: Adquirir e armazenar em cache o token S2S

A cada mensagem recebida, adquira o token S2S por meio da cadeia de identidade agêntica e armazene-o em cache para uso do resolvedor.

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])

Importante

O fluxo manual de duas etapas (get_agentic_application_token + MSAL acquire_token_for_client) é necessário para S2S. AgenticUserAuthorization.get_token() retorna um token restrito ao escopo de 5a807f24-.../.default (Bot Framework), e não para o recurso de observabilidade api://9b975845-.../.default: o endpoint S2S o rejeita com 401 InvalidAudience.

  • Use context.activity.get_agentic_instance_id() e get_agentic_tenant_id() para ler o agente e o tenant da atividade (lendo de recipient conforme a convenção do SDK).
  • Adquira e armazene em cache o token S2S antes de criar intervalos. O BatchSpanProcessor do exportador pode ser descarregado antes que o manipulador termine: se o token ainda não estiver em cache, a exportação falhará.
  • Encapsule todos os escopos BaggageBuilder do A365 para que o exportador saiba para qual agente e locatário resolver tokens. Na ausência de bagagem, os spans são descartados silenciosamente com a mensagem "Nenhum span com identidade de locatário/agente encontrado."

Importante

Antes que seu resolver retorne e armazene em cache o token final de Observabilidade:

  • Valide que o token é somente de aplicativo. Aceite idtyp=app. Se idtyp estiver ausente, aceite apenas um token que tenha uma claim não vazia roles ou uma claim não vazia oid igual a sub. Rejeite tokens que tenham uma scp declaração ou outro valor idtyp.
  • Verifique se aud é 9b975845-388f-4429-889e-eab1ef63949c ou api://9b975845-388f-4429-889e-eab1ef63949c, e se o token não está expirado.
  • Nunca envie a asserção intermediária do blueprint, um token de blueprint ou um token de usuário ou OBO para a Observabilidade.
  • Armazene o token final em cache e atualize-o antes que expire. O exportador chama o resolver uma vez para cada identidade de tenant e agente em cada lote de exportação.

Para implementações completas que utilizam a distro, veja os samples do Agent 365 para Node.js, Python e .NET.

Mecanismo personalizado usando o OBO

Os agentes de mecanismo customizado usam registros de aplicativo padrão com conexões OAuth do Azure Bot, não a cadeia de identidade agêntica. Usando o OBO, o agente obtém um token de usuário por meio de Azure Bot OAuth que já está no escopo da API de observabilidade do A365 pelo Serviço de Token do Bot Framework. Uma única chamada a getToken ou GetTurnTokenAsync retorna o token no escopo correto, portanto você não precisa de exchangeToken.

Pré-requisitos

Registro do aplicativo Microsoft Entra com permissões de API delegadas. Adicionar Agent365.Observability.OtelWrite (Delegado) e conceder consentimento do administrador.

Importante

O agentId no cache de token deve corresponder ao ID do cliente do registro do aplicativo, e não ao agenticAppId da atividade, que não existe para agentes de mecanismo personalizados. A URL de exportação inclui o agentId, e uma incompatibilidade causa HTTP 403.

Etapa 1: Configuração de ambiente e aplicativo

Os exemplos a seguir mostram como configurar seu aplicativo e ambiente de runtime, incluindo valores de conexão de serviço, configurações de locatário e cliente e mapeamentos de autorização necessários.

# .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

Importante

load_configuration_from_env converte todas as chaves das variáveis de ambiente em maiúsculas. O nome do manipulador passa a ser OBOCONNECTIONPROFILE e você deve referenciá-lo com essa capitalização exata nas chamadas auth_handlers e get_token(). A ausência de TYPE causa Auth handler ... not recognized or not configured em tempo de execução.

Etapa 2: Configurar a distribuição para OBO

Os exemplos a seguir mostram como habilitar a exportação do Agent 365, manter o exportador no endpoint OBO e registrar um TokenResolver personalizado que retorna tokens delegados durante a exportação.

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

O modo OBO requer jwt_authorization_middleware em aiohttpApplication (valida o JWT recebido (JSON Web Token) do Bot Framework). O caminho S2S/emulador não deve incluir esse middleware.

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

Etapa 3: Adquirir o token OBO

Os exemplos a seguir mostram como solicitar um token OBO delegado da conexão Azure Bot OAuth configurada e, em seguida, armazená-lo em cache por cliente de aplicativo e locatário para o exportador.

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

Importante

Pré-requisito do portal do Azure: Defina os Scopes para a conexão OAuth do Azure Bot chamada oboConnectionProfile para api://9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite. Sem essa configuração, o token tem como escopo o próprio público-alvo do bot (api://botid-...) e a exportação falha com HTTP 401 InvalidAudience.

Note

AGENT_APP.auth.get_token() retorna o token corretamente escopado diretamente – nenhuma exchange_token() chamada é necessária. O Serviço de Token do Bot Framework manipula a troca de OBO quando o escopo da conexão OAuth tem como destino o recurso de observabilidade do A365.

Motor personalizado com S2S

Agentes de mecanismo personalizados podem usar S2S (credenciais do cliente) para obter um token somente de aplicativo usando as credenciais de conexão do serviço. Esse método usa credenciais padrão de cliente MSAL – não precisa de uma cadeia de identidade agentic.

Pré-requisitos

  • Registro de aplicativos do Microsoft Entra: O registro do aplicativo deve ser um aplicativo de mecanismo personalizado (padrão). Os registros de aplicativo com o Agent 365 habilitado não podem usar apenas client_credentials para o recurso de observabilidade (AADSTS82001).
  • Permissões de aplicação: Adicionar Agent365.Observability.OtelWrite (Aplicação, não Delegado) e conceder consentimento de administrador. Os registros padrão de aplicativos não são instâncias de agente registradas no Agent 365, então eles precisam desse papel de aplicativo na rota S2S.

Importante

O agentId que você usa para cache deve ser o ClientId do ServiceConnection. A URL de exportação é /observabilityService/tenants/{tenantId}/otlp/agents/{agentId}/traces : uma incompatibilidade causa HTTP 403.

Etapa 1: Configuração de ambiente e aplicativo

Os exemplos a seguir mostram como configurar seu aplicativo e ambiente de runtime, incluindo valores de conexão de serviço, configurações de locatário e cliente e mapeamentos de autorização necessários.

# .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

Etapa 2: Configurar a distribuição para S2S

Os exemplos a seguir mostram como habilitar a exportação do Agent 365, definir o exportador para usar o endpoint S2S e registrar um TokenResolver personalizado para busca de token durante a exportação.

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,
)

Etapa 3: Adquirir o token S2S

Os exemplos a seguir mostram como solicitar um token de acesso somente para aplicativo para o recurso de observabilidade ao usar as credenciais da conexão de serviço e, em seguida, armazená-lo em cache por agente e por locatário para o exportador.

# 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

Etapa 4: Definir baggage para exportação de spans

O exportador Agent365 exige bagagem (ID do tenant e ID do agente) no contexto do span. Sem essa bagagem, o exportador dropa spans e registra a mensagem 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])