在Amazon Bedrock AgentCore网关中使用策略和Lambda拦截器保护AI代理
本文介绍了如何使用Amazon Bedrock AgentCore网关中的策略(Policy)和Lambda拦截器(Interceptor)来保护AI代理。策略基于Cedar语言实现确定性访问控制,拦截器支持动态验证和上下文注入。通过一个湖仓数据代理示例,展示了如何结合两者实现分层安全架构,包括基于地理位置的访问控制。
人工智能代理的安全性是企业在构建代理解决方案时面临的关键挑战。随着企业迅速采用AI代理来自动化工作流程,他们面临着管理组织内工具安全访问的规模化挑战。现代统一的企业AI平台拥有数百个代理,为组织内的用户提供服务。这些代理需要访问跨不同团队、组织和业务部门的数千个模型上下文协议(MCP)工具。这种平台的规模带来了根本性的治理问题。传统应用程序执行固定逻辑,而由大语言模型(LLM)驱动的代理在运行时决定调用哪些工具、使用什么参数以及按什么顺序调用。由于工作流程的动态性,预先审计调用图变得困难。必须构建机制以确保LLM按预期行为。
您可以使用Amazon Bedrock AgentCore网关通过两种互补机制来保护代理和工具:Amazon Bedrock AgentCore中的策略用于确定性访问控制,AgentCore网关的拦截器用于动态验证。Amazon Bedrock AgentCore中的策略允许您定义附加到网关工具的策略。策略使用Cedar编写,Cedar是一种声明式策略语言,它根据主体、操作和资源评估每个请求,并可选地基于请求上下文的条件。结果是确定的允许或拒绝决定,并自动记录在审计日志中。Lambda拦截器允许您定义在每次工具调用之前或之后运行的自定义代码,支持动态验证、负载增强、令牌交换和响应过滤。您可以结合这两种机制为您的代理解决方案构建分层安全架构。
在这篇文章中,我们使用一个湖仓数据代理来演示如何将策略用于确定性访问控制,以及将Lambda拦截器用于动态验证。然后,我们展示如何结合Lambda拦截器和策略来实现基于地理位置的访问控制,这需要动态验证和确定性访问控制。
前提条件
在实施此解决方案之前,您需要:
- 一个AWS账户。
- 访问GitHub存储库。
- AWS Identity and Access Management (IAM) 权限来设置先决条件。
解决方案概述
湖仓数据代理是一个AI助手,允许保险公司员工查询索赔数据。数据存储在Amazon S3表(Apache Iceberg)中,并通过Amazon Athena和AWS Lake Formation查询。应用程序中存在三个用户角色:保单持有人(只能查看自己的索赔)、调解员(管理分配的索赔)和管理员(具有完整的数据访问权限,包括审计日志)。Streamlit UI通过Amazon Cognito对用户进行身份验证,并将JSON Web令牌(JWT)传递给代理。
MCP服务器公开了五个工具:query_claims、get_claim_details、get_claims_summary、query_login_audit和text_to_sql。角色到工具的访问、租户IAM角色映射和用户地理位置存储在Amazon DynamoDB中。AWS Lake Formation在查询时实施行级和列级安全性。在这种情况下,即使代理构建了广泛的SQL查询,结果也会自动限定在调用者的IAM角色被允许查看的范围内。
下图显示了湖仓数据代理的架构:
[图片描述] 用户通过Streamlit UI访问湖仓代理,Amazon Cognito对用户进行身份验证并颁发承载令牌。AgentCore Runtime托管湖仓代理,验证这些令牌并为每个用户建立隔离会话。当代理调用工具时,AgentCore Gateway通过Lambda拦截器路由请求。拦截器提取承载令牌,通过租户角色映射验证工具访问权限,并生成具有租户范围声明的令牌。AgentCore策略引擎在允许访问之前根据定义的策略评估每个工具调用。然后,湖仓MCP服务器使用范围凭证查询数据。AWS Lake Formation根据用户表和索赔表实施行级和列级安全性,帮助每个用户只看到他们被授权访问的数据。AgentCore可观测性和会话日志流式传输到Amazon CloudWatch以进行实时监控和合规审计。
请求流程
下图显示了通过解决方案的工具调用流程:
[图片描述] 当湖仓代理通过AgentCore网关发起工具调用时,请求被请求拦截器Lambda函数拦截。请求拦截器通过用租户范围凭证替换承载令牌并注入额外上下文来转换请求。然后,策略引擎根据Cedar策略评估转换后的请求。转换后的请求用于使用湖仓MCP服务器调用工具。然后,响应拦截器Lambda函数评估响应,在将响应返回给用户之前过滤工具列表。
网关在Cedar策略之前评估请求拦截器。这种顺序对于您将使用拦截器丰富请求上下文,然后使用策略评估该丰富上下文的设计模式至关重要。
AgentCore网关中的策略实施
Amazon Bedrock AgentCore中的策略使用Cedar策略语言在网关处实施确定性、可审计的访问控制。Cedar策略表示为permit或forbid规则,这些规则根据主体、操作和资源进行评估,并基于操作上下文的条件。
当授权规则可以表示为身份属性、操作标识符和请求上下文上的逻辑条件时,我们使用Cedar策略进行细粒度访问控制。典型用例包括限制角色可以调用哪些工具,以及阻止某些用户组对敏感操作的访问。Cedar还根据拦截器注入的上下文属性强制执行数据驻留规则,并支持在请求到达下游服务之前在网关处进行范围检查或时间窗口执行。
设计1:仅策略
首先,让我们看一个策略作为湖仓代理安全层的示例。考虑企业决定保单持有人不应能够调用get_claims_summary的场景。保单持有人可以查看自己的个人索赔,但汇总摘要保留给调解员和管理员。为此,您可以将策略引擎附加到网关,并定义两个协同工作的Cedar策略:基线许可规则和针对性禁止规则。
当策略引擎附加到网关时,它遵循默认拒绝语义。如果没有策略明确允许请求,则拒绝请求。因此,您首先需要一个基线许可策略,允许代理调用网关上的工具:
permit(
principal,
action,
resource == AgentCore::Gateway::""
);仅使用此策略,所有经过身份验证的用户都可以调用任何工具。
接下来,添加一个禁止规则来为保单持有人划定特定限制。由于在Cedar中禁止规则优先于许可规则,这个单一规则足以阻止目标工具调用,同时保持所有其他访问不受影响。
forbid(
principal is AgentCore::OAuthUser,
action == AgentCore::Action::"lakehouse-mcp-target___get_claims_summary",
resource == AgentCore::Gateway::""
) when {
principal.hasTag("cognito:groups") &&
principal.getTag("cognito:groups") like "*policyholders*"
};这两个策略的组合允许代理调用任何工具,除非保单持有人尝试访问索赔摘要。
注意:最佳做法是从策略引擎上的策略实施模式设置为LOG_ONLY开始。所有策略决策都写入CloudWatch,但不会阻止任何请求。这使您可以在切换到ENFORCE模式之前验证每个策略规则的行为是否符合预期。
下图显示了遵循仅策略模式的工具调用流程:
[图片描述] 当湖仓代理发送传入请求时,AgentCore网关首先使用内置授权验证JWT令牌。然后,策略引擎根据附加的Cedar策略组合评估请求。在此示例中,Cedar策略使用禁止-许可模式。它首先禁止OAuth用户访问get_claims_summary工具,然后仅当主体具有匹配保单持有人的Cognito组标签时才允许访问。这种确定性策略评估确保只有属于授权组的用户才能调用特定工具。根据策略评估结果,网关要么允许调用湖仓MCP服务器并将原始响应返回给代理,要么在请求到达工具之前拒绝请求。
设计1的策略评估结果
| 用户 | 工具 | 预期结果 | 决策所有者 | |------|------|----------|------------| | policyholder001 | query_claims | Allow | 策略:permit匹配 | | policyholder001 | get_claim_details | Allow | 策略:permit匹配 | | policyholder001 | get_claims_summary | DENY | 策略:forbid覆盖 | | adjuster001 | get_claims_summary | Allow | 策略:无forbid匹配 |
基于策略的执法的好处
Cedar策略为保护AI代理提供了三个关键好处:
- 确定性:相同的输入总是产生相同的决策,与LLM行为无关。
- 可审计性:一旦为网关启用了CloudWatch日志交付,每个允许或拒绝的决定都会记录完整的上下文,提供完整的审计跟踪。
- 低延迟:Cedar评估为请求处理增加了最小的开销。
用于动态控制的拦截器
拦截器是自定义Lambda函数,AgentCore网关在请求生命周期的两个阶段调用它们。REQUEST拦截器在请求到达下游工具之前运行,RESPONSE拦截器在响应返回给代理之前运行。网关向每个拦截器传递一个包含原始请求头和主体的JSON事件(在mcp键下)。拦截器转换请求内容并以相同结构返回。拦截器适用于所有网关目标类型,包括Lambda函数、OpenAPI端点和MCP服务器。有关完整的负载合同和详细演练,请参阅此文章。
当代理代表用户调用工具时,一个关键的安全决策是身份如何在调用链中传播。模拟方法是将原始用户JWT不变地传递给每个下游服务。这更简单,但它也允许下游服务获得超过所需的权限。一个受损的服务可以重用在其他地方具有过多权限的令牌(混淆代理问题)。另一种方法是“代理行为”方法,其中每个下游目标收到一个单独的、专门为该服务限定的最小权限令牌。用户的身份上下文流过以进行审计。设计2实现了这种模式。REQUEST拦截器将用户的Cognito JWT通过sts:AssumeRole交换为短期、租户范围的IAM凭证,而这些范围凭证才是到达MCP服务器的内容。
设计2:仅拦截器——代理行为令牌交换和上下文传播
REQUEST拦截器中发生了三个Cedar无法执行的操作:
- JWT到IAM令牌交换(代理行为):从JWT读取用户的Cognito组,在DynamoDB中查找相应的租户IAM角色,并调用sts:AssumeRole获取短期范围凭证。
- 上下文注入:将用户身份和临时IAM凭证写入MCP请求体的params.arguments.context中,以便MCP服务器可以使用它们构建范围的Athena客户端。
- 工具授权:在转发请求之前检查DynamoDB allowed_tools,为未经授权的调用返回结构化的MCP错误。
REQUEST拦截器处理程序(简化):
[为了控制成本,代码已截断]