使用 Amazon Bedrock AgentCore 中的时间策略保护 AI Agent
英文标题:Securing AI agents with temporal policies in Amazon Bedrock AgentCore
Amazon Bedrock AgentCore 的时间策略(temporal policies)允许开发者根据 Agent 会话中的历史轨迹定义有状态授权规则,而非仅逐次检查单个请求。该机制可强制工具调用顺序、验证跨工具传递的数据完整性、限制单个会话的累计金融风险敞口,并要求高价值操作获得人工批准。时间策略在 AgentCore Gateway 边界运行,独立于 Agent 自身代码,因此 Agent 无法通过提示词、代码缺陷或运行时行为绕过控制。文章以私人银行投资组合 Agent 为例,说明如何借助 Dogwood 语言和轨迹状态实施这些控制。
1.3 MB
101.1 KB
124.1 KB
345.0 KB
141.2 KB
346.5 KB
115.8 KB
27.3 KB
41.1 KB
10.9 KB
156.3 KB
中文
在 AI Agent 出现之前,访问控制通常只需将每个操作视为独立事件即可。应用依靠确定性的业务逻辑,确保操作以正确顺序发生,或确保数据保持最新。AI Agent 的行为方式与传统应用有根本差异:它们在运行时决定调用哪些工具、使用哪些参数,以及以何种顺序调用。这种灵活性与日益智能的模型结合,使 Agent 既能力强大,也更难控制。单独看,一次工具调用可能被视为安全;但结合此前的调用上下文,例如在读取不可信数据源之后,它可能造成危害。那么,如何实施一套授权规则,使其能够考虑 Agent 的会话历史,同时又无法被 Agent 绕过?
Amazon Bedrock AgentCore 中的时间策略(Temporal policies),可通过在 Agent 轨迹中结合先前事件评估当前请求,为 AgentCore Gateway 目标定义决定授权结果的有状态规则。由于这些策略运行在 AgentCore Gateway 的边界层、位于 Agent 自身代码之外,Agent 无法拦截或操纵它们。
本文将介绍时间策略是什么、如何工作,并通过一个示例加以演示。我们将展示如何使用时间策略强制工作流顺序、防止工具调用之间的数据伪造、限制每个会话的累计金融风险敞口,以及要求高价值操作获得人工批准。你还将了解,当 Agent 在缺少人工参与的情况下运行时,如何自动收紧其权限。不过,首先我们将更详细地探讨有状态策略的需求和使用场景。
为什么 Agent 需要有状态策略执行
AgentCore Policy 中现有的访问控制会针对每一项单独请求执行无状态、确定性的规则:谁可以调用哪个工具,以及在什么条件下可以调用。无状态控制是必要的,但对于 Agent 而言通常还不够。请考虑以下场景,现有无状态控制无法发现其中的关键问题:
- Agent 调用
lookup_customer工具后,幻觉生成了一个与返回结果不同的账户号码,并将其传给transfer_funds工具,导致资金被转入错误客户的账户。 - 失控的 Agent 在循环中执行数十笔交易,因为没有任何机制跟踪其累计风险敞口已经超过风险限制。
- Agent 在几秒内既批准又拒绝同一笔保险理赔。
在这些场景中,每次单独的工具调用都能通过无状态策略检查。只有查看 Agent 的轨迹——即一个会话中有序排列的操作序列——问题才会显现。时间策略为 AgentCore 中的 Policy 扩展了这一感知轨迹的执行层。时间策略在网关处、在 Agent 代码之外运行,因此无论 Agent 做什么、收到何种提示,或 Agent 代码中存在何种缺陷,都无法绕过它们。常见的时间策略使用场景包括:
- 强制链式工具之间的输出完整性。 要求传递给当前工具调用的参数,必须与此前工具调用的输出完全匹配,防止 Agent 在步骤之间产生幻觉或替换数值。
- 强制工具调用顺序。 要求在调用一个工具之前先调用另一个工具,以验证是否遵循标准操作程序(SOP)。
- 在特权操作前要求人工批准。 在轨迹中记录明确的人工批准事件之前,阻止破坏性或敏感工具调用。
- 强制数据新鲜度。 要求在授权依赖操作之前,必须在指定时间范围内完成数据查询,避免基于过时信息作出决策。时间策略是一种授权控制,回答的问题是:“鉴于 AgentCore Gateway 观测到的近期轨迹,这一具体请求是否获得授权?”它们根据当前请求以及近期轨迹(即会话内的事件),评估经由网关路由的请求是否应被允许。它们不会转换请求、调用工具、执行分析,也不会直接编排 Agent。
时间策略作用于流经 AgentCore Gateway 的流量。由于 Gateway 会通过单一端点路由 Agent 的模型上下文协议(MCP)工具调用、Agent 间调用和模型推理调用,只要 Agent 经由网关发起这些调用,时间策略就可以同时治理这三类调用。无论 Agent 发起的是哪一种调用,这都为分析其随时间变化的行为提供了一个一致的位置。
时间策略如何工作
时间策略构建在现有策略引擎之上,后者已用于无状态访问控制。它们引入了 Agent 轨迹这一概念:由主体(principal)和会话 ID 标识的、有边界的操作序列。Agent 永远无法看到策略逻辑、接触状态存储或修改控制。与现有 AgentCore Policy 功能一样,时间策略默认拒绝,并且 forbid 的优先级高于 permit。
当网关接收到工具调用时,策略引擎会:
- 查询与正在评估的策略相关的操作、输入和输出的轨迹状态。
- 在当前请求的历史范围内(即客户定义轨迹中的先前事件),针对当前请求评估每项时间策略。
- 返回确定性的 ALLOW 或 DENY 决策,并记录决策的完整上下文。
时间策略评估的每个请求都必须携带 x-amzn-bedrock-agentcore-policy-session-id 请求头,用于标识该请求所属的会话。你可以自行决定什么构成会话的开始与结束。边界可以反映适合应用的任何工作单元,无论是单次用户对话、多步骤任务,还是持续时间更长的工作流。由于每个会话最多只能有一个并发授权请求,我们建议将会话范围保持得尽可能小。如果未传递该请求头,系统将代表你生成一个。不过请注意,新的会话 ID 意味着策略引擎将基于一个没有历史记录的、全新的空轨迹进行评估。
会话绝不会仅由其 ID 定义。AgentCore 会将会话 ID 与终端用户身份相结合,生成唯一会话。这意味着两个不同身份可以提供相同的会话 ID,但仍会被视为完全独立的会话。由于底层身份不同,策略会独立应用于每条轨迹。在活跃会话中,Agent 轨迹的最大回溯窗口为 24 小时。任何早于该时间的轨迹事件都会被自动删除。还有一条规则约束会话与策略本身之间的关系:每当策略引擎中的策略发生变更,现有会话都会失效。这可确保每个会话均按照当前策略集进行评估,并确保每个相关轨迹事件都以预期的模式记录。
将时间策略应用于私人银行投资组合 Agent
为使这些概念更具体,我们将演示时间策略如何保护一个假设的私人银行 Agent。该 Agent 帮助一家金融服务公司的财富顾问管理客户投资组合。它会检索客户资料、加载投资组合持仓、获取实时市场价格、执行分析,并代表顾问执行交易。
在此场景中,以下 MCP 工具通过 AgentCore Gateway 暴露:
| 工具 | 说明 |
|---|---|
| get_client_profile | 获取客户的风险承受能力、投资政策、账户限制以及关联的投资组合 ID |
| load_portfolio | 获取客户的投资组合持仓和当前头寸 |
| get_market_price | 获取证券当前市场价格 |
| execute_trade | 针对投资组合执行买入或卖出订单 |
| rebalance_portfolio | 调整各项持仓之间的投资组合配置 |
共有三类顾问角色:初级顾问(交易授权有限)、高级顾问(拥有完整交易授权)以及合规官(仅有只读监控访问权限)。在本示例中,我们将使用 Amazon Cognito 进行身份管理,并将 JWT 用于进入托管 Agent 工具的 AgentCore Gateway 的入站认证。有关 AgentCore Gateway 以及如何设置 Gateway 认证,请参阅 AgentCore Gateway 文档。时间策略使用 Dogwood,这是一种面向 Agent 及其工具的新型开源治理语言。Dogwood 支持评估现有的 Cedar 策略,并支持时间条件。由于 Dogwood 与现有 Cedar 策略兼容,客户可以继续使用当前的 Cedar 策略,无需迁移。关于 Dogwood 及其语义的更多详情,可参阅语言文档或这篇博客文章。
合规团队要求在该 Agent 上线前实施以下时间控制:
- 在执行任何交易前,Agent 必须先获取客户资料,然后加载投资组合。
- 交易中使用的
portfolio_id必须与get_client_profile的输出完全匹配。 - 必须在交易执行前 1 分钟内获取市场价格。
- 单个会话的交易总金额不得超过 60,000 美元。
- 任何超过 25,000 美元的单笔交易都需要顾问批准,每笔交易对应一次批准。
- 如果卖出时亏损,Agent 不得在同一轨迹内先买入后卖出同一证券。
- 顾问在 15 分钟内没有互动后,Agent 将失去写操作访问权限。
经由网关和策略的请求流

图 1:经由 AgentCore Gateway 和 Policy 的请求流
该图展示了发往网关的请求如何被 AgentCore 中的 Policy 拦截和评估。当投资组合 Agent 发起工具调用时,将发生以下步骤:
- 请求到达 AgentCore Gateway。顾问已通过 AgentCore Identity 完成认证。该请求携带当前会话的轨迹 ID。
- 策略引擎检索轨迹累积的状态。
- 每项时间策略都会根据该历史记录评估当前请求。
- 如果所有策略均允许,请求将继续发送至 MCP 工具。如果任一策略禁止,请求将被拒绝,且该拒绝将被记录。
- 成功执行后,操作及其结果将被追加到轨迹状态中,供后续评估使用。
实施时间策略
如果你已有处于 ENFORCE 模式的策略引擎,可以将其执行模式更新为 LOG_ONLY,也可以更改单个策略的执行模式。不建议在生产工作负载中将现有策略或策略引擎切换为 LOG_ONLY 模式,因为策略将不再执行这些安全规则。
前提条件
在实施此解决方案之前,请确认已满足以下前提条件:
- 已启用 Amazon Bedrock AgentCore 的有效 AWS 账户。
- 已配置至少一个 MCP 目标的 AgentCore Gateway。
- 已附加到网关的策略引擎。
- 用于创建和管理策略资源的适当身份与访问管理(IAM)权限(请参阅文档)。
策略 1:工作流顺序控制(多跳链路)
合规团队要求 Agent 按照 get_client_profile、load_portfolio、rebalance_portfolio 的顺序执行。没有客户资料,Agent 就没有经过系统验证的上下文来了解哪些投资组合属于该客户、客户的风险承受能力如何,或适用哪些账户限制。
permit (principal, action == AgentCore::Action::"FinTarget___load_portfolio", resource == AgentCore::Gateway::<GATEWAY_ARN>)
when temporal {
formerly within 5m (AgentCore::Action::"FinTarget___get_client_profile"::response{eventResource: resource})
};
permit (principal, action == AgentCore::Action::"FinTarget___rebalance_portfolio", resource == AgentCore::Gateway::<GATEWAY_ARN>)
when temporal {
formerly within 5m (AgentCore::Action::"FinTarget___load_portfolio"::response{eventResource: resource})
};
该策略会禁止 rebalance_portfolio,除非 get_client_profile 和 load_portfolio 均已在该轨迹内以正确顺序完成。即使 Agent 收到相应指令,若其跳过加载资料步骤并直接进行再平衡,也会被拒绝。
| 轨迹状态 | 尝试的操作 | 预期结果 |
|---|---|---|
| 空 | rebalance_portfolio (portfolio_id: ” 8821”, amount: 15000) | DENY |
| get_client_profile 已完成 | rebalance_portfolio (portfolio_id: ” 8821”, amount: 15000) | DENY |
| get_client_profile 随后 load_portfolio 已完成 | rebalance |
English / 原文
Before AI agents, it was generally sufficient for access controls to treat each action as an independent event. Applications relied on deterministic business logic to enforce whether actions happened in the right order or whether the data was up-to-date. AI agents behave in fundamentally different ways than traditional applications. They decide at runtime which tools to call, with which arguments, and in what order. That flexibility, combined with increasingly intelligent models, makes agents equal measures capable and challenging to control. One tool call might be deemed safe when considered in isolation, but harmful in the context of the preceding call, such as after reading from an untrusted data source. The question then becomes, how do you enforce authorization rules that account for an agent’s session history, in a way the agent cannot circumvent?
Temporal policies in Amazon Bedrock AgentCore let you define stateful rules that determine authorization to AgentCore Gateway targets by evaluating the current request in the context of prior events in an agent’s trajectory. Because these policies run at the AgentCore Gateway perimeter, outside the agent’s own code, the agent cannot intercept or manipulate them.
In this post, you will learn what temporal policies are, how they work, and walk through an example to demonstrate. We will show you how to use temporal policies to enforce workflow sequencing, prevent data fabrication between tool calls, cap cumulative financial exposure per session, and require human approval for high-value actions. You will also see how to automatically tighten permissions when an agent operates without human engagement. First, however, we will explore the needs and use cases for stateful policies in more detail.
Why agents need stateful policy enforcement
Existing access controls in AgentCore Policy enforce stateless, deterministic rules on each individual request: who can call which tool, under what conditions. Stateless controls are necessary but often insufficient for agents. Consider the following scenarios where existing stateless controls fail to catch critical issues:
- An agent calls a
lookup_customertool, hallucinates a different account number than what was returned, and passes it to atransfer_fundstool that then moves money to the wrong customer’s account. - A runaway agent executes dozens of trades in a loop because nothing tracks that cumulative exposure has already exceeded the risk limit.
- An agent both approves and denies the same insurance claim within seconds.
Each individual tool call in these scenarios would pass a stateless policy check. The problem only becomes apparent when you look at the agent’s trajectory, the ordered sequence of actions in a session. Temporal policies extend Policy in AgentCore with this trajectory-aware enforcement layer. Temporal policies run at the gateway, outside the agent’s code, so they cannot be bypassed regardless of what the agent does, how it is prompted, or what bugs exist in the agent code. Some common temporal policy use cases include:
- Enforcing output integrity across chained tools. Require that an argument passed to the current tool call exactly matches the output of a prior tool call, preventing the agent from hallucinating or substituting values between steps.
- Enforcing tool-call ordering. Require that one tool is called before another tool to verify standard operating procedure (SOP) adherence.
- Requiring human approval before privileged actions. Block destructive or sensitive tool calls until an explicit human approval event is recorded in the trajectory.
- Enforcing data freshness. Require that a data lookup completed within a given timeframe before a dependent action is authorized, preventing decisions based on stale information.Temporal policies are authorization controls that answer the question “given the recent trajectory observed at the AgentCore Gateway, is this specific request authorized?”. They evaluate whether a gateway-routed request should be permitted based on the current request and recent trajectory (that is, events within a session). They do not transform requests, call tools, perform analysis, or directly orchestrate the agent.
Temporal policies operate on the traffic that flows through AgentCore Gateway. Because Gateway routes an agent’s Model Context Protocol (MCP) tool calls, agent-to-agent calls, and model inference calls through a single endpoint, a temporal policy can govern all three whenever your agent issues those calls through the gateway. This gives you one consistent place to reason about an agent’s behavior over time, regardless of which kind of call the agent is making.
How temporal policies work
Temporal policies build on the existing policy engine that’s already used for stateless access control. They introduce the concept of agent trajectories, which are bounded sequences of actions identified by a principal and session ID. Agents never see the policy logic, never touch the state store, and cannot alter the controls. As with the existing AgentCore Policy features, temporal policies deny by default and forbid wins over permit.
When the gateway receives a tool call, the policy engine:
- Queries the trajectory state for actions, inputs, and outputs relevant to the policies being evaluated.
- Evaluates each temporal policy against the current request in the context of its historical scope (that is, prior events within the customer-defined trajectory).
- Returns a deterministic ALLOW or DENY decision and logs the full context of the decision.
Every request that a temporal policy evaluates must carry an x-amzn-bedrock-agentcore-policy-session-id header, which identifies the session the request belongs to. You decide what constitutes the beginning and end of a session. The boundary can reflect whatever unit of work makes sense for your application, whether that is a single user conversation, a multi-step task, or a longer-running workflow. Because there can be no more than one concurrent authorization request per session, we recommend keeping the scope of a session as narrow as possible. If no header is passed, one will be generated on your behalf. However, note that a new session ID means that the policy engine will evaluate against a new, empty trajectory with no history.
A session is never defined by its ID alone. AgentCore combines the session ID with the end user’s identity to produce a unique session, which means two different identities can present the same session ID and still be treated as having entirely separate sessions. Policies apply independently to each trajectory, because the underlying identity differs. Within an active session, agent trajectories carry a maximum look-back window of 24 hours. Any trajectory events older than that are automatically deleted. One additional rule governs the relationship between sessions and the policies themselves. Whenever a change is made to the policies in a policy engine, existing sessions are invalidated. This makes sure that each session is evaluated against the current set of policies and each relevant trajectory event is recorded with the expected schema.
Applying temporal policies to a private banking portfolio agent
To make these concepts concrete, we’ll walk through how temporal policies can secure a hypothetical private banking agent. The agent helps wealth advisors at a financial services firm manage client portfolios. It retrieves client profiles, loads portfolio holdings, fetches real-time market prices, performs analysis, and executes trades on the advisor’s behalf.
In this scenario, the following MCP tools are exposed through the AgentCore Gateway:
| Tool | Description |
|---|---|
| get_client_profile | Retrieves client’s risk tolerance, investment policy, account restrictions, and associated portfolio IDs |
| load_portfolio | Retrieves a client’s portfolio holdings and current positions |
| get_market_price | Fetches current market price for a security |
| execute_trade | Executes a buy or sell order against a portfolio |
| rebalance_portfolio | Adjusts portfolio allocations across holdings |
There are three different advisor roles: junior advisors (limited trade authority), senior advisors (full trade authority), and compliance officers (read-only monitoring access). In this example, we will use Amazon Cognito for identity and pass JWTs for inbound auth to the AgentCore Gateway, which hosts our agent’s tools. To learn about AgentCore Gateway and how to set up auth with Gateway, read the AgentCore Gateway Documentation. Temporal policies use Dogwood, a new open-source governance language designed for agents and their tools. Dogwood supports evaluating existing Cedar policies and enables support for temporal conditions. Because Dogwood is compatible with existing Cedar policies, customers can continue to use their current Cedar policies without needing to migrate. For additional detail on Dogwood and its semantics, you can read the language documentation or this blog post.
The compliance team requires the following temporal controls before the agent reaches production:
- The agent must pull the client profile, then load the portfolio, before any trade executes.
- The
portfolio_idused in a trade must exactly match the output fromget_client_profile. - Market prices must be retrieved within 1 minute of a trade execution.
- No single session can exceed $60,000 in total trade value.
- Any individual trade over $25,000 requires advisor approval, one approval per trade.
- The agent cannot buy and then sell the same security within the same trajectory if it sells for a loss.
- After 15 minutes without advisor interaction, the agent loses access to write operations.
Request flow through gateway and policy

Figure 1: Request flow through AgentCore Gateway and Policy
This diagram demonstrates how requests to your gateway are intercepted and evaluated by Policy in AgentCore. When the portfolio agent initiates a tool call, the following steps occur:
- The request arrives at the AgentCore Gateway. The advisor is already authenticated through AgentCore Identity. The request carries the trajectory ID for the current session.
- The policy engine retrieves the trajectory’s accumulated state.
- Each temporal policy evaluates the current request against that history.
- If all policies permit, the request proceeds to the MCP tool. If any policy forbids, the request is denied and the denial is logged.
- On successful execution, the action and its result are appended to the trajectory state for future evaluations.
Implementing temporal policies
If you have an existing policy engine in ENFORCE mode, you can either update its enforcement mode to LOG_ONLY, or you can change the enforcement mode of the individual policies. Switching existing policies or policy engines to LOG_ONLY mode is not recommended for production workloads since policies will no longer enforce those security rules.
Prerequisites
Before implementing this solution, verify that you have met the following prerequisites:
- An active AWS account with Amazon Bedrock AgentCore enabled.
- An AgentCore Gateway with at least one MCP target configured.
- A policy engine attached to the gateway.
- Appropriate Identity and Access Management (IAM) permissions to create and manage policy resources (see documentation).
Policy 1: Workflow sequencing (multi-hop chain)
The compliance team requires that the agent follow get_client_profile, then load_portfolio, then rebalance_portfolio in sequence. Without the client profile, the agent has no system-verified context about which portfolios belong to this client, what the client’s risk tolerance is, or what account restrictions apply.
permit (principal, action == AgentCore::Action::"FinTarget___load_portfolio", resource == AgentCore::Gateway::<GATEWAY_ARN>)
when temporal {
formerly within 5m (AgentCore::Action::"FinTarget___get_client_profile"::response{eventResource: resource})
};
permit (principal, action == AgentCore::Action::"FinTarget___rebalance_portfolio", resource == AgentCore::Gateway::<GATEWAY_ARN>)
when temporal {
formerly within 5m (AgentCore::Action::"FinTarget___load_portfolio"::response{eventResource: resource})
};
This policy forbids rebalance_portfolio unless get_client_profile and load_portfolio have both completed in the correct order within this trajectory. An agent that skips the load profile step and jumps directly to rebalancing is denied regardless of what instructions it received.
| Trajectory state | Action attempted | Expected result |
|---|---|---|
| Empty | rebalance_portfolio (portfolio_id: ” 8821”, amount: 15000) | DENY |
| get_client_profile completed | rebalance_portfolio (portfolio_id: ” 8821”, amount: 15000) | DENY |
| get_client_profile then load_portfolio completed | rebalance_portfolio(portfolio_id: ” 8821”, amount: 15000) | ALLOW |
Policy 2: Output-to-input integrity
The portfolio_id passed to execute_trade must exactly match one of the portfolio IDs returned by get_client_profile. The agent cannot fabricate or substitute a different portfolio ID.
permit (
principal,
action == AgentCore::Action::"execute_trade",
resource
)
when temporal {
formerly within 24h (
AgentCore::Action::"get_client_profile"::response{
input.profile_id: context.input.profile_id,
eventResource: resource
}
)
};
This policy prevents an attacker from using prompt injection to steer the agent to trade against a different client’s portfolio. The attacker can convince the LLM to use a fabricated ID, but the policy verifies the value against what the CRM system actually returned.
| get_client_profile returned | execute_trade portfolio_id | Expected result |
|---|---|---|
| port-8821 | port-8821 | ALLOW |
| port-8821 | port-3347 | DENY |
Policy 3: Data freshness
A get_market_price call must have completed within the last 30 seconds before execute_trade is authorized. The agent cannot act on stale quotes.
permit (
principal,
action == AgentCore::Action::"execute_trade",
resource
)
when temporal {
formerly within 30s (
AgentCore::Action::"get_market_price"::response{eventResource: resource}
)
};
In volatile markets, even a 60-second-old quote can represent significant price drift. This policy forces the agent to refresh its market data before every trade, ensuring that decisions are based on current information.
| Time since get_market_price | Action | Expected result |
|---|---|---|
| 4 seconds ago | BUY Stock A | ALLOW |
| 2 minutes ago | BUY Stock A | DENY |
| Never called | BUY Stock A | DENY |
Policy 4: Cumulative budget cap per trajectory
Total trade value in a single policy session (or trajectory) cannot exceed $60,000. This contains blast radius from runaway agents or successful attacks.
permit (
principal,
action == AgentCore::Action::"execute_trade",
resource
)
when temporal {
exists (total: Long). ((sum amount for (amount: Long), (t: Timepoint). where (formerly within 24h (
AgentCore::Action::"get_market_price"::request{input.cost: amount, eventResource: resource} && tp(t)))) == total && total < 60000
)
};
A compromised agent executing dozens of small trades that individually look fine can still accumulate catastrophic exposure. After $60,000, all trades are denied until a new trajectory begins.
| Prior cumulative trades | Current trade amount | Total | Expected result |
|---|---|---|---|
| $0 | $15,000 | $15,000 | Allow |
| $15,000 | $22,000 | $37,000 | Allow |
| $37,000 | $30,000 | $67,000 | DENY |
Policy 5: Human approval for large trades (one-time consumption)
Any trade exceeding $25,000 requires the advisor’s explicit approval. Each approval is consumed by a single trade. A second large trade requires a fresh approval.
permit (
principal,
action == AgentCore::Action::"execute_trade",
resource
)
when {
context.input.cost < 25000 || temporal {
!(
AgentCore::Action::"execute_trade"::response{eventResource: resource}
)
since within 24h (
AgentCore::Action::"approve_trade"::response{ input.status: "approved", eventResource: resource}
)
}
};
This prevents the agent from interpreting a single approval as blanket permission for multiple large trades. Each approval covers exactly one execution.
| Trade amount | Approval in trajectory | Expected result |
|---|---|---|
| $15,000 | None | Allow (below threshold) |
| $30,000 | None | DENY |
| $30,000 | Approved (unconsumed) | ALLOW |
| $30,000 (second trade) | Only prior approval (consumed) | DENY |
Policy 6: Mutual exclusion
The agent cannot buy and then sell the same security within the same trajectory if it sells for a loss.
permit (
principal,
action == AgentCore::Action::"execute_sell",
resource
)
unless {
context.input.profit < 0 && temporal {
formerly within 24h (
AgentCore::Action::"execute_buy"{
stock_symbol: context.input.stock_symbol, eventResource: resource}
)
}
}
};
If the agent sold AAPL two minutes ago and now tries to buy AAPL, the request is denied. The contradiction itself is the signal that something has gone wrong and the session should be reviewed.
| Prior action | Current action | Time gap | Expected result |
|---|---|---|---|
| SELL Stock A | BUY Stock A | 2 min | DENY |
| SELL Stock A | BUY Stock A | 7 min | ALLOW |
| SELL Stock A | BUY Stock B | 2 min | ALLOW (different security) |
Policy 7: Progressive trust decay
After 15 minutes without advisor interaction, the agent loses access to write operations (execute_trade, rebalance_portfolio). The advisor can re-engage at any time to restore full access.
permit (
principal,
action in [
AgentCore::Action::"execute_trade",
AgentCore::Action::"rebalance_portfolio"
],
resource == AgentCore::Gateway::"<arn>"
)
unless temporal {
formerly within 15m AgentCore::Action::"interact_advisor"::response{eventResource: resource}
};
If the advisor walks away, the agent naturally converges toward read-only behavior. This ensures that extended autonomous operation does not accumulate unchecked risk.
| Time since last advisor interaction | Action attempted | Expected result |
|---|---|---|
| 3 minutes | execute_trade | ALLOW |
| 20 minutes | execute_trade | DENY |
| 20 minutes | get_market_price | ALLOW (read-only) |
Cost considerations
You only pay for the authorization requests performed during agent execution. Each time an agent calls a tool through AgentCore Gateway, Policy checks the action against your rules to determine whether it is allowed or denied. Your first 100 temporal policies per policy engine are included in the existing per-authorization-request price (see the AgentCore pricing page for details).
Clean up
To avoid ongoing charges, remove the resources you created in this walkthrough. Delete the resources in order: first delete the temporal policies from the policy engine, then detach the policy engine from the gateway, and then delete the policy engine itself. A policy engine cannot be deleted while it still contains policies or remains attached to a gateway. If you created the gateway, its MCP target solely for this walkthrough, delete those as well. Note that deleting or changing policies invalidates any active policy sessions, so perform cleanup only after your test sessions are complete.
List and delete the policies on the policy engine. Repeat the delete-policy command for each of the seven policies:
aws bedrock-agentcore-control list-policies $
--policy-engine-id <POLICY_ENGINE_ID>
aws bedrock-agentcore-control delete-policy $
--policy-engine-id <POLICY_ENGINE_ID> $
--policy-id <POLICY_ID>
Detach the policy engine from the gateway by updating the gateway without a policy engine configuration:
aws bedrock-agentcore-control create-gateway $
--name my-gateway $
--role-arn arn:aws:iam::123456789012:role/my-gateway-service-role $
--protocol-type MCP $
--authorizer-type CUSTOM_JWT $
--authorizer-configuration '{
"customJWTAuthorizer": {
"discoveryUrl": "https://cognito-idp.us-west-2.amazonaws.com/some-user-pool/.well-known/openid-configuration",
"allowedClients": ["clientId"]
}
}'
Delete the policy engine:
aws bedrock-agentcore-control delete-policy-engine $
--policy-engine-id <POLICY_ENGINE_ID>
(Optional) Delete the gateway target and gateway if you created them for this walkthrough:
aws bedrock-agentcore-control delete-gateway-target $
--gateway-identifier <GATEWAY_ID> $
--target-id <TARGET_ID>
aws bedrock-agentcore-control delete-gateway $
--gateway-identifier <GATEWAY_ID>
Conclusion
In this post, you learned how temporal policies bring stateful, trajectory-aware authorization to agentic AI systems. You applied seven policy patterns to a hypothetical private banking portfolio agent. These patterns covered workflow sequencing, output-to-input integrity, data freshness, cumulative budget caps, human-in-the-loop approvals, mutual exclusion, and progressive trust decay. These patterns generalize across domains where agents interact with sensitive tools at runtime. Because enforcement happens at the AgentCore Gateway perimeter, outside the agent’s own reasoning loop, these protections remain tamper-proof regardless of model behavior. This gives you a declarative, auditable way to enforce operational boundaries without constraining the flexibility that makes agents valuable. To get started, review the AgentCore documentation.
About the authors
Sean Eichenberger
Sean is a Principal Product Manager at AWS Agentic AI. He leads initiatives across agent governance, safety, and connectivity for Amazon Bedrock AgentCore.
Philipp Trucksaess
Philipp Trucksaess is a Senior Software Development Engineer at AWS, where he builds primitives for agentic applications. He focuses on distributed systems implemented in Rust, and enjoys providing customers with deterministic controls for their stochastic systems.
Nicholas Gordon
Nick is a Principal Engineer at AWS. During his 10 years at AWS, Nick has worked on Amazon Bedrock and Amazon DynamoDB building large scale distributed systems. He is presently focused on infrastructure for AI.