人工智能

ServiceNow 借助 Bedrock AgentCore Gateway 实现代表用户(OBO)的 token 交换

代表用户与企业 API 交互的 AI 智能体需要在整条请求链中保持用户身份。如果没有身份传递,API 调用到达下游服务时会以应用程序本身而非发起操作的用户身份出现。这会破坏审计追踪、绕过用户级访问控制,并违反最小权限原则。

Amazon Bedrock AgentCore 是一个用于大规模构建、连接和优化智能体的平台,支持任意框架或模型。本文介绍如何配置 Amazon Bedrock AgentCore Gateway(Amazon Bedrock AgentCore 的一项能力),用于与 Microsoft Entra ID 进行代表用户(OBO)的 token 交换。随后,AI 智能体便可调用 ServiceNow REST API 同时保留调用用户的身份。你在网关目标上配置 token 交换,AgentCore Gateway 会在每次请求时执行交换。该模式可应用于其他由 OAuth 保护的 REST API。

在生产环境中,你还可以将身份传递与 Amazon Bedrock Guardrails 配合使用,以过滤有害内容并验证智能体的输入和输出。

解决方案概述

该架构包含三个关键组件,它们通过 AgentCore Gateway 连接:

  1. 一个 AI 智能体应用,通过 OAuth 应用程序注册受 Microsoft Entra ID 保护。
  2. 一个模型上下文协议(MCP)服务器,使用 AgentCore Gateway 实现,位于智能体与 ServiceNow 之间。
  3. ServiceNow REST API,配置了与 Microsoft Entra ID 关联的入站 OAuth 集成。

下图展示了端到端解决方案架构,包括 AWS、Microsoft Entra ID 和 ServiceNow 中的组件。

Solution architecture showing the agent, AgentCore Gateway, Microsoft Entra ID, and ServiceNow and the token flow between them

图 1:跨 AWS、Microsoft Entra ID 和 ServiceNow 的解决方案架构

如图 1 所示,用户获取 JSON Web Token(JWT)以调用智能体 1。智能体使用作用域限定为其自身应用程序注册的 JWT token 向网关进行身份验证 2。随后,网关使用 OBO 流程将该 token 交换为作用域限定为 ServiceNow API connector 的新 token,并保留原始用户的身份 3。ServiceNow 收到一个有效 token,其 preferred_username 声明映射到现有的 ServiceNow 用户,并将该用户的权限应用于 API 调用 4。

在此场景中,OBO token 交换是如何工作的

当智能体调用网关时,它会出示一个带有 audience 与智能体客户端 ID 匹配的声明(例如, 3ff88e17-XXXX-XXXX-XXXX-XXXXXXXXXXXX)。然而,ServiceNow 期望的 token 带有一个 audience 声明与其自身的 API connector 客户端 ID 相匹配(5d4a7a11-XXXX-XXXX-XXXX-XXXXXXXXXXXX).

OBO 流程弥合了这一差距。AgentCore Gateway 将入站 token 连同智能体应用程序的客户端凭证、目标作用域以及一个参数发送到 Entra token 端点。 requested_token_use: on_behalf_ofEntra 验证调用用户已同意该委派,然后为 ServiceNow API 签发一个新 token,并保留原始用户的声明不变。

先决条件

开始之前,你需要准备以下内容:

  • 一个可访问 AgentCore Gateway 的 AWS 账户。
  • 一个具有创建权限的 Microsoft Entra ID 租户 应用程序注册你的账户至少需要具备 应用程序开发者角色 以注册应用程序。
  • 具有管理访问权限、可配置入站 OAuth 集成的 ServiceNow 实例。你可以在 ServiceNow 个人开发者实例注册页面创建 ServiceNow 个人开发者实例(PDI) https://developer.servicenow.com/.
  • 两个 Entra 应用程序注册:一个代表 AI 智能体,另一个代表 ServiceNow API connector。

配置 Microsoft Entra ID

首先创建一个应用程序注册,用于表示 ServiceNow API connector。以下截图显示了 Microsoft Entra ID 中 ServiceNow API Connector 的应用程序注册页面。

Microsoft Entra application registration page for the ServiceNow API connector application

图 2:在 Microsoft Entra ID 中为 ServiceNow API connector 进行应用程序注册

创建完成后,在“概述”页面记下 应用程序(客户端)ID。

在导航菜单中展开“ 管理 并选择“ 公开 API ,并使用默认的应用程序 ID URI。此作用域正是 OBO 流程在交换 token 时所请求的。以下截图展示了如何在 Microsoft Entra ID 中公开 API。图 3:在 Microsoft Entra ID 中公开 user_impersonation 作用域接下来,为 AI 智能体创建一个应用程序注册。以下截图显示了 Microsoft Entra ID 中 ServiceNow Agent 应用程序的应用程序注册页面。图 4:在 Microso 中为 ServiceNow Agent 进行应用程序注册 user_impersonation 使用默认的应用程序 ID URI。此作用域正是 OBO 流程在交换 token 时所请求的。以下截图展示了如何在 Microsoft Entra ID 中公开 API。

Expose an API page in Microsoft Entra ID with the user_impersonation scope added

图 3:在 Microsoft Entra ID 中公开 user_impersonation 作用域

接下来,为 AI 智能体创建一个应用程序注册。以下截图显示了 Microsoft Entra ID 中 ServiceNow Agent 应用程序的应用程序注册页面。

Microsoft Entra application registration page for the ServiceNow Agent application

图 4:在 Microsoft Entra ID 中为 ServiceNow Agent 进行应用程序注册

记下 ServiceNowAgent 的应用程序(客户端)ID。

在此注册上创建客户端密码。网关需要这些凭据来执行 OBO 交换。以下截图展示了如何在 Microsoft Entra ID 中为 ServiceNow Agent 应用程序注册创建客户端密码。

Certificates and secrets page showing a new client secret on the ServiceNow Agent registration

图 5:在 ServiceNow Agent 应用程序注册上创建客户端密码

然后配置该智能体应用程序,使其具有调用 ServiceNow API connector 应用程序的 API 权限。以下截图显示了您需要在 Microsoft Entra ID 中为 ServiceNow Agent 应用程序注册配置的 API 权限。

API permissions page granting the agent application access to the ServiceNow API connector

图 6:Microsoft Entra ID 中的 API 权限配置

除了为两个应用程序之间的任何标准 OBO 集成所做的设置之外,无需对 Entra 配置进行任何更改。

配置 ServiceNow

在 ServiceNow 管理控制台中,导航到 系统 OAuth > 入站集成 并创建一个新的入站集成(由支持 OIDC 的身份提供方签发的第三方 ID token)。指定你在 Entra 中创建的 ServiceNow API connector 应用程序注册中的客户端 ID。以下截图展示了 ServiceNow 中入站集成的配置。

ServiceNow inbound integration configured with the API connector client ID

图 7:在 ServiceNow 中配置入站集成

在同一屏幕中,创建一个新的 OpenID Connect (OIDC) 提供方配置,并输入你的 Entra 租户的 OIDC 元数据 URL。将用户声明映射到相应的用户字段。例如,如果你的 Entra 租户将用户的电子邮件放在 preferred_username 声明,将其映射到 电子邮件 字段。如果你的 Entra 租户不在令牌中包含 JTI,请清除 JTI 验证。Entra 使用一个名为 uti 所签发令牌上的声明,这相当于 JTI。考虑将此 uti 声明 jti 声称可提供额外的重放保护和拒绝列表。以下截图展示了如何在 ServiceNow 中配置 OIDC 提供方。

ServiceNow OIDC provider configuration with the Entra metadata URL and claim mapping

图 8:在 ServiceNow 中配置 OAuth OIDC 提供方

最后,在同一屏幕中,为该集成创建一个授权范围(例如, APIConnector)。以下截图展示了如何在 ServiceNow 中创建新的授权范围。

ServiceNow auth scope creation form for the integration

图 9:在 ServiceNow 中创建新的授权范围

将授权范围限制为 Table API,或你的智能体需要访问的任何 ServiceNow API,如下图所示。

ServiceNow auth scope limited to the Table API

图 10:在 ServiceNow 中将授权范围限制为 Table API

完成此配置后,ServiceNow 将接受带有 audience 的 API connector 客户端 ID,并根据 preferred_username 声明解析调用用户。

配置 AgentCore Gateway

在配置好 Entra 和 ServiceNow 之后,你现在可以设置 AgentCore Gateway,以原生方式处理 OBO 交换。

步骤 1:创建出站身份验证配置

创建新的出站身份验证配置(选择 构建 > 身份 > 添加出站身份验证 > 添加 OAuth 客户端)在 AgentCore 中,并选择“ 自定义提供方输入你的智能体应用注册中的客户端 ID 和客户端密钥,以及如下截图所示的 Entra 发现 URL。

AgentCore outbound auth adding an OAuth client with the agent client ID, secret, and Entra discovery URL

图 11:在 AgentCore Gateway 中添加 OAuth 客户端

展开 其他配置 并选择“ JWT 授权授予 如下图所示。这会告知网关使用基于 JWT 的授权类型进行令牌交换。

Additional configurations panel with JWT authorization grant selected

图 12:配置 JWT 授权授予

步骤 2:使用 MCP 版本 2025-11-25 创建网关

创建新的 AgentCore Gateway(构建 > 网关 > 创建网关)。在定义网关详细信息时,展开 其他配置(可选) 并选择 MCP 版本 2025-11-25,如下图所示。原生 OBO 支持需要此版本。对于使用早期 MCP 版本创建的网关,无法开启原生 OBO。图 13:选择 MCP 版本 2025-11-25使用你的智能体应用注册配置入站身份(选择“使用现有身份提供方配置”),就像对任何接受 Entra 身份验证请求的网关所做的那样。在 JWT 授权配置下,添加我们之前记录的应用程序 ID 2025-11-25 如下图所示。原生 OBO 支持需要此版本。对于使用早期 MCP 版本创建的网关,无法开启原生 OBO。

Gateway creation additional configurations with MCP version 2025-11-25 selected

图 13:选择 MCP 版本 2025-11-25

使用你的智能体应用注册配置入站身份(选择“ 使用现有身份提供方配置),就像你对任何接受 Entra 身份验证请求的网关所做的那样。

在 JWT 授权配置 添加我们之前记录的应用程序 ID,用于 ServiceNowAgent 如下图所示。

JWT authorization configuration with the ServiceNowAgent application ID added as inbound identity

图 14:在 AgentCore Gateway 中配置入站授权

步骤 3:添加一个带令牌交换的目标

向网关添加一个指向你的 ServiceNow REST 端点的目标。以内联方式定义 schema。例如,要公开一个名为 ListIncidents、用于调用 ServiceNow Table API 的工具,你可以使用以下 OpenAPI 规范(将服务器 URL 替换为你的 PDI 对应的 URL)。

{
  "openapi": "3.0.0",
  "info": {
    "title": "ServiceNow Incident API (Minimal)",
    "description": "A subset of the ServiceNow Table API for listing incident records.",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://devxxx.service-now.com/api/now/table",
      "variables": {
        "instance": {
          "default": "devxxx",
          "description": "Your ServiceNow instance name."
        }
      }
    }
  ],
  "paths": {
    "/incident": {
      "get": {
        "operationId": "getIncidents",
        "summary": "List incidents",
        "description": "Retrieves a list of incident records from the ServiceNow instance.",
        "parameters": [
          {
            "name": "sysparm_limit",
            "in": "query",
            "description": "Maximum number of records to return.",
            "schema": {
              "type": "integer",
              "default": 10
            }
          },
          {
            "name": "sysparm_query",
            "in": "query",
            "description": "An encoded query string to filter results (e.g., active=true).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sysparm_fields",
            "in": "query",
            "description": "A comma-separated list of fields to return.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A successful response containing an array of incidents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "result": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Incident"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid credentials."
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "schemas": {
      "Incident": {
        "type": "object",
        "properties": {
          "sys_id": {
            "type": "string",
            "description": "Unique identifier for the incident."
          },
          "number": {
            "type": "string",
            "description": "Incident ID (e.g., INC0000001)."
          },
          "short_description": {
            "type": "string",
            "description": "A brief summary of the incident."
          },
          "severity": {
            "type": "string",
            "description": "The severity level of the incident."
          },
          "state": {
            "type": "string",
            "description": "The current state of the incident (e.g., New, In Progress, Closed)."
          },
          "sys_created_on": {
            "type": "string",
            "format": "date-time",
            "description": "The timestamp when the incident was created."
          }
        }
      }
    }
  }
}

以下截图展示了如何在 AgentCore Gateway 中使用 OpenAPI schema 配置 REST API 目标。

AgentCore Gateway target configured with the ServiceNow OpenAPI schema defined inline

图 15:使用 ServiceNow OpenAPI schema 配置 REST API 目标

对于 出站身份验证配置 在目标上,选择 OAuth 作为出站身份提供方,并选择你在步骤 1 中创建的出站身份验证配置。

现在展开“ 其他配置 部分,然后选择“ 令牌交换授权。配置以下内容:

作用域: api://5d4a7a11-xxxx-xxxx-xxxx-xxxxxxxxxxxx/user_impersonation

这是你在 Entra 中为 ServiceNow API connector 应用程序注册所公开的作用域。

自定义参数(键值对): requested_token_use:on_behalf_of

此参数至关重要。缺少它,Entra 就不会执行 OBO 交换,对 ServiceNow 的调用将因身份验证错误而失败。

最终配置如下图所示。

Outbound auth token exchange grant with the user_impersonation scope and requested_token_use custom parameter

图 16:AgentCore Gateway 目标上的令牌交换授权配置

步骤 4:保存并测试

保存目标配置。AgentCore Gateway 现在会自动将入站令牌交换为有效的 ServiceNow 令牌,保留用户身份,无需自定义代码。

当智能体调用网关时,以下过程会透明地发生:

  1. 网关接收智能体的 JWT(audience:智能体客户端 ID)。
  2. 网关使用 OBO 授权类型将令牌发送到 Entra 的令牌端点。
  3. Entra 签发一个新令牌(audience:ServiceNow API connector 客户端 ID),并保留原始用户的声明。
  4. 网关使用交换后的令牌将请求转发到 ServiceNow。
  5. ServiceNow 从令牌中解析出用户,并应用其权限。

以下代码片段展示了一个通过 MCP 服务器与 ServiceNow 交互的最小聊天智能体。

import sys
import strands
from strands.models import BedrockModel
from strands.tools.mcp import MCPClient
from mcp.client.streamable_http import streamablehttp_client

token = sys.argv[1] if len(sys.argv) > 1 else sys.exit("Usage: python snow_agent.py <TOKEN>")
MCP_URL = "<GATEWAY_URL>"
mcp_client = MCPClient(lambda: streamablehttp_client(url=MCP_URL, headers={"Authorization": f"Bearer {token}"}))
agent = strands.Agent(
    model=BedrockModel(model_id="global.anthropic.claude-sonnet-4-6", streaming=False),
    system_prompt=(
        "You have a tool called 'target-snow___getIncidents'. "
        "When asked about incidents, call it immediately with no parameters. "
        "Never ask the user for credentials or instance details --- the tool is pre-configured."
    ),
    tools=[mcp_client],
)

while (user_input := input("\nYou: ")).lower() not in ("quit", "exit", "q"):
    print(f"\nAgent: {agent(user_input)}")

故障排查

如果你从 ServiceNow 收到身份验证错误,请验证以下各项:

  • 以下 preferred_username 交换后令牌中的声明映射到 ServiceNow 中的有效用户邮箱。
  • ServiceNow 入站集成上的授权作用域允许访问你的智能体所调用的 API 端点。
  • 该智能体应用程序在 Entra 中拥有对 ServiceNow API connector 应用程序的 API 权限。

清理

如果你为测试创建了以下资源,请将其删除,以避免产生持续费用:

  • AgentCore Gateway 及其目标。
  • 出站身份验证配置。
  • Entra 应用程序注册(如果专为本演练创建)。
  • ServiceNow 入站集成和 OIDC 提供程序配置。

结论

AgentCore Gateway 原生支持 OBO,无需再使用自定义 AWS Lambda 拦截器来执行令牌交换。你可以直接在网关目标上配置令牌交换,网关会在每次请求时透明地处理。这种方法在智能体到 API 的整个链路中保持用户身份,支持 ServiceNow 的用户级访问控制,并消除了需要单独维护的自定义代码。

要开始使用 AgentCore Gateway,请参阅 Amazon Bedrock AgentCore 文档有关 Microsoft Entra 的 OBO 流程的更多信息,请参阅 Microsoft 身份平台文档.


关于作者