可観測性認証のセットアップ

エージェント 365 エクスポーターでは、テレメトリをエクスポートするときに認証を行うためにトークン リゾルバーが必要です。 このガイドでは、Microsoft 365 エージェント SDK を使用して構築されたエージェントのセットアップについて説明します。エージェント 365 対応エージェントとカスタム エンジン エージェントの両方を、.NET、Python、および Node.jsにわたってカバーします。

ディストリビューションのインストール、一般的な構成、およびエージェント以外の SDK シナリオについては、「Microsoft OpenTelemetry Distroを参照してください。

Overview

エージェントの種類とトークンの取得方法に応じて、4 つの認証シナリオがあります。 トークンの取得には、On-Behalf-Of フロー (OBO) または Service-to-Service (S2S) を使用できます。 セットアップに一致するシナリオを選択します。

Scenario Description
OBO を使用したエージェント 365 対応 ディストリビューションの組み込み AgenticTokenCache は、委任フローでのトークン取得を自動的に処理します。 カスタム リゾルバーは不要です。 このルートには委任された Agent365.Observability.OtelWrite 権限と管理者の同意が必要ですが、a365 setup all ではブループリント エージェント用に構成していません。
S2S を使用したエージェント 365 対応 エージェントはgetAgenticApplicationToken + Microsoft認証ライブラリ(MSAL) agentic ID チェーンを使ってアプリ専用トークンを取得します。 カスタム TokenResolver とS2Sエンドポイントオプションが必要です。 登録エージェントのインスタンスはObservability権限や管理者の同意を必要としないため、 a365 setup allで設定したBlueprint Agentにはこの方法が推奨されます。
OBO を使用したカスタム エンジン エージェントは、Azure Bot OAuth を介して、可観測性 API 向けにスコープ指定されたユーザー トークンを取得します。 カスタムTokenResolver、Azure Bot OAuth 接続、そして管理者の同意が必要な委任されたAgent365.Observability.OtelWrite権限が必要です。
S2S を使用したカスタム エンジン エージェントは、クライアント資格情報を使用してアプリ専用トークンを取得します。 カスタム TokenResolverが必要です。 アプリの登録は、標準 (非エージェント) アプリである必要があります。 標準的なアプリ登録は登録済みエージェント インスタンスではないため、管理者の同意を得た Agent365.Observability.OtelWrite アプリケーション権限が必要です。

OBO を使用する Agent 365 の有効化

エージェント 365 対応エージェントは、エージェント 365 プラットフォームからエージェント ID (agenticAppId、 agenticUserId) を使用して要求を受信します。 OBOを使うことで、ディストリビューションの内蔵 AgenticTokenCache が委任フロー上でトークン取得を自動的に処理するため、カスタムトークンリゾルバは不要です。

[前提条件]

  • Microsoft Entra アプリ登録:クライアントID、クライアントシークレット、テナントIDを持つサービスプリンシパル(アプリ登録)です。

  • 委任されたAPI権限: Agent365.Observability.OtelWrite を追加 (委任) し、管理者の同意を与えます。 a365 setup allコマンドはブループリントエージェントに対してこの権限を追加しません。 グローバル管理者は以下のコマンドを実行することで追加し、管理者の同意を付与できます:

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

    Microsoft Entra 管理センターを含むその他のオプションについては、「権限を付与する」をご覧ください。

Tip

Observability権限や管理者の同意の委任を避けるには、で設定したBlueprintエージェントに対してa365 setup allを使用してください。

セットアップ

各ターンで、エージェントはターン コンテキストを使用して RegisterObservability 関数を呼び出します。 組み込みキャッシュは、 AgenticUserAuthorization ハンドラーからユーザーの委任されたトークンを使用して OBO 交換を実行し、 Agent365.Observability.OtelWriteスコープのトークンを取得します。

パッケージ、構成、コード例などの完全なセットアップ手順については、 Agent Framework アプリを使用した Agentic トークン キャッシュに関するページを参照してください。

S2S を使用したエージェント 365 対応

エージェント 365 対応エージェントは、OBO の代わりに S2S (サービス間) 認証を使用することもできます。 このパスは a365 setup allで設定したブループリントエージェントに推奨されます。 エージェントは、2 段階のエージェント ID チェーンを介して、独自のサービス プリンシパル ID を使用してトークンを取得します。

  1. getAgenticApplicationToken(tenantId, agentId)を呼び出して、Federated Managed Identity(FMI)パスでクライアントの認証トークンを取得します。
  2. アプリのトークンを acquireTokenForClient、スコープを api://9b975845-388f-4429-889e-eab1ef63949c/.default として MSAL clientAssertion を呼び出します。

Note

フェデレーション マネージド ID (FMI) は、マネージド ID がフェデレーション ID 資格情報を介してワークロード ID フェデレーションに参加し、ID 間の信頼関係に基づいてトークン交換とシークレットレス認証を有効にするアーキテクチャです。

MicrosoftのOpenTelemetryディストリビューションはデフォルトで委任ルートを使用するため、カスタム TokenResolver を指定し、使用する言語に応じて、たとえば UseS2SEndpoint = true、useS2SEndpoint: true、a365_use_s2s_endpoint=True のように S2S エンドポイント オプションを設定する必要があります。

[前提条件]

  • エージェント365の登録:エージェントのインスタンスはエージェント365に登録されている必要があります。 a365 setup allコマンドはブループリントエージェントのインスタンスを登録します。 Microsoft Entraのアイデンティティを作成するだけではエージェントインスタンスは登録されません。
  • FMI 交換用のブループリント資格情報: ブループリント クライアント シークレットまたはマネージド ID を使って、api://AzureADTokenExchange/.default の Federated Managed Identity (FMI) トークンを取得し、その後エージェント インスタンスの Observability トークンと交換します。
  • 識別値のマッチング: baggage 内のエージェント ID とテナント ID、およびエクスポート URL は、アプリのみのトークン内のエージェント インスタンス クライアント ID およびテナントと一致しなければなりません。

Note

Agent 365に登録されたエージェントインスタンスは、Agent365.Observability.OtelWrite ロールを持たないアプリ専用トークンでS2Sルートでエクスポートできます。 Observabilityの許可や管理者の同意は必要ありません。 未登録のID エンティティ (標準的なアプリ登録を含む) でも、Agent365.Observability.OtelWrite アプリ ロールと管理者の同意が引き続き必要です。

手順 1: 環境の構成

次のコード例は、カスタム S2S トークン フローを有効にする前に、必要な接続、テナント、クライアント資格情報、監視エクスポーターの環境設定を設定する方法を示しています。

AgenticUserAuthorization ハンドラーは必要ありません。 S2S では、手動エージェント ID チェーン (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: カスタム トークン リゾルバーを使用してディストリビューションを構成する

次の例では、エージェント 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 トークンを取得してキャッシュする

各受信メッセージで、エージェント ID チェーンを介して 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])

Important

S2S には、手動の 2 段階フロー (get_agentic_application_token + MSAL acquire_token_for_client) が必要です。 AgenticUserAuthorization.get_token()は、可観測性リソース5a807f24-.../.defaultではなく、api://9b975845-.../.default (Bot Framework) をスコープとするトークンを返します。S2S エンドポイントは、401 InvalidAudienceで拒否します。

  • context.activity.get_agentic_instance_id()とget_agentic_tenant_id()を使用して、アクティビティからエージェントとテナントを読み取ります (SDK 規則に従ってrecipientから読み取ります)。
  • スパンを作成する 前に 、S2S トークンを取得してキャッシュします。 ハンドラーが終了する前に、エクスポーターの BatchSpanProcessor がフラッシュされる可能性があります。トークンがまだキャッシュされていない場合、エクスポートは失敗します。
  • トークンを解決するエージェントとテナントをエクスポーターが認識できるように、すべての A365 スコープを BaggageBuilder でラップします。 バゲージがない場合、スパンは「テナント/エージェント ID を持つスパンが見つかりません」として通知なしに破棄されます。

Important

リゾルバーが最終的なObservabilityトークンを返してキャッシュする前に:

  • トークンがアプリ専用であることを検証してください。 承諾する idtyp=app。 idtypが存在しない場合は、空でないrolesクレーム、またはsubに等しい空でないoidクレームを持つトークンのみを受け入れます。 scpクレームやその他のidtyp値を持つトークンは拒否してください。
  • audが9b975845-388f-4429-889e-eab1ef63949cまたはapi://9b975845-388f-4429-889e-eab1ef63949cであり、トークンの有効期限が切れていないことを確認してください。
  • 中間ブループリントの主張、ブループリントトークン、ユーザートークンまたはOBOトークンをObservabilityに送ってはいけません。
  • 最後のトークンをキャッシュして、期限切れ前にリフレッシュしてください。 エクスポーターは各エクスポートバッチで、各テナント ID とエージェント ID ごとにリゾルバーを 1 回呼び出します。

ディストリビューションを使用した完全な実装については、Node.js、Python、.NETのAgent 365サンプルを参照してください。

OBO を使用したカスタム エンジン

カスタム エンジン エージェントは、エージェント ID チェーンではなく、Azure Bot OAuth 接続で標準アプリ登録を使用します。 OBO を使用すると、エージェントは、Bot Framework トークン サービスによって既に A365 監視 API にスコープが設定されている、Azure Bot OAuth を介してユーザー トークンを取得します。 1 つの getToken 呼び出しまたは GetTurnTokenAsync 呼び出しで正しいスコープのトークンが返されるため、 exchangeTokenは必要ありません。

[前提条件]

Microsoft Entra アプリ登録で Delegated API 権限を持つもの。 Agent365.Observability.OtelWrite(委任)を追加し、管理者の同意を付与してください。

Important

トークン キャッシュ内の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

Important

load_configuration_from_env すべての環境変数のキーを大文字に変換します。 ハンドラー名は OBOCONNECTIONPROFILE になり、auth_handlers 呼び出しと get_token() 呼び出しでは、その表記どおりの大文字/小文字で参照する必要があります。 TYPEが見つからないと、実行時にAuth handler ... not recognized or not configuredが発生します。

手順 2: OBO のディストリビューションを構成する

次の例では、エージェント 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_middlewareaiohttpでApplicationが必要です (Bot Framework からの受信 JWT (JSON Web トークン) を検証します)。 S2S/エミュレーター パスには、このミドルウェアを含めることはできません。

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

手順 3: OBO トークンを取得する

次の例では、構成された Azure Bot OAuth 接続から委任された OBO トークンを要求し、それをアプリ クライアントとエクスポーターのテナントによってキャッシュする方法を示します。

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

Important

Azure ポータルの前提条件: という名前の Azure Bot OAuth 接続の oboConnectionProfile を api://9b975845-388f-4429-889e-eab1ef63949c/Agent365.Observability.OtelWrite に設定します。 この設定がないと、トークンのスコープはボット自身の対象ユーザー (api://botid-...) になり、HTTP 401 InvalidAudienceでエクスポートが失敗します。

Note

AGENT_APP.auth.get_token() は適切なスコープのトークンを直接返すため、exchange_token() の呼び出しは不要です。 Bot Framework トークン サービスは、OAuth 接続スコープが A365 監視リソースを対象とする場合に OBO 交換を処理します。

S2S を使用したカスタム エンジン

カスタムエンジンエージェントはS2S(クライアント認証情報)を使ってサービス接続認証情報を使ってアプリ専用トークンを取得することができます。 この方法は標準的なMSALクライアント認証情報を使用しており、agentic ID チェーンは必要ありません。

[前提条件]

  • Microsoft Entraアプリの登録:アプリの登録はカスタムエンジン(標準)でなければなりません。 エージェント 365 対応アプリの登録では、監視リソース (client_credentials) にプレーンなAADSTS82001を使用することはできません。
  • アプリケーション権限: Agent365.Observability.OtelWrite を追加(アプリケーション、委任ではなく)、管理者の同意を付与します。 標準的なアプリ登録はAgent 365の登録エージェント インスタンスではないため、S2S ルートではこのアプリ ロールが必要です。

Important

キャッシュに使用するagentIdは、ServiceConnectionのでClientId。 エクスポート 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 のディストリビューションを構成する

次の例では、エージェント 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: スパン エクスポートの手荷物を設定する

Agent365のエクスポーターは、スパンのコンテキストでbaggage(テナントIDおよびエージェントID)を必要とします。 これがない場合、エクスポーターはspanを破棄し、メッセージ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])