目 录CONTENT

文章目录

使用 Bedrock AgentCore 网关拦截器实现细粒度访问控制

Administrator
2025-11-27 / 0 评论 / 0 点赞 / 0 阅读 / 0 字

📢 转载信息

原文链接:https://aws.amazon.com/blogs/machine-learning/apply-fine-grained-access-control-with-bedrock-agentcore-gateway-interceptors/

原文作者:Dhawalkumar Patel, Bhuvan Annamreddi, Ganesh Thiyagarajan, Kevin Tsao, Avinash Kolluri, Mohammad Tahsin, and Ozan Deniz


随着企业快速采用AI代理来自动化工作流程和提高生产力,它们面临着一个关键的扩展挑战:管理对组织内数千个工具的安全访问。现代AI部署不再涉及少数代理调用少量API——相反,企业正在构建统一的AI平台,其中数百个代理、消费者AI应用程序和自动化工作流需要访问跨越不同团队、组织和业务部门的数千个模型上下文协议(MCP)工具。

这种规模的增加带来了一个根本性的安全和治理问题:您如何确保每个调用主体——无论是AI代理、用户还是应用程序——只能访问它们被授权使用的工具?您如何根据用户身份、代理上下文、请求访问的渠道以及不断变化的权限动态过滤工具可用性?您如何在多跳工作流程中,从代理到工具再到下游API,保护敏感数据流动的安全?以及如何在不牺牲性能、不产生操作瓶颈或不迫使团队为每个租户或用例部署单独MCP服务器实例的情况下实现所有这些目标?

为了解决这些挑战,我们正在推出一项新功能:Amazon Bedrock AgentCore Gateway的网关拦截器。这项强大的新功能提供了细粒度的安全性、动态访问控制和灵活的Schema管理能力。

工具访问的细粒度访问控制

企业客户正在通过统一的AgentCore Gateway部署数千个MCP工具。这些客户使用这个单一的MCP网关来访问来自不同团队、组织、消费者AI应用程序和AI代理的工具,每个工具都为其分配给调用主体的访问权限。挑战在于根据调用主体的访问权限和上下文安全地访问MCP工具,并对AgentCore Gateway的ListTools、InvokeTool和Search调用做出响应。

工具过滤必须基于多个动态因素,包括代理身份、用户身份和执行上下文,其中权限可能根据用户上下文、用户访问代理的渠道、工作区访问级别和其他上下文属性动态变化。这需要具有安全意识的过滤,其中权限更改会立即影响工具可用性,而不会缓存过时的权限状态。

下图提供了一个基于用户的工具过滤示例,并为网关如何在返回允许的工具之前评估身份和上下文设定了背景。

用户基于身份和上下文的工具过滤示例图

MCP与下游API之间的Schema转换和数据保护

客户在管理AI代理与下游API之间的契约时,面临着复杂的挑战,同时还需要维护安全性和灵活性。组织必须动态地将MCP请求Schema映射到相应的下游API Schema,从而实现关键的数据保护功能,例如*删除*或*移除*用户可能作为提示的一部分发送给代理的敏感数据,如个人身份信息(PII)或敏感个人信息(SPI)。当API调用不需要此类信息时,这可以防止敏感数据泄露到下游API。

此外,客户需要Schema转换功能来处理API合约变更,同时保持MCP Schema的完整性和与下游实现的解耦。这种解耦允许更平滑的API演进和版本控制,而不会破坏AI代理和工具合约,因此后端团队可以修改其API实现、更改字段名称、重构有效载荷或更新身份验证要求,而无需强制更改代理层或重新训练已学习特定工具Schema的AI模型。

多租户SaaS的租户隔离

提供代理即服务或工具即服务的组织面临复杂的多租户要求。客户必须为其所有用户部署其MCP服务器,同时保持适当的租户隔离,这要求同时传递和验证租户ID和用户ID。多租户MCP服务器架构要求不同的客户和工作区保持完全隔离,工具访问严格基于租户边界控制。挑战在于确定是需要为每个租户部署单独的网关,还是单个网关可以在提供适当隔离保证的情况下安全地处理多租户场景。

动态工具过滤

客户需要实时、上下文感知的工具过滤,以适应不断变化的权限和用户上下文。组织需要统一的MCP服务器,能够进行两个阶段的工具过滤:首先按代理权限和工作区上下文过滤,然后按语义搜索过滤——关键要求是由于权限可能随时更改,因此不能对动态过滤的工具列表进行缓存。

自定义Header传播和身份上下文管理

AI代理在行为上与传统微服务有根本不同,因为它们是自主的和非确定的。与通常依赖服务到服务信任和授权技术的传统微服务到微服务授权方法不同,AI代理需要代表最终用户执行工作流程,并根据用户执行上下文访问下游工具、API和资源。然而,将原始授权令牌发送到下游服务会带来重大的安全漏洞,例如凭证被盗、权限升级以及“被混淆的副手”问题(Confused Deputy Problem),即更具权限的服务被诱骗代表权限较低的攻击者执行操作。

“冒充”与“代表”方法的比较

客户在身份上下文如何通过多跳工作流程(代理到代理到工具到API)传播时面临一个根本性的安全决策:是使用冒充(impersonation)方法,还是使用代表(act-on-behalf)方法。

冒充方法中,原始用户的JWT令牌在调用链的每个跳跃中都保持不变地传递。虽然实现起来更简单,但这种方法会带来重大的安全风险。由于以下风险,我们不推荐这种方法:

  • 下游服务接收到的令牌权限超出了所需范围
  • 如果任何组件受到攻击,权限升级的风险增加
  • 令牌范围无法限制到特定的下游目标
  • 容易受到“被混淆的副手”攻击,受攻击的服务可能会滥用权限过高的令牌

代表方法中,工作流中的每个跳跃都会接收到一个单独的、作用域限定的令牌,专门为该下游目标颁发,并且JWT用于在整个过程中传播执行上下文。这是推荐的方法,因为它提供了以下好处:

  • 最小权限原则——每个服务仅接收访问特定下游API所需的权限
  • 减少爆炸半径——受损令牌的作用域有限,无法在其他地方重用
  • 更好的可审计性——清晰的责任链显示了哪个服务代表用户操作,可通过AgentCore可观测性进行追踪
  • 令牌作用域限制——每个下游目标接收的令牌或凭证专门为其API限定作用域
  • 安全边界——在调用链中不同服务之间强制执行适当的隔离
  • “被混淆的副手”预防——作用域受限的令牌和凭证可防止服务被诱骗执行未经授权的操作

代表模型要求网关从传入请求中提取执行上下文,为每个下游目标生成新的作用域限定的授权令牌,并在注入适当Header的同时,为审计和授权决策维护用户的身份上下文——所有这些都不向下游服务暴露权限过高的凭证。这种安全方法确保AI代理可以代表用户执行工作流程,同时在调用链的每个跳跃中维护严格的安全边界。

下图比较了冒充代表方法的流程。

冒充与代表方法的流程对比图

冒充方法(顶部)中,当用户 A 连接到代理时,代理将用户 A 完整的身份令牌及其完整作用域("order: read, promotions:write")未更改地传递给订单工具和促销工具,这意味着每个工具接收的权限都超过了其所需。相比之下,代表方法(底部)显示代理为每个工具创建单独的作用域限定令牌——订单工具仅接收 "order: read" 作用域,促销工具仅接收 "promotions:write" 作用域,并且每个令牌都包含一个 "Act: Agent" 字段,建立了清晰的责任链,表明代理代表用户 A 进行操作。这展示了委托如何通过限制每个下游服务仅拥有其所需的特定权限来实现最小权限原则,从而降低安全风险并防止潜在的令牌滥用。

AgentCore Gateway:AI代理的安全MCP集成

AgentCore Gateway将您现有的API和AWS Lambda函数转换为兼容代理的工具,连接到现有的MCP服务器,并提供与基本第三方业务工具和服务的无缝集成(如Jira、Asana和Zendesk)。这个统一的访问点实现了跨企业系统的安全集成。通过AgentCore Identity,代理可以使用OAuth标准进行适当的身份验证和授权,从而安全地访问和操作这些工具。

随着网关拦截器的推出,AgentCore Gateway通过在两个关键点使用自定义Lambda函数,帮助组织实施细粒度访问控制和凭证管理:

  • 网关请求拦截器——请求拦截器Lambda函数在请求到达目标工具之前处理传入请求,从而可以根据用户凭证、会话上下文和组织策略进行细粒度访问控制、创建审计跟踪、Schema转换等等。
  • 网关响应拦截器——响应拦截器Lambda函数在响应返回调用代理之前处理传出的响应,允许创建审计跟踪、工具过滤、Schema转换以及对搜索和列表工具的细粒度访问控制。

下图说明了请求-响应流经网关拦截器的过程。

请求响应流经网关拦截器的流程图

让我们检查一下自定义拦截器在请求-响应周期的每个阶段接收和必须返回的特定有效载荷结构。网关请求拦截器接收一个具有以下结构的事件:

{
  "interceptorInputVersion": "1.0",
  "mcp": {
    "gatewayRequest": {
        "headers": { "Authorization": "Bearer eyJhbG...", ... },
        "body": { "jsonrpc": "2.0", "method": "tools/list", ... }
    },
    "requestContext": { ... }
  }
}

您的网关请求拦截器Lambda函数必须返回一个具有transformedGatewayRequest字段的响应:

{
  "interceptorOutputVersion": "1.0",
  "mcp": {
    "transformedGatewayRequest": {  // <-- 此字段必须由您的代码添加
        "headers": { ... },
        "body": { ... }
    }
  }
}

在目标服务响应后,将调用网关响应拦截器,并向其传递包含原始请求和响应的事件:

{
  "interceptorInputVersion": "1.0",
  "mcp": {
    "gatewayRequest": { ... },
    "requestContext": { ... },
    "gatewayResponse": {  // <-- 此字段包含目标的响应
        "statusCode": 200,
        "headers": { ... },
        "body": {             "jsonrpc": "2.0",
            "result": { "tools": [ ... ] }
        }
    }
  }
}

您的网关响应拦截器Lambda函数必须返回一个具有transformedGatewayResponse字段的响应:

{
  "interceptorOutputVersion": "1.0",
  "mcp": {
    "transformedGatewayResponse": {  // <-- 此字段必须由您的代码添加
        "statusCode": 200,
        "headers": { ... },
        "body": { ... }
    }
  }
}

理解这个请求-响应结构对于实现我们稍后在本文中探讨的自定义拦截器逻辑至关重要。网关拦截器为代理式AI工作流提供了关键功能,用于安全性和管理:

  • Header管理——通过自定义Header在整个流程中传递身份验证令牌、关联ID和元数据
  • 请求转换——在到达目标服务之前修改请求有效载荷、添加上下文或丰富数据
  • 安全增强——实施自定义身份验证、授权和数据清理逻辑
  • 细粒度访问控制——根据调用主体的访问权限和上下文,安全地访问MCP工具,并对AgentCore Gateway的ListTools、InvokeTool和Search调用做出响应
  • 多租户MCP工具的租户隔离——在多租户环境中,根据调用用户、代理和租户身份实施租户隔离和访问控制
  • 可观测性——添加日志记录、指标和跟踪信息以监控代理式工作流

网关拦截器适用于所有AgentCore Gateway目标类型:包括Lambda函数、OpenAPI端点和MCP服务器。

网关拦截器的用例

网关拦截器为代理式AI系统实现了灵活的安全和访问控制模式。本文展示了三种方法:实现工具调用的细粒度访问控制、基于用户权限的动态工具过滤,以及跨分布式系统的身份传播。

实现工具调用的细粒度访问控制

AgentCore Gateway通过统一的MCP端点暴露多个后端工具。具有不同角色的用户需要不同的工具权限。您可以使用JWT作用域结合网关拦截器来实现细粒度访问控制,以确保用户只能调用授权的工具,并且只能发现属于其角色或工作区的工具。细粒度访问控制使用Amazon Cognito(或其他OAuth 2提供商)颁发的JWT作用域值。您也可以使用YAML文件或带有映射权限的数据库来实现此功能。我们遵循一个简单的命名约定:用户对MCP目标拥有完全访问权限(例如,mcp-target-123)或工具级别的访问权限(例如,mcp-target-123:getOrder)。这些作用域直接映射到OAuth令牌中作用域声明中的工具权限,使授权模型可预测且易于审计。

下图说明了此工作流程。

基于JWT作用域实现工具调用细粒度访问控制的工作流程

请求拦截器通过以下步骤在执行时强制执行权限:

  1. 提取并解码JWT以检索作用域声明。
  2. 识别正在调用的工具(使用tools/call)。
  3. 如果用户缺乏完全的目标访问权限或工具特定权限(基于配置文件或访问策略数据存储),则阻止请求。
  4. 对未经授权的调用返回结构化的MCP错误,阻止后端工具处理程序执行。

核心授权函数刻意保持最小化:

def check_tool_authorization(scopes, tool, target):
    if target in scopes:
        return True
return f"{target}:{tool}" in scopes

此模式支持调用和发现路径(在下一节中进一步讨论)的预测性强制执行。您可以扩展模型以包含额外的声明(例如,tenantIdworkspaceId),以支持多租户架构。

为了操作安全,请保持拦截器具有确定性,避免复杂的条件分支逻辑,并完全依赖令牌声明而不是大型语言模型(LLM)指令。通过在网关边界强制执行授权——在LLM看到或执行任何工具之前——您可以在不修改工具实现或MCP目标的情况下,跨角色、租户和域实现强大的隔离。

动态工具过滤

代理通过两种主要方法发现可用工具:允许自然语言查询的语义搜索功能(如“查找与订单管理相关的工具”)和提供可用工具完整清单的标准(tools/list)操作。这种发现机制是代理功能的基础,但它也带来了重大的安全考虑。如果没有适当的过滤控制,MCP服务器将返回所有可用工具的完整列表,而不管请求代理或用户的授权级别如何。这种不受限制的工具发现可能会通过向未经授权的用户或代理暴露敏感功能而带来潜在的安全漏洞。

当目标响应语义搜索或MCP tools/list请求返回工具列表时,可以使用网关响应拦截器来实施细粒度的访问控制。拦截器在响应到达请求代理之前对其进行处理,因此用户只能发现他们被授权访问的工具。工作流程包括以下步骤:

  1. 目标验证传入的JWT令牌,并根据语义搜索返回完整的工具列表或经过过滤的集合,而不考虑细粒度访问控制。
  2. AgentCore Gateway调用配置的响应拦截器。响应拦截器提取并解码有效载荷中的JWT,检索定义用户权限的作用域声明。
  3. 对于列表中的每个工具,拦截器根据JWT作用域评估用户的授权。
  4. 用户无权访问的工具将从列表中删除。
  5. 响应拦截器返回一个包含经过授权工具的转换后响应。

下图说明了这对两种工具的工作流程。

语义搜索工具过滤工作流程图

tools/list工具过滤工作流程图

以下是响应拦截器Lambda处理程序的代码片段,它在返回转换后的响应以及授权工具之前执行JWT令牌提取、工具列表检索和基于权限的过滤:

def lambda_handler(event, context):
    # Extract gateway response and authorization header
    gateway_response = event['mcp']['gatewayResponse']
    auth_header = gateway_response['headers'].get('Authorization', '')
    token = auth_header.replace('Bearer ', '')     # Extract scopes from JWT token
    claims = decode_jwt_payload(token)
    scopes = claims.get('scope', '').split()
    
    # Get tools from gateway response (for list tools)
    tools = gateway_response['body']['result'].get('tools', [])
    # from structuredContent(in case of semantic search)
    if not tools:
        tools = gateway_response['body']['result'].get('structuredContent', {}).get('tools', [])
    
    # Filter tools based on scopes
    filtered_tools = filter_tools_by_scope(tools, scopes)
     
    # Return transformed response with filtered tools
    return {
        "interceptorOutputVersion": "1.0",
        "mcp": {
            "transformedGatewayResponse": {
                "statusCode": 200,
                "headers": {"Authorization": auth_header},
                "body": {
                    "result": {"tools": filtered_tools}
                }
            }
        }
    }
    }

filter_tools_by_scope函数实现了对用户允许的作用域的每个工具的授权检查:

def filter_tools_by_scope(tools, allowed_scopes):
    """Filter tools based on user's allowed scopes"""
    filtered_tools = []
    for tool in tools:
        target, action = tool['name'].split('___')
        # Check if user has full target access or specific tool access
        if target in allowed_scopes or f"{target}:{action}" in allowed_scopes:
            filtered_tools.append(tool)
         
    return filtered_tools

完整的实现可以在GitHub 仓库中找到。

自定义Header传播

随着AI代理与多个下游服务交互,在服务边界维护用户身份对于安全、合规和审计跟踪至关重要。当代理通过AgentCore Gateway调用工具时,原始用户身份必须从代理流向网关,再从网关流向下游服务。如果没有适当的身份传播,下游服务将无法强制执行用户特定的授权策略、维护准确的审计日志或实施租户隔离。在不同用户共享相同代理基础设施但需要严格数据分离的多租户环境中,这一挑战尤为突出。

网关请求拦截器通过以下步骤,从传入请求Header和上下文中提取身份信息,将其转换为下游服务期望的格式,并丰富请求,然后再将其发送到目标服务:

  1. 网关请求拦截器从传入请求中提取授权Header,并将其转换为下游服务所需的格式。
  2. AgentCore Gateway协调请求流并管理拦截器的执行。
  3. 目标调用接收到经过丰富格式化的请求,其中包含适当格式的身份信息。

网关请求拦截器帮助组织获得用户操作的端到端可见性,跨服务边界强制执行一致的授权策略,并维护对数据主权要求的合规性。

工作流程包括以下步骤:

  1. MCP客户端调用AgentCore Gateway。
  2. AgentCore Gateway对入站请求进行身份验证。
  3. AgentCore Gateway调用自定义拦截器。
  4. 网关请求拦截器通过将授权令牌作为参数添加到下游Lambda目标中,来转换传入的请求有效载荷。(我们不建议将传入的JWT原封不动地发送给下游API,因为它存在权限升级和凭证被盗的安全风险。但是,在代理需要使用访问令牌调用MCP服务器以访问下游API的情况下,可能会有例外情况。)或者,您可以移除来自请求的传入JWT,并添加一个新的、作用域限定的最小权限令牌,用于调用相关的下游API。
  5. AgentCore Gateway使用转换后的请求调用目标。目标接收到拦截器Lambda函数传递的授权令牌。
  6. AgentCore Gateway返回来自目标的响应。

下图说明了此工作流程。

自定义Header传播工作流程图

以下是执行自定义Header传播的拦截器Lambda处理程序的代码片段:

import json
import uuid def lambda_handler(event, context):
    # Extract the gateway request from the correct structure
    mcp_data = event.get('mcp', {})
    gateway_request = mcp_data.get('gatewayRequest', {})
    headers = gateway_request.get('headers', {})
    body = gateway_request.get('body', {})
    extended_body = body
     
    # Pass through the Authorization header
    a... [内容被截断]



🚀 想要体验更好更全面的AI调用?

欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,文档丰富,小白也可以简单操作。

0

评论区