用 Okta Cross App Access 与 Amazon Bedrock AgentCore 管控 AI 智能体访问(第 1 部分)

AWS ML Blog 2026-11-06T21:29:53.235269

当一个 AI 代理更新工单或读取客户记录时,它是在代替某个人行事,而且是在这个人有权访问的应用内操作。这时,身份团队必须回答一个按应用 OAuth 授权和共享服务账号都无法解决的问题:哪个代理可能代表哪个用户、在哪个应用中操作,以及如何阻止它。Okta Cross App Access(XAA)在身份提供方(IdP)中给出了答案。你在 Okta 中注册该代理,管理员审批它可能访问的应用,之后每次代理请求代表某个用户行事时,Okta 都会评估策略。在我们的测试中,管理员移除某个用户对代理的分配后,Okta 在大约 1 秒内拒绝了该代理针对该用户的新请求,已签发的令牌也在 5 分钟内过期。Amazon Bedrock AgentCore 是一个平台,可以用任意框架或模型大规模构建、连接和优化代理。本方案利用它的两项能力,在 AWS 上执行 Okta 的决策。Amazon Bedrock AgentCore runtime 负责验证 Okta 的授权;Amazon Bedrock AgentCore Identity 则用你的代理代码看不到的凭证,将授权兑换为短期访问令牌,并把令牌保存在它的令牌保管库中。在我们的测试中,AgentCore Identity 为一个端到端耗时约 30 秒的请求增加了约 0.6 秒。本文是两部分中的第一篇:你将在 AgentCore runtime 上构建一个任务代理,让它通过 XAA 和 AgentCore Identity 代表已登录用户行事。你会配置它所需的 AgentCore Identity 组件,在各工具中强制执行每个用户的权限,并看到我们测量的结果:每项检查会拒绝什么、我们最终采用的做法,以及 Okta 的控制措施生效有多快。第二部分则把同样的治理放到 Amazon Bedrock AgentCore Gateway 后面,结合 Cedar 策略、一个运行在 Amazon Elastic Kubernetes Service(Amazon EKS)上的第二个代理,以及在 Amazon CloudWatch 中的审计轨迹。

方案概览

Okta 是治理平面:它决定哪个代理可以代表哪个用户、针对哪个资源行事。

AgentCore Identity 是执行层:它持有智能体的凭证,把 Okta 的授权决定转换成资源方能够接受的令牌,并在这枚令牌中同时保留用户与智能体两个身份。在图 1 中,智能体以及它调用的两个 MCP(Model Context Protocol,模型上下文协议)服务器都运行在 AgentCore runtime 上。图 1:解决方案架构,图中编号与下文步骤对应。每个请求携带三枚令牌,每枚令牌记录不同的决策:ID token 表明用户是谁,Identity Assertion JWT Authorization Grant(ID-JAG)是 Okta 的授权决定,access token 则是资源方最终接受的凭证。

一次请求的流程如下:

  1. 用户通过智能体关联的 Okta 应用,以 OpenID Connect 登录 Web 前端(即 BFF,backend for frontend)。
  2. 对每个请求,BFF 在 Okta 的组织授权服务器上,以智能体身份通过 RFC 8693 令牌交换,把用户的 ID token 换成 ID-JAG。Okta 会检查三件事:智能体处于活跃状态、用户已分配给该智能体、管理员已将该智能体连接到目标授权服务器且覆盖所需 scope。ID-JAG 只能使用一次,5 分钟后失效。
  3. BFF 以 ID-JAG 作为 bearer token,调用 AgentCore runtime 上的智能体。runtime 的 JWT authorizer 只接受 Okta 签发给这个智能体的 ID-JAG。
  4. runtime 从 AgentCore Identity 获取一枚 workload access token,把智能体的 workload 身份与用户绑定,并传给智能体代码。这枚 workload access token 是 AWS 内部的绑定令牌,Okta 和资源方都看不到,因此不算在三枚令牌之内。
  5. 智能体向 AgentCore Identity 申请 access token。AgentCore Identity 以智能体身份,通过 RFC 7523 的 JWT authorization grant,在资源方的 Okta 自定义授权服务器上兑换 ID-JAG。Okta 返回一枚 5 分钟有效的 access token,其中同时标明用户和智能体,并携带用户的组信息。
  6. 智能体用这枚令牌调用 MCP 服务器。任务管理器会验证:令牌确实由已注册的智能体取得,且用户的组和 scope 允许使用该工具。

图 2 以时序图展示同一请求,并标出每一方各自执行的校验。

图 2:三令牌链以及每一方所做的校验,第 4 步的工作负载访问令牌始终留在 AWS 内部

准备工作

要跟着做,你需要:

准备工作 我们用的
一个 AWS 账号,能访问 Amazon Bedrock AgentCore,并且在美国西部(俄勒冈)区域能用上 Amazon Bedrock 里的 Anthropic Claude 模型 美国西部(俄勒冈)
一个启用了 AI 智能体跨应用访问(Cross App Access)和 API 访问管理(自定义授权服务器)的 Okta 组织 —
一个 Okta Integrator 免费版组织 —
Python、AWS 命令行工具(AWS CLI)、boto3、AgentCore CLI 和 AgentCore Python SDK(Amazon Bedrock AgentCore 的一个能力) Python 3.11、AWS CLI 2 版、boto3 1.43、AgentCore CLI 0.31.1、AgentCore Python SDK 1.24.1
AWS 身份与访问管理(IAM)权限 创建 AgentCore 资源和 IAM 角色的权限

整个演练大约需要 1 小时。AgentCore 按用量收费,详情见 Amazon Bedrock AgentCore 定价。

本方案基于 GitHub 上 AgentCore 示例仓库里的 AWS 示例 08-okta-xaa-delegation-chain,你可以在此基础上搭建文章里的方案。除该示例之外,文中给出的代码片段和配置只是概念性演示,并非完整、可直接部署的方案。这些代码是供非生产环境使用的示例代码,部署前请与安全和法务团队合作,确保满足组织的安全、监管和合规要求。

在 Okta 中注册智能体

Okta 需要为资源(也就是智能体)准备一个授权服务器,建立两者之间的连接,并制定一条允许该智能体授权的策略。以下步骤都在 Okta 管理控制台里完成:注册智能体时会自动创建它关联的应用,所以不需要走应用集成的向导。

为资源应用创建一个自定义授权服务器,受众(audience)设为 api://task-manager,自定义作用域设为 xaa:read 和 xaa:write。请求时只申请资源的自定义作用域:如果 ID-JAG 请求里带了 OpenID Connect 作用域(比如 openid 或 profile),Okta 会以 invalid_scope 拒绝,所以请求至少要包含一个自定义作用域,且不能有 OpenID Connect 作用域。在其访问令牌里加一个 groups 声明,过滤出以 xaa- 开头的组。

这个声明把每个用户的权限带给了工具。在管理控制台中,进入 Directory > AI Agents,选择 Register AI agent,再选 Register manually,可以指定一个所有者,然后创建一个关联的 OpenID Connect 应用。在 Client registration 中选择 Client secret,生成密钥,然后激活代理。代理和应用共用一个客户端 ID,而且必须由这个应用来完成用户登录:如果使用另一个应用签发的 ID 令牌,交换就会失败,并报错“the client application is not registered for delegation to this agent”。在代理的 Resource connections 标签页中,把它连接到授权服务器,只授予它需要的权限范围,如图 3 所示。给自定义授权服务器添加一条访问策略规则,允许代理使用 JWT 持有者授权(JWT Bearer grant),访问令牌有效期设为 5 分钟。如果没有配置这个授权类型,第二次交换会失败,报错 no_matching_policy;而有效期则决定了被撤销的委派还能继续生效多久。然后分配可能通过该代理行事的用户或组。这些用户通过关联应用登录,所以需要给这个应用配置一条登录策略,允许他们用自己已注册的认证方式登录。在我们的沙箱组织中,关联应用有自己的策略,其中有一条针对测试组的规则。对于真实用户,应沿用贵组织的策略,包括多因素认证。

图 3:任务代理在 Okta 中的资源连接,权限范围限定为 xaa:read 和 xaa:write

Okta 的 Cross App Access 指南覆盖了这些控制台操作步骤,而 AWS 示例 08-okta-xaa-delegation-chain 则用脚本配置授权服务器及其 JWT 持有者策略。接着,BFF 以代理身份通过认证,请求 ID-JAG:

POST /oauth2/v1/token HTTP/1.1
Host: YOUR-ORG.okta.com

Authorization: Basic <the agent's client ID and secret>

Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange

&requested_token_type=urn:ietf:params:oauth:token-type:id-jag

&subject_token=<the user's ID token>

&subject_token_type=urn:ietf:params:oauth:token-type:id_token

&audience=https://YOUR-ORG.okta.com/oauth2/YOUR-CUSTOM-AS-ID

&scope=xaa:read xaa:write

AWS 的示例代码 06-okta-xaa 用 Python 发送了同样的请求,见 agent/xaa_client.py。由于 BFF(Backend for Frontend,面向前端的后端服务)是以 AI agent 的身份做认证,agent 的 client secret 应该放在 AWS Secrets Manager 里,而不是写进代码或配置文件。

配置 AgentCore Identity

这套方案里,AgentCore Identity 负责保管三样东西。你的 agent 代码既看不到 client secret,也不需要调用 Okta 的令牌端点:

AgentCore Identity 的组成部分 它保管的内容 由谁创建
工作负载身份(Workload identity) agent 在 AWS 上的身份,每次请求都会绑定到当前登录用户 AgentCore 运行时,按每个 agent 运行时创建
OAuth2 凭证提供方(credential provider) agent 的 Okta client ID 和 secret,以及要使用的授权类型 由你创建,每个 Okta agent 一次
令牌保险库(Token vault) 凭证提供方换回来的访问令牌 AgentCore Identity

创建凭证提供方

第二次令牌交换由凭证提供方完成。把它指向自定义授权服务器,以 AI agent 的身份认证,并把代表用户换取令牌的授权类型设为 JWT_AUTHORIZATION_GRANT。AgentCore Identity 会以 jwt-bearer 方式发起请求,把 ID-JAG 作为断言(assertion)发出去:

control = boto3.client("bedrock-agentcore-control")

provider = control.create_oauth2_credential_provider(
    name="okta-xaa-obo",
    credentialProviderVendor="CustomOauth2",
    oauth2ProviderConfigInput={"customOauth2ProviderConfig": {
        "oauthDiscovery": {"discoveryUrl": f"{OKTA_ORG}/oauth2/{CUSTOM_AS_ID}/.well-known/openid-configuration"},
        "clientId": AGENT_CLIENT_ID,          # the AI agent's Okta client ID
        "clientSecret": AGENT_CLIENT_SECRET,  # AgentCore Identity stores it in AWS Secrets Manager
        "clientAuthenticationMethod": "CLIENT_SECRET_BASIC",
        "onBehalfOfTokenExchangeConfig": {"grantType": "JWT_AUTHORIZATION_GRANT"},
    }},
)
provider_arn = provider["credentialProviderArn"]

Okta 会把这个令牌交换绑定的 client 限制在 ID-JAG 里写明的那个 client 上,因此每个 Okta agent 都要配自己的 provider。我们试着拿一个 agent 的 ID-JAG 去换另一个 agent 的令牌时,Okta 直接拒绝,报错:「The 'client_id' in the JWT Bearer Grant must match the 'client_id' used to authenticate the client.」AgentCore Identity 会把 client secret 存在一个由服务托管的 AWS Secrets Manager 密钥里,轮换时用 update-oauth2-credential-provider 更新即可。如果你们团队已经在 Secrets Manager 里管着这个 client secret,也可以直接引用那个密钥的 ARN。AgentCore Identity 会从该密钥读取 client secret,这样轮换密钥时无需改动 provider(见《Reference your own AWS Secrets Manager secrets in Amazon Bedrock AgentCore Identity》)。若想避免共用 secret,也可以改用私钥来做认证,参见《Authenticate with Private Key JWT using Amazon Bedrock AgentCore Identity》。图 4 展示了控制台里的这个 provider。

图 4:凭证提供方使用 JWT 授权许可,以 agent 身份完成认证

使用 AgentCore runtime 托管的工作负载身份

AgentCore runtime 会为每个 agent runtime 创建并管理一个工作负载身份。请求通过 runtime 的 JWT 授权器之后,runtime 会拿到该工作负载身份的访问令牌(workload access token),以及入站令牌的签发方和主体,一并传给业务代码。AgentCore Identity 随后用它背后的 ID-JAG 作为令牌交换的断言。

AgentCore Python SDK 把这个工作负载访问令牌放在 BedrockAgentCoreContext 里,而不是放在入口函数收到的请求头中。我们最早的版本去请求头里找,自然什么都没找到,于是退回去自己调了一次 GetWorkloadAccessTokenForJWT,用上了第二个工作负载身份——我们抽查的 21 个请求全都走到了这条错路上。正确做法是从 context 里读:

from bedrockagentcore.runtime import BedrockAgentCoreContext

identity = boto3.client("bedrock-agentcore")

def okta_access_token() -> str:

    workload_token = BedrockAgentCoreContext.get_workload_access_token()  # minted by the runtime

    return identity.get_resource_oauth2_token(

        workloadIdentityToken=workload_token,
resourceCredentialProviderName="okta-xaa-obo",

scopes=["xaa:read", "xaa:write"],  # 必须与 ID-JAG 的 scopes 一致

oauth2Flow="ON_BEHALF_OF_TOKEN_EXCHANGE",

)["accessToken"]

AgentCore Identity 会把访问令牌留在自己的令牌保险库(token vault)中,供该请求后续使用。在 10 次请求中,Agent 第一次调用换取 ID-JAG 耗时约半秒(见“验证结果”中的延迟表),第二次调用针对另一个 MCP 服务器,直接返回同一个令牌,中位耗时 58 毫秒,无需再次兑换这个一次性的 ID-JAG。如果同一用户拿到新的 ID-JAG,就会获得新的令牌,因此每次请求都能反映 Okta 的最新决策。示例 08-okta-xaa-delegation-chain 用同样的方式读取工作负载访问令牌(agent/agent.py)。

将 Agent 的角色限定到其工作负载身份和提供者

AgentCore Identity 在同一账户内不会把工作负载身份与凭证提供者绑定起来。Agent 的 IAM 角色会绑定,所以要把它的权限限定到 Agent 自己的工作负载身份、提供者,以及该提供者的密钥:

[
  {
    "Sid": "OktaOnBehalfOf",
    "Effect": "Allow",
    "Action": "bedrock-agentcore:GetResourceOauth2Token",
    "Resource": [
      "arn:aws:bedrock-agentcore:us-west-2:123456789012:workload-identity-directory/default",
      "arn:aws:bedrock-agentcore:us-west-2:123456789012:workload-identity-directory/default/workload-identity/RUNTIME-WORKLOAD-IDENTITY",
      "arn:aws:bedrock-agentcore:us-west-2:123456789012:token-vault/default",
      "arn:aws:bedrock-agentcore:us-west-2:123456789012:token-vault/default/oauth2credentialprovider/okta-xaa-obo"
    ]
  },
  {
    "Sid": "ReadProviderSecret",
    "Effect": "Allow",
    "Action": "secretsmanager:GetSecretValue",
    "Resource": "arn:aws:secretsmanager:us-west-2:123456789012:secret:bedrock-agentcore-identity!default/oauth2/okta-xaa-obo-*"
  }
]

从 GetAgentRuntime 的 workloadIdentityDetails 中获取工作负载身份的名称,从 credentialProviderArn 中获取提供商的 ARN:这一段是 oauth2credentialprovider,而在使用带连字符的形式时,每次调用都会失败并报出 AccessDeniedException。该角色不需要 GetWorkloadAccessToken 权限,因为获取该令牌的是运行时,而不是代理。我们的测试仅使用这两条语句就通过了。在 AgentCore 运行时上部署代理,将代理运行时的入站授权器配置为只接受 Okta 颁发给该代理的 ID-JAG。其颁发者是 Okta 的组织授权服务器,受众是资源的自定义授权服务器。在 agentcore.json 中:

"authorizerType": "CUSTOM_JWT",

"authorizerConfiguration": {

"customJwtAuthorizer": {

"discoveryUrl": "https://YOUR-ORG.okta.com/.well-known/openid-configuration",

"allowedAudience": ["https://YOUR-ORG.okta.com/oauth2/YOUR-CUSTOM-AS-ID"],

"allowedClients": ["YOUR_AGENT_CLIENT_ID"],

"allowedScopes": ["xaa:read", "xaa:write"]

}

} allowedClients 要与 ID-JAG 中的 client_id 声明匹配。缺少它时,运行时就会以 HTTP 200 接受另一个智能体的 ID-JAG,请求随后会在交换阶段失败;有了它,运行时会以 HTTP 401 拒绝该 token。除了上一节提到的策略,执行角色还需要 bedrock:InvokeModel 和 bedrock:InvokeModelWithResponseStream。它不需要 bedrock-agentcore:InvokeAgentRuntime 权限来调用 MCP 服务器:每个 MCP 服务器都运行在 AgentCore 运行时上,位于各自的 JWT 授权器之后,以自定义授权服务器作为签发者、api://task-manager 作为受众,因此智能体调用它时使用的是 Okta 访问令牌作为 bearer token,而不是 AWS Signature Version 4 (SigV4)。

在 MCP 服务器中强制实施每个用户的权限

资源连接为某个智能体的所有用户设置了作用域,因此三个测试用户都获得了 xaa:read xaa:write;而每个用户的权限改为通过 groups 声明传递:Alice 的 token 携带 xaa-readers,Bob 的携带 xaa-writers,Carol 的则不含任何组。任务管理器检查两件事:它只接受已注册智能体获得的 token;只有当组和作用域同时存在时,才允许写入:

REGISTERED_AGENTS = {"YOUR_AGENT_CLIENT_ID"}

def _require_agent() -> None:
    claims = _decode_claims()  # 运行时的 JWT 授权器已验证过此 token
    agent = (claims.get("act") or {}).get("sub")
    if agent in REGISTERED_AGENTS and claims.get("cid") == agent:
        return
    raise ToolError("insufficient_privileges: this server accepts only tokens that a registered "
                    "AI agent obtained through Okta Cross App Access")

def _require_write() -> None:
    _require_agent()
    if WRITERS_GROUP in _groups() and "xaa:write" in _scopes():
        return
raise ToolError(f"insufficient_privileges: this tool requires membership in '{WRITERS_GROUP}'")

这两处检查,分别堵住了我们此前发现的两个漏洞。第一,原先的写入检查允许没有 groups 声明的令牌通过,结果是不属于任何组的 Carol 也能创建任务。第二,在加入 _require_agent 之前,一个用普通令牌交换(token exchange)得到、发给某个服务应用且不带 act 声明的令牌,可以为 Bob 创建任务。

服务端之所以能直接读取声明、不必再验证令牌,是因为运行时的 JWT 授权器已经验证过了。如果服务端前面没有这层授权器,就必须自行检查签名、签发方、受众和过期时间,正如第二部分中跑在 Amazon EKS 上的那个智能体所做的那样。

验证结果

我们对部署好的方案逐项做了检查。Alice、Bob 和 Carol 分别让智能体创建任务,再列出项目的任务:

调用方 create_task list_tasks
Alice 拒绝:需要属于 xaa-writers 允许
Bob 已创建 允许
Carol 拒绝:无 groups 声明 允许
先 Bob,紧接着 Alice 为 Bob 创建,随后拒绝 Alice:权限不延续 允许

下面这些请求在工具真正执行前就被拦下了:

请求 拦截环节 响应
智能体 B 发给任务智能体的 ID-JAG 运行时的 JWT 授权器 401:“Claim 'client_id' value mismatch with configuration.”
一个已持有 245 秒的 ID-JAG 运行时的 JWT 授权器 401:“Ineffectual token, will expire within the next minute”
一个格式错误的 bearer 令牌 运行时的 JWT 授权器 403:“Failed to parse token”
同一个 ID-JAG 兑换两次 Okta 的自定义授权服务器 400:“The id-jag was already used.”
第二次交换时缩小了 scope Okta 的自定义授权服务器 400:“The scope parameter must exactly match the scopes in the id-jag.”
超出连接范围的 scope Okta 的组织授权服务器 400 invalid_scope
在 MCP 服务器上使用普通令牌交换令牌 MCP 服务器 拒绝:只有已注册 AI 智能体获得的令牌才行

AgentCore Identity 返回的令牌,与我们直接在 Okta 兑换得到的令牌逐条声明都对得上:sub 是用户,cid 和 act 指向智能体,scp 包含连接的 scope,groups 对应用户所在的组,有效期为 300 秒。

AgentCore Identity 会给端到端约 30 秒的请求增加约 0.6 秒,其中大部分时间花在模型和工具调用上。下面是测试客户端运行五次的中位数:

调用 中位数
登录(脚本化的授权码流程) 1,205 ms
在 Okta 组织授权服务器把 ID token 换成 ID-JAG 216 ms
GetWorkloadAccessTokenForJWT 135 ms
GetResourceOauth2Token(含 Okta 的 JWT bearer 授权) 508 ms

运行中的代理治理

Okta 在签发 ID-JAG 时会评估代理、用户和连接三者。我们实测了每项管理员操作对下一次请求和已签发 token 的影响:

Okta 中的管理员操作 新请求 已签发的 token
删除代理的资源连接 立即拒绝(invalid_target) 继续有效直到过期,最长 5 分钟
移除用户的分配 约 1 秒内拒绝,即使用户已持有 ID token 最长 5 分钟
停用代理 Okta 执行完操作后拒绝(我们的测试组织排队了 86 分钟) 最长 5 分钟

对某个代理的操作不影响另一个代理正常工作。Okta 在兑换 ID-JAG 时不会重新检查用户:它的自定义授权服务器在我们移除某用户 3 秒后,仍为一个移除前签发的 ID-JAG 签发了访问 token。Okta 的 System Log 会把每次授权记录在案,代理作为操作者;Part 2 会把这些事件流式传输到 CloudWatch。

委派链的最佳实践

这些测量得出了六条实践。每一条都是委派链本身的属性,而不是偏好设置:

实践 我们测到的结果
每次请求都新签发一个 ID-JAG ID-JAG 一次性使用,有效期 300 秒。运行时拒绝剩余不足 60 秒的 ID-JAG,所以 225 秒可用,245 秒不行
在 groups claim 中携带按用户区分的权限,每次请求只申请一组 scope Okta 从资源连接设置 scope,所以三个用户拿到相同的 scope;第二次交换必须精确请求 ID-JAG 的……
在运行时固定代理,并在工具中检查 act 和 cid allowedClients 与 ID-JAG 携带的 client_id claim 匹配

Okta 访问令牌里携带的是 cid,而不是……

直接向 Okta 复现一次失败的令牌交换。通过 AgentCore Identity,权限范围不匹配和客户端错误都会表现为“令牌交换失败,HTTP 状态码 400”。

为代理的角色授予对提供商密钥的读取权限。在角色能够读取之前,GetResourceOauth2Token 一直失败。

保持较短的存活时间,并把资源连接当作你的“紧急开关”。删除连接会立即生效。而停用代理则在 Okta 的测试版 AI agent API 队列里排了 86 分钟,期间无法取消。

跨应用访问与普通令牌交换的对比

普通的 RFC 8693 令牌交换同样会将用户身份传递到下游。我们在同一个 Okta 授权服务器和同一个用户下,将它与 XAA 进行了对比:

观察到的行为 普通令牌交换 跨应用访问
令牌中的代理身份 无 act 声明 act 声明指明代理
权限范围 扩大:Alice 自己的令牌包含 xaa:read,交换后返回 xaa:read xaa:write 管理员批准的范围
交换规则 限定为 xaa-writers,Alice 仍能拿到令牌 Alice 被拒绝
用户未分配 复用了之前的令牌,仍能交换 拒绝
管理员看到的内容 一个带授权类型的服务应用 代理、它的连接,以及每条日志事件中的代理

这些结果反映的是我们的 Okta 配置。Okta 的指南显示交换后的令牌应包含 act 声明,但我们没有收到。普通令牌交换传递了用户身份,但没有传递用户的权限。

这种模式适用的场景

我们与媒体和娱乐公司合作,也是在这里最先遇到这个问题。一家制片厂、流媒体或游戏公司会针对制作跟踪、作品与素材元数据、版权与本地化、观众或玩家支持运行代理。每个系统都有自己的授权模型和自己的审计人员,而用户的权限因作品、地区或发行窗口而异。因此,“哪个代理可能在哪个系统中代表哪个用户行事”这个问题,必须在代理上线前得到回答。

这条链路中没有任何环节是特定于该行业的:代理是你 IdP 中的一个身份,目标是 OAuth 2.0 授权服务器,而用户的权限搭载在一个声明中。

清理

为了避免产生持续费用,请删除你创建的资源:

结论

本文用 Okta Cross App Access 决定哪个智能体可以代表哪个用户行事,再用 AgentCore Identity 落实每个决策。运行时只接受智能体自己的 ID-JAG;凭证提供方用智能体并不持有的密钥兑换每一个 ID-JAG;令牌保险库在同一次请求内复用兑换结果;MCP 服务器则根据 groups 声明执行每个用户的权限。

这套设计把令牌交换限制在智能体角色内,并在每个 MCP 服务器上重复授权检查。本系列第 2 部分会介绍:为什么新设计把这两件事都移到同一个 AgentCore Gateway 后面,并用 Cedar 策略管理;如何在 Amazon EKS 上增加第二个智能体;以及如何把 Okta System Log 与 CloudWatch 中的 AgentCore 追踪记录关联起来。

要开始上手,可以查看 AgentCore 示例和 Okta 的 Cross App Access 文档。API 细节见 AgentCore 开发者指南中的 On-behalf-of token exchange。

作者简介

Hammad Ausaf 是媒体与娱乐领域的首席解决方案架构师。他热衷于动手构建,致力于为 AWS 客户提供最佳方案。

Rajat Jain 是 AWS 媒体与娱乐领域的技术客户经理,在公司工作超过 3 年。他指导客户遵循运维最佳实践,帮助他们充分利用 AWS 服务。

Madhu Samhitha Vangara 是 AWS 的全球生成式 AI 专家解决方案架构师,负责 Amazon Bedrock AgentCore 和 Strands Agents 的智能体 AI 市场推广工作,把新兴的 AI 能力和研究成果转化为客户可衡量的业务成果。工作之外,她是一名受过专业训练的印度古典舞者,也是艺术爱好者。

AI 智能体代替用户行事时,会引出一个身份问题——针对单个应用的 OAuth 授权和服务账号都没能回答它:哪个智能体可以代表哪个用户行动,又该如何阻止它。在两篇系列文章的第一篇里,你将基于 Amazon Bedrock AgentCore 构建一个任务智能体,借助 Okta Cross App Access 和 AgentCore Identity 管控访问,并落实每个用户的权限边界。

查看原文