用 Okta Cross App Access 与 Amazon Bedrock AgentCore 治理 AI 智能体访问权限(第一部分)
Govern AI agent access with Okta Cross App Access and Amazon Bedrock AgentCore – Part 1
AWS 在 Okta Cross App Access(XAA)与 Amazon Bedrock AgentCore 的组合方案中,由 Okta 作为治理平面决定智能体可代表哪个用户访问哪个应用,AgentCore runtime 与 AgentCore Identity 负责在 AWS 侧执行校验并兑换短时效访问 token。
一个为某人更新工单或读取客户记录的 AI 智能体,是在该人可访问的应用程序内代表此人行事。此时你的身份团队必须回答一个按应用 OAuth 同意和共享服务账户都无法回答的问题:哪个智能体可能在哪个应用中代表哪个用户行事,以及你如何阻止它。Okta Cross App Access(XAA)在你的身份提供商(IdP)中回答了这个问题。你在 Okta 中注册该智能体,由管理员批准它可能访问的应用程序,并且每当智能体请求代表某用户行事时,Okta 都会评估策略。在我们的测试中,管理员移除了用户对该智能体的授权后,Okta 在大约 1 秒内就拒绝了该智能体针对该用户新的请求,而已签发的令牌在 5 分钟内过期。
Amazon Bedrock AgentCore 是一个大规模构建、连接和优化智能体的平台,支持任何框架或模型。本解决方案使用其中两项能力在 AWS 上执行 Okta 的决策。Amazon Bedrock AgentCore runtime(Amazon Bedrock AgentCore 的一项能力)验证 Okta 的授权。Amazon Bedrock AgentCore Identity(Amazon Bedrock AgentCore 的一项能力)将其兑换为短期访问令牌,且凭据对你的智能体代码不可见,并将该令牌保存在其令牌保管库中。在我们的测试中,AgentCore Identity 为一个端到端耗时约 30 秒的请求增加了约 0.6 秒。
在这两篇系列文章的第一篇中,你将在 AgentCore runtime 上构建一个任务智能体,它通过 XAA 和 AgentCore Identity 代表已登录用户行事。你将配置它所需的 AgentCore Identity 组件,在工具中强制执行每个用户的权限,并了解我们测得的结果:每项检查会拒绝什么、我们最终采用的实践,以及 Okta 的控制措施生效的速度。第 2 部分将把同样的治理机制应用于 Amazon Bedrock AgentCore Gateway(Amazon Bedrock AgentCore 的一项能力),并结合 Cedar 策略、部署在 Amazon Elastic Kubernetes Service(Amazon EKS)上的第二个智能体,以及 Amazon CloudWatch 中的审计追踪。
解决方案概述
Okta 是治理平面:它决定哪个智能体可以代表哪个用户、访问哪个资源。AgentCore Identity 是执行平面:它保管智能体的凭据,将 Okta 的决策转换为资源接受的令牌,并在该令牌中保留两种身份。在图 1 中,智能体及其调用的两个 Model Context Protocol(MCP)服务器都运行在 AgentCore runtime 上。
图 1:解决方案架构,编号与后续步骤一一对应
每个请求携带三个令牌,每个令牌记录不同的决策:ID 令牌说明用户是谁,Identity Assertion JWT Authorization Grant(ID-JAG)是 Okta 的决策,访问令牌则是资源所接受的内容。一个请求的流程如下:
- 用户通过智能体关联的 Okta 应用,使用 OpenID Connect 登录到 Web 前端(一个 backend for frontend(BFF))。
- 对于每个请求,BFF 以智能体的身份在 Okta 的组织授权服务器上将用户的 ID 令牌交换为 ID-JAG(RFC 8693 令牌交换)。Okta 会检查智能体是否处于活动状态、用户是否已分配给它,以及管理员是否已将其连接到目标授权服务器以获取所请求的权限范围。ID-JAG 为一次性使用,5 分钟后过期。
- BFF 以 ID-JAG 作为持有者令牌在 AgentCore runtime 上调用智能体。runtime 的 JWT 授权器仅接受 Okta 签发给该智能体的 ID-JAG。
- 运行时会从 AgentCore Identity 获取一个工作负载访问令牌,该令牌将智能体的工作负载身份与用户绑定,并将其传递给智能体代码。这个工作负载访问令牌是 AWS 内部的绑定令牌:Okta 和资源都看不到它,因此它不属于那三个令牌。
- 智能体向 AgentCore Identity 请求访问令牌。AgentCore Identity 以智能体的身份,使用 JWT 授权许可(RFC 7523)在资源的 Okta 自定义授权服务器上兑换 ID-JAG。Okta 返回一个有效期为 5 分钟的访问令牌,其中同时标明用户和智能体,并携带用户的用户组。
- 智能体使用该令牌调用 MCP 服务器。任务管理器会检查该令牌是否由已注册的智能体获取,以及用户的用户组和权限范围是否允许使用该工具。
图 2 以时序形式展示了同一请求,以及各方所做的检查。
图 2:三令牌链及各方的检查,其中第 4 步的工作负载访问令牌始终留在 AWS 内部
前提条件
要按照本文操作,你需要满足以下条件:
| 前提条件 | 我们使用的环境 |
| 一个可以访问 Amazon Bedrock AgentCore 以及 Amazon Bedrock 中 Anthropic Claude 模型的 AWS 账户 | 美国西部(俄勒冈) |
| 一个启用了面向 AI 智能体的 Cross App Access 和 API Access Management(自定义授权服务器)的 Okta 组织 | 一个 Okta Integrator Free Plan 组织 |
| Python、AWS Command Line Interface(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 Identity and Access Management(IAM)权限 | 创建 AgentCore 资源和 IAM 角色的权限 |
本演练大约需要 1 小时。AgentCore 按使用量收费。请参阅 Amazon Bedrock AgentCore 定价。
本解决方案的基础是 GitHub 上 AgentCore 示例仓库中的 AWS 示例 08-okta-xaa-delegation-chain,你可以在此之上构建本文中的解决方案。除了该示例之外,本文中的代码片段和配置仅从概念上展示该模式,并不是一个完整、可直接部署的解决方案。这些代码是供非生产环境使用的示例代码,因此在部署之前,请与你的安全和法务团队合作,以满足贵组织的安全、监管和合规要求。
在 Okta 中注册智能体
Okta 需要为资源提供一个授权服务器、一个智能体、两者之间的连接,以及一条允许该智能体授权许可的策略。所有这些步骤都在 Okta Admin Console 中完成:注册智能体会自动创建其关联的应用,因此你不需要使用应用集成向导。
- 为资源应用创建一个自定义授权服务器,受众为
api://task-manager,自定义权限范围为xaa:read和xaa:write。只请求资源的自定义权限范围:Okta 会拒绝包含 OpenID Connect 权限范围(例如openid或profile)的 ID-JAG 请求(invalid_scope),因此请求中必须至少包含一个自定义权限范围,且不得包含任何 OpenID Connect 权限范围。 - 在其访问令牌中添加一个
groups声明,并过滤为以xaa-开头的用户组。该声明将每位用户的权限传递给工具。 - 在管理控制台中,进入 Directory > AI Agents,选择 Register AI agent,然后选择 Register manually,可选择指派一个所有者,并创建一个关联的 OpenID Connect 应用。在 Client registration 页面,选择 Client secret,生成一个密钥,然后激活该智能体。智能体和应用共享同一个 client ID,且该应用必须用于用户登录:来自其他应用的 ID 令牌在交换时会失败,报错“the client application is not registered for delegation to this agent.”
- 在该智能体的 Resource connections 标签页上,将其连接到授权服务器,并限制为它所需的范围(scope),如图 3 所示。
- 为自定义授权服务器添加一条访问策略规则,允许该智能体的 JWT Bearer 授权,并将访问令牌的有效期设为 5 分钟。如果没有该授权类型,第二次交换会失败,如
no_matching_policy所示;而有效期则限制了被撤销的委托还能继续生效多久。 - 指派可能通过该智能体进行操作的用户或群组。他们通过关联的应用登录,因此要为其配置一个应用登录策略,允许他们使用已注册的身份验证器登录。在我们的沙箱组织中,关联的应用拥有自己的策略,其中包含针对测试群组的一条规则。对于真实用户,请应用贵组织的策略,包括多因素身份验证。
图 3:Okta 中任务智能体的资源连接,仅限于 xaa:read 和 xaa:write 范围
Okta 的 Cross App Access 指南涵盖了控制台中的操作步骤,而 AWS 示例 08-okta-xaa-delegation-chain 则以脚本方式配置了授权服务器及其 JWT bearer 策略。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:writeAWS 示例 06-okta-xaa 用 Python 发送同样的请求(agent/xaa_client.py)。BFF 以该智能体的身份进行认证,因此应将该智能体的 client secret 存放在 AWS Secrets Manager 中,而不是放在代码或配置文件里。
设置 AgentCore Identity
AgentCore Identity 为本方案保存三样东西,而你的智能体代码既看不到 client secret,也不用调用 Okta 的令牌端点:
| AgentCore Identity 的组成部分 | 它保存的内容 | 由谁创建 |
| 工作负载身份 | 该智能体在 AWS 上的身份,在每个请求中与已登录用户绑定 | AgentCore runtime,为每个智能体运行时创建 |
| OAuth2 凭证提供程序 | 该智能体在 Okta 的 client ID 和 secret,以及要使用的授权方式 | 你,每个 Okta 智能体创建一次 |
| 令牌保管库 | 该凭证提供程序获取的访问令牌 | AgentCore Identity |
创建凭证提供程序
凭证提供程序执行第二次交换。将其指向自定义授权服务器,以该 AI 智能体的身份进行认证,并将代表授权(on-behalf-of grant)设置为 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 将两次交换都绑定到 ID-JAG 中指定的客户端,因此每个 Okta 智能体都需要自己的 provider:当我们将一个智能体的 ID-JAG 换作另一个智能体去兑换时,Okta 拒绝并报错“JWT Bearer Grant 中的 ‘client_id’ 必须与用于验证客户端的 ‘client_id’ 匹配”。AgentCore Identity 将密钥保存在一个由服务托管的 AWS Secrets Manager 密钥中,你可以用 update-oauth2-credential-provider 来轮换它。如果你的团队已经在 Secrets Manager 中管理该客户端密钥,你可以改为引用该密钥的 ARN。AgentCore Identity 会从中读取客户端密钥,因此你可以在不更新 provider 的情况下轮换密钥(参见 在 Amazon Bedrock AgentCore Identity 中引用你自己的 AWS Secrets Manager 密钥)。为避免共享密钥,可以改用私钥进行身份验证。参见 使用 Amazon Bedrock AgentCore Identity 通过私钥 JWT 进行身份验证。图 4 展示了 AgentCore 控制台中的该 provider。
图 4:使用 JWT 授权许可(JWT authorization grant)以智能体身份进行验证的凭证 provider
使用 AgentCore runtime 所管理的工作负载身份
AgentCore runtime 会为每个智能体运行时创建并管理一个工作负载身份。当请求通过 runtime 的 JWT 授权器时,runtime 会为该工作负载身份以及入站令牌的签发者和主体 获取一个工作负载访问令牌,并将其传递给你的代码。随后,AgentCore Identity 使用其背后的 ID-JAG 作为交换的断言。
AgentCore Python SDK 将工作负载访问令牌保存在 BedrockAgentCoreContext 中,而不是你的入口点所接收的请求头中。我们的第一个版本在请求头中查找它,什么都没找到,于是回退到它自己带第二个工作负载身份的 GetWorkloadAccessTokenForJWT 调用,在我们检查的全部 21 个请求上都是如此。应改为从上下文中读取它:
from bedrock_agentcore.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"], # must equal the ID-JAG's scopes
oauth2Flow="ON_BEHALF_OF_TOKEN_EXCHANGE",
)["accessToken"]AgentCore Identity 会在该请求的剩余时间内将访问令牌保存在其令牌保管库中。在 10 个请求中,智能体的第一次调用大约半秒钟就兑换了 ID-JAG(参见验证结果中的延迟表),而针对另一个 MCP 服务器的第二次调用以中位数 58 毫秒返回了同一个令牌,且没有再次兑换该一次性 ID-JAG。为同一用户新建的 ID-JAG 会得到一个新令牌,因此每个请求都反映 Okta 的最新决定。示例 08-okta-xaa-delegation-chain 以同样的方式读取工作负载访问令牌(agent/agent.py)。
将智能体的角色限定到其工作负载身份和 provider
AgentCore Identity 不会将工作负载身份与同一账户中的凭证 provider 绑定。智能体的 IAM 角色会做这种绑定,因此应将其 限定范围 到智能体自身的工作负载身份和 provider,以及该 provider 的密钥:
[
{
"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,provider 的 ARN 取自 credentialProviderArn:该片段是 oauth2credentialprovider,如果使用带连字符的形式,每次调用都会失败并报 AccessDeniedException。该角色不需要 GetWorkloadAccessToken 权限,因为那个令牌是由 runtime 获取的,而不是智能体。我们的测试仅凭这两条语句就通过了。
在 AgentCore runtime 上部署智能体
将智能体 runtime 的入站授权器配置为只接受 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 声明。没有它时,runtime 会以 HTTP 200 放行另一个智能体的 ID-JAG,请求随后在交换环节失败。有了它,runtime 会以 HTTP 401 拒绝该令牌。
除了上一节中的策略外,执行角色还需要 bedrock:InvokeModel 和 bedrock:InvokeModelWithResponseStream。它不需要 MCP 服务器的 bedrock-agentcore:InvokeAgentRuntime 权限:每个 MCP 服务器都运行在 AgentCore runtime 上,各自有独立的 JWT 授权器,以自定义授权服务器为签发者、以 api://task-manager 为受众,因此智能体以 Okta 访问令牌作为持有者令牌来调用它,而不是使用 AWS Signature Version 4(SigV4)。
资源连接为智能体的所有用户设置了作用域,因此三个测试用户都收到了 xaa:read xaa:write,而每个用户的权限则通过 groups 声明传递:Alice 的令牌携带了 xaa-readers,Bob 的携带了 xaa-writers,而 Carol 的则没有任何权限。
任务管理器检查两件事:它只接受由已注册智能体获取的令牌,并且仅当组和作用域同时存在时才允许写入:
REGISTERED_AGENTS = {"YOUR_AGENT_CLIENT_ID"}
def _require_agent() -> None:
claims = _decode_claims() # the runtime's JWT authorizer already validated the 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 之前,一个发放给没有 act 声明的服务应用普通令牌交换令牌为 Bob 创建了一个任务。服务器之所以能读取这些声明而无需再次验证令牌,是因为 runtime 的 JWT 授权器已经完成了验证。前面没有该授权器的服务器必须自行检查签名、签发者、受众和有效期,就像运行在 Amazon EKS 上的 Part 2 智能体那样。
验证结果
我们对已部署的解决方案运行了所有检查。Alice、Bob 和 Carol 分别让智能体创建一个任务,然后列出该项目的任务:
| 调用者 | create_task |
list_tasks |
| Alice | 被拒绝:需要 xaa-writers 的成员身份 |
允许 |
| Bob | 已创建 | 允许 |
| Carol | 被拒绝:没有 groups 声明 |
允许 |
| Bob,随后 Alice 紧随其后 | 为 Bob 创建成功,随后 Alice 被拒绝:权限未随令牌传递 | 允许 |
以下请求在工具运行前就被拦截了:
| 请求 | 拦截者 | 响应 |
| 发给任务智能体的 Agent B 的 ID-JAG | runtime 的 JWT 授权器 | 401:“Claim ‘client_id’ value mismatch with configuration.” |
| 一个已持有 245 秒的 ID-JAG | runtime 的 JWT 授权器 | 401:“Ineffectual token, will expire within the next minute” |
| 一个格式错误的持有者令牌 | runtime 的 JWT 授权器 | 403:“Failed to parse token” |
| 一个被两次兑换的 ID-JAG | Okta 的自定义授权服务器 | 400:“The id-jag was already used.” |
| 第二次交换时使用了更窄的作用域 | Okta 的自定义授权服务器 | 400:“The scope parameter must exactly match the scopes in the id-jag.” |
| 一个超出连接范围的作用域 | Okta 的组织授权服务器 | 400 invalid_scope |
| 在 MCP 服务器上使用普通令牌交换令牌 | MCP 服务器 | 被拒绝:只接受由已注册 AI 智能体获取的令牌 |
AgentCore Identity 返回的令牌与我们直接在 Okta 兑换的令牌在各项声明上完全一致:sub 是用户,cid 和 act 标明了智能体,scp 包含连接的作用域,groups 包含用户的组,有效期 300 秒。
AgentCore Identity 为一个端到端约需 30 秒(大部分时间用于模型和工具调用)的请求增加了约 0.6 秒。来自我们测试客户端五次运行的中位数:
| 调用 | 中位数 |
| 脚本化登录(授权码流程) | 1,205 ms |
| 在 Okta 的组织授权服务器上将 ID 令牌换为 ID-JAG | 216 ms |
GetWorkloadAccessTokenForJWT |
135 ms |
GetResourceOauth2Token,包括 Okta 的 JWT 持有者授权 |
508 ms |
治理运行中的智能体
Okta 在签发 ID-JAG 时会评估智能体、用户和连接。我们测量了每项管理员操作对下一次请求和已签发令牌的影响:
| Okta 中的管理员操作 | 新请求 | 已签发的令牌 |
| 删除智能体的资源连接 | 立即被拒绝(invalid_target) |
在其到期前持续有效,最长 5 分钟 |
| 移除用户的分配 | 在约 1 秒内被拒绝,即使用户已持有 ID token | 最长 5 分钟 |
| 停用智能体 | 在 Okta 执行该操作后被拒绝,我们的测试组织将此操作排队了 86 分钟 | 最长 5 分钟 |
对其中一个智能体的操作并未影响另一个的运行。Okta 在兑换 ID-JAG 时不会重新检查用户:在我们移除某用户 3 秒后,其自定义授权服务器仍为一个在该移除之前铸造的 ID-JAG 签发了访问令牌。Okta 的 System Log 以该智能体作为执行者记录每次授权,而第二部分将这些事件流式传输到 CloudWatch。
委托链的最佳实践
这些测量得出了六条实践,每一条都是链的属性而非偏好:
| 实践 | 我们的测量结果 |
| 为每个请求铸造新的 ID-JAG | ID-JAG 是一次性的,有效期为 300 秒。运行时会拒绝剩余时间不足 60 秒的 ID-JAG,因此剩 225 秒时可用,245 秒时则不行 |
在 groups 声明中携带每用户的权限,并为每个请求请求一组作用域 |
Okta 根据资源连接设置作用域,因此三个用户都获得了相同的作用域,而且第二次交换必须请求与 ID-JAG 完全一致的作用域 |
在运行时固定智能体,并在工具中检查 act 和 cid |
allowedClients 与 ID-JAG 携带的 client_id 声明匹配。而 Okta 访问令牌携带的是 cid |
| 直接对 Okta 复现一次失败的交换 | 通过 AgentCore Identity,作用域不匹配和错误的客户端都表现为“Token exchange failed with HTTP status 400” |
| 为智能体的角色授予读取提供方密钥的权限 | GetResourceOauth2Token 在角色能够读取它之前一直失败 |
| 保持生命周期短,并将资源连接用作你的终止开关 | 删除连接立即生效。而停用智能体在 Okta 的 beta 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 授权服务器,用户的权限则通过一个 claim 传递。金融服务、医疗保健和公共部门的团队将不同的资源置于相同的控制之下。
清理
为避免持续产生费用,请删除您创建的资源:
- 删除 AgentCore CLI 为智能体和两个 MCP 服务器创建的 AWS CloudFormation 堆栈。
- 使用
aws bedrock-agentcore-control delete-oauth2-credential-provider --name okta-xaa-obo删除凭据提供程序,并使用delete-workload-identity删除您自己创建的任何工作负载身份。 - 删除您添加到执行角色的 IAM 策略。
- 在 Okta 中,停用并删除 AI 智能体及其关联的应用,并移除资源连接、授权服务器的策略规则、范围和 claim,以及测试用户和群组。
结论
在这篇文章中,您使用 Okta Cross App Access 决定哪个智能体可以代表哪个用户,并使用 AgentCore Identity 执行每项决策。运行时仅接受智能体自己的 ID-JAG,凭据提供程序用智能体不持有的密钥兑换每一个,令牌保管库在一次请求内复用结果,而 MCP 服务器则根据 groups claim 强制执行每个用户的权限。
此设计将交换保持在智能体的角色内,并在每个 MCP 服务器中重复授权检查。请参阅本系列的第 2 部分,了解其设计为何将两者移至一个带有 Cedar 策略的 AgentCore Gateway 之后,在 Amazon EKS 上添加第二个智能体,并将 Okta System Log 与 CloudWatch 中的 AgentCore 跟踪关联起来。
要开始使用,请探索 AgentCore 示例和 Okta 的 Cross App Access 文档。有关 API 详细信息,请参阅 AgentCore 开发人员指南中的 On-behalf-of 令牌交换。
关于作者
来源: AWS Machine Learning Blog · aws.amazon.com



