

# Policy in Amazon Bedrock AgentCore: Control Agent-to-Tool Interactions
<a name="policy"></a>

Policy in Amazon Bedrock AgentCore enables developers to define and enforce security controls for AI agent interactions with tools by creating a protective boundary around agent operations. AI agents can dynamically adapt to solve complex problems - from processing customer inquiries to automating workflows across multiple tools and systems. However, this flexibility introduces new security challenges, as agents may inadvertently misinterpret business rules, or act outside their intended authority.

With Policy in AgentCore, developers can create policy engines, create and store deterministic policies in them and associate policy engines with gateways. Policy in AgentCore intercepts all agent traffic through Amazon Bedrock AgentCore Gateways and evaluates each request against defined policies in the policy engine before allowing tool access.

Policies are constructed using [Cedar language](https://www.cedarpolicy.com/en) , an open source language for writing and enforcing authorization policies. This allows developers to precisely specify what agents can access and what actions they can perform. Policy in AgentCore also provides the capability to author policies using natural language by allowing developers to describe rules in plain English instead of writing formal policy code in Cedar. Natural language-based policy authoring interprets what the user intends, generates candidate policies, validates them against the tool schema, and uses automated reasoning to check safety conditions such as identifying policies that are overly permissive, overly restrictive, or contain conditions that can never be satisfied - ensuring customers catch these issues before enforcing policies.

Policy in AgentCore supports fine-grained permissions based on user identity and tool input parameters, making it possible to safely deploy autonomous agents at enterprise scale. By moving security controls outside of agent code, developers can focus on building innovative agent capabilities while maintaining strong security guarantees - eliminating the need for custom security implementation and reducing the risk of policy bypass through agent manipulation.

**Topics**
+ [Key benefits](#policy-benefits)
+ [Key features](#policy-features)
+ [Getting started with Policy in AgentCore](policy-getting-started.md)
+ [Core concepts](policy-core-concepts.md)
+ [AgentCore Gateway and Policy in AgentCore IAM Permissions](policy-permissions.md)
+ [Create a policy engine](policy-create-engine.md)
+ [Create a policy](policy-create-policies.md)
+ [Writing policies in natural language](policy-natural-language.md)
+ [Validate and test policies](policy-validate-policies.md)
+ [Use policies](policy-use-policies.md)
+ [Example policies](example-policies.md)
+ [Advanced features and topics for Policy in AgentCore](policy-advanced.md)

## Key benefits
<a name="policy-benefits"></a>

Policy in AgentCore provides three key benefits that enable secure, scalable deployment of AI agents in enterprise environments:

 **Fine-grained control over agent actions**   
Define what actions an agent is allowed to perform - including which tools it can call and the precise conditions under which those actions are permitted.

 **Deterministic enforcement with strong guarantees**   
Every agent action through Amazon Bedrock AgentCore Gateway is intercepted and evaluated at the boundary outside of agent’s code - ensuring consistent, deterministic enforcement that remains reliable regardless of how the agent is implemented.

 **Simple, accessible authoring with organization-wide consistency**   
Write policies using natural language prompts or directly in Cedar (AWS's open-source policy language for fine-grained permissions), making it easy for builders with varying degree of expertise to define rules for their agents. Teams can set boundaries once and have them applied consistently across all agents and tools, with every enforcement decision logged through CloudWatch metrics and logs, so security and compliance teams can audit and validate behavior.

## Key features
<a name="policy-features"></a>

Policy in AgentCore offers comprehensive capabilities for policy-based governance of agent interactions, including the following key features:
+  **Policy Enforcement** - Intercepts and evaluates all agent requests against defined policies before allowing tool access
+  **Access Controls** - Enables fine-grained based on user identity and tool input parameters
+  **Policy Authoring** - Provides Cedar policy language support for writing clear, validated policies. Policies can also be authored in natural language using English prompts which are translated into Cedar policies and validated
+  **Policy Monitoring** - Offers CloudWatch integration for monitoring policy evaluations and decisions
+  **Infrastructure Integration** - Integrates with VPC security groups and other AWS security infrastructure
+  **Audit Logging** - Maintains detailed logs of policy decisions for compliance and troubleshooting

# Getting started with Policy in AgentCore
<a name="policy-getting-started"></a>

In this tutorial, you’ll learn how to set up Policy in AgentCore and integrate it with a Amazon Bedrock AgentCore Gateway using the AgentCore CLI. You’ll create a refund processing tool with Cedar policies that enforce business rules for refund amounts.

**Topics**
+ [Prerequisites](#policy-getting-started-prerequisites)
+ [Step 1: Setup and install](#policy-getting-started-setup)
+ [Step 2: Add a gateway with a policy engine](#policy-getting-started-create-script)
+ [Step 3: Deploy](#policy-getting-started-run-setup)
+ [Step 4: Test the policy](#policy-getting-started-test)
+ [What you’ve built](#policy-getting-started-results)
+ [Troubleshooting](#policy-getting-started-troubleshooting)
+ [Clean up](#policy-getting-started-cleanup)

## Prerequisites
<a name="policy-getting-started-prerequisites"></a>

Before starting, make sure you have the following:
+  ** AWS Account** with credentials configured. To configure credentials, you can install and use the AWS Command Line Interface by following the steps at [Getting started with the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html).
+  **Node.js 18\$1** installed
+  **IAM permissions** for creating roles, Lambda functions, policy engines, and using Amazon Bedrock AgentCore
+  **A Lambda function** that processes refund requests. You can use an existing function or create one for this tutorial. Note the function ARN for use in Step 2.

## Step 1: Setup and install
<a name="policy-getting-started-setup"></a>

Install the AgentCore CLI:

```
npm install -g @aws/agentcore
```

Create a new AgentCore project:

**Example**  

1. 

   ```
   agentcore create --name PolicyDemo --defaults
   cd PolicyDemo
   ```

   The `--defaults` flag creates a project with a default Python Strands agent. The **cd** command moves into the project directory where subsequent commands must be run.

1. You can also run `agentcore create` without flags to use the interactive wizard. The wizard guides you through selecting a project name, agent framework, model provider, and other options. After project creation, change into the project directory with **cd PolicyDemo**.

## Step 2: Add a gateway with a policy engine
<a name="policy-getting-started-create-script"></a>

Use the AgentCore CLI to add a gateway, a Lambda function target, and a policy engine to your project.

 **Add a gateway** 

Create a gateway with no inbound authorization (for simplicity in this tutorial) and attach your agent to it:

**Example**  

1. 

   ```
   agentcore add gateway --name PolicyGateway --authorizer-type NONE --runtimes PolicyDemo
   ```

1. Run `agentcore` to open the TUI, then select **add** and choose **Gateway** :

1. Enter the gateway name:  
![\[Gateway wizard: enter name\]](http://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/images/tui/gateway-add-name.png)

1. Select the authorizer type. For this tutorial, choose **NONE** :  
![\[Gateway wizard: select NONE authorizer\]](http://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/images/tui/gateway-add-auth-none.png)

1. Configure advanced options or accept the defaults:  
![\[Gateway wizard: advanced configuration\]](http://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/images/tui/gateway-add-advanced.png)

1. Review the configuration and press **Enter** to confirm:  
![\[Gateway wizard: review configuration\]](http://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/images/tui/gateway-add-confirm.png)

 **Add a Lambda function target with a refund tool** 

Register your Lambda function as a gateway target with a tool schema that defines a refund processing tool:

**Example**  

1. 

   ```
   agentcore add gateway-target --name RefundTarget --type lambda-function-arn \
     --lambda-arn ++<YOUR_LAMBDA_ARN>++ \
     --tool-schema-file refund_tools.json \
     --gateway PolicyGateway
   ```

   Replace `<YOUR_LAMBDA_ARN>` with the ARN of your Lambda function. The `refund_tools.json` file defines the tool schema for the refund tool.

1. Run `agentcore` to open the TUI, then select **add** and choose **Gateway Target** :

1. Enter the target name.

1. Select **Lambda function** as the target type:  
![\[Gateway target wizard: select Lambda function\]](http://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/images/tui/gateway-target-type-lambda.png)

1. Enter the Lambda ARN and tool schema file path, then confirm.

 **Add a policy engine** 

Create a policy engine and attach it to the gateway in ENFORCE mode:

**Example**  

1. 

   ```
   agentcore add policy-engine --name RefundPolicyEngine \
     --attach-to-gateways PolicyGateway \
     --attach-mode ENFORCE
   ```

1. Run `agentcore` to open the TUI, then select **add** and choose **Policy Engine** :

1. Enter the policy engine name:  
![\[Policy engine wizard: enter name\]](http://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/images/tui/policy-engine-name.png)

1. Select the gateways to attach the policy engine to:  
![\[Policy engine wizard: attach gateways\]](http://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/images/tui/policy-engine-gateways.png)

1. Choose the enforcement mode. Select **ENFORCE** :  
![\[Policy engine wizard: select enforcement mode\]](http://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/images/tui/policy-engine-mode.png)

 **Create a Cedar policy** 

Provide a Cedar policy file directly:

```
agentcore add policy --name RefundLimit \
  --engine RefundPolicyEngine \
  --source refund_policy.cedar
```

**Note**  
Cedar policies that reference specific gateway ARNs in the `resource` field (as shown in the example below) require a two-phase deployment: first deploy without the policy to create the gateway, then retrieve the gateway ARN from **agentcore status** , update the Cedar file, and add the policy before redeploying. Cedar does not allow wildcard resources in policy statements.

Alternatively, after deploying your resources in Step 3, you can generate a Cedar policy from a natural-language description:

```
agentcore add policy --name RefundLimit \
  --engine RefundPolicyEngine \
  --generate "Only allow refunds under 1000 dollars" \
  --gateway PolicyGateway
```

The `--generate` flag requires the gateway to be deployed first, because it calls an AWS API that needs the gateway ARN to convert natural language into Cedar. This approach automatically resolves gateway ARNs, making it the simplest path for creating policies.

### Understanding the setup
<a name="policy-understanding-setup-script"></a>

The CLI commands above configure several resources in your AgentCore project. Here’s a detailed explanation of each component.

**Topics**
+ [Create a Gateway](#policy-create-gateway)
+ [Add Lambda target](#policy-add-lambda-target)
+ [Create a Policy Engine](#policy-create-policy-engine)
+ [Create Cedar Policy](#policy-create-cedar-policy)
+ [Attach Policy to Gateway](#policy-attach-to-gateway)

#### Create a Gateway
<a name="policy-create-gateway"></a>

The **agentcore add gateway** command creates a gateway that acts as your MCP server endpoint. Setting `--authorizer-type NONE` disables inbound authorization for simplicity in this tutorial. In production, use IAM or JWT authorization to secure your gateway.

#### Add Lambda target
<a name="policy-add-lambda-target"></a>

The **agentcore add gateway-target** command registers a Lambda function as a target in the gateway. The tool schema file defines the inputs that agents can pass to the function, such as a refund amount.

#### Create a Policy Engine
<a name="policy-create-policy-engine"></a>

The **agentcore add policy-engine** command creates a policy engine — a collection of Cedar policies that evaluates and authorizes agent tool calls. The policy engine intercepts all requests at the gateway boundary and determines whether to allow or deny each action based on the defined policies. This provides deterministic authorization outside of the agent’s code, ensuring consistent security enforcement regardless of how the agent is implemented.

#### Create Cedar Policy
<a name="policy-create-cedar-policy"></a>

Cedar is an open-source policy language developed by AWS for writing authorization policies. The **agentcore add policy** command creates a Cedar policy that governs tool calls through the gateway. You can either generate a policy from a natural-language description using `--generate` , or provide a Cedar policy file directly using `--source`.

The following is an example Cedar policy that allows refunds under \$11000:

```
permit(principal,
  action == AgentCore::Action::"RefundTarget___process_refund",
  resource == AgentCore::Gateway::"<gateway-arn>")
when {
  context.input.amount < 1000
};
```

The policy uses:
+  `permit` – Allows the action (Cedar also supports `forbid` to deny actions)
+  `principal` – The entity making the request
+  `action` – The specific tool being called (RefundTarget\$1\$1\$1process\$1refund)
+  `resource` – The gateway instance where the policy applies
+  `when` condition – Additional requirements (amount must be < \$11000)

#### Attach Policy to Gateway
<a name="policy-attach-to-gateway"></a>

The `--attach-to-gateways` and `--attach-mode ENFORCE` flags on the **agentcore add policy-engine** command attach the policy engine to the gateway in ENFORCE mode. In this mode:
+ Every tool call is intercepted and evaluated against all policies
+ By default, all actions are denied unless explicitly permitted
+ If any `forbid` policy matches, access is denied (forbid-wins semantics)
+ Policy decisions are logged to CloudWatch for monitoring and compliance

This ensures all agent operations through the gateway are governed by your security policies.

## Step 3: Deploy
<a name="policy-getting-started-run-setup"></a>

Deploy all resources to AWS:

```
agentcore deploy
```

The AgentCore CLI creates the gateway, registers the Lambda target, provisions the policy engine, and attaches the Cedar policy. This process takes approximately 2–3 minutes.

After deployment completes, you can verify the status of your resources:

```
agentcore status
```

## Step 4: Test the policy
<a name="policy-getting-started-test"></a>

Test the policy by sending requests to the gateway. Because the gateway uses `--authorizer-type NONE` , you can send requests directly with **curl**.

 **Test 1: Refund \$1500 (should be allowed)** 

The refund amount of \$1500 is under the \$11000 limit, so the policy engine permits the request:

```
curl -X POST ++<GATEWAY_URL>++ \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"RefundTarget___process_refund","arguments":{"amount":500}}}'
```

 **Test 2: Refund \$12000 (should be denied)** 

The refund amount of \$12000 exceeds the \$11000 limit, so the policy engine denies the request:

```
curl -X POST ++<GATEWAY_URL>++ \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"RefundTarget___process_refund","arguments":{"amount":2000}}}'
```

**Note**  
Replace `<GATEWAY_URL>` with the gateway URL shown in the output of **agentcore status**.

## What you’ve built
<a name="policy-getting-started-results"></a>

Through this tutorial, you’ve created:
+  **MCP Server (Gateway)** – A managed endpoint for tools
+  **Lambda target** – A refund processing tool registered in the gateway
+  **Policy engine** – Cedar-based policy evaluation system
+  **Cedar policy** – Governance rule allowing refunds under \$11000

## Troubleshooting
<a name="policy-getting-started-troubleshooting"></a>

If you encounter issues during setup or testing, refer to the following common problems and solutions:


| Issue | Solution | 
| --- | --- | 
|  "AccessDeniedException"  |  Check IAM permissions for bedrock-agentcore:\$1  | 
|  Gateway not responding  |  Wait 30–60 seconds after deployment for DNS propagation  | 
|  Deploy fails  |  Run **agentcore status** to check resource states and review error messages  | 
|  Policy not enforced  |  Verify the policy engine is attached in ENFORCE mode by running **agentcore status**   | 
|  Cedar validation error during deploy  |  Cedar policies must use specific resource ARNs — wildcard resources (e.g., `permit(principal, action, resource);` ) are rejected. Use the gateway ARN from **agentcore status** in your Cedar policy’s `resource` field.  | 
|  Tool call denied unexpectedly  |  The policy engine is enforcing and the Cedar policy denied the request. Verify that the policy’s `action` and `resource` fields match the tool call being made.  | 
|  Deploy fails with policy validation error  |  The default validation mode `FAIL_ON_ANY_FINDINGS` runs both schema checks and semantic validation, rejecting the policy if either produces findings. You can set the validation mode to `IGNORE_ALL_FINDINGS` to run only schema checks if you don’t need semantic validation. For production, fix the Cedar policy to pass both schema checks and semantic validation.  | 

## Clean up
<a name="policy-getting-started-cleanup"></a>

To remove the resources created in this tutorial, remove both the gateway and the policy engine, then redeploy:

```
agentcore remove gateway --name PolicyGateway
agentcore remove policy-engine --name RefundPolicyEngine
agentcore deploy
```

Removing a gateway does not automatically remove its attached policy engine. You must remove the policy engine separately using `agentcore remove policy-engine`.

# Core concepts
<a name="policy-core-concepts"></a>

Before using Policy in Amazon Bedrock AgentCore, it’s important to understand the key concepts and components that work together to provide policy-based governance for your AI agents.

**Topics**
+ [Gateway](#concept-gateway)
+ [Gateway Target](#concept-gateway-target)
+ [Principal types](#concept-principal-types)
+ [Cedar](#concept-cedar)
+ [Cedar Policy](#concept-cedar-policy)
+ [Policy engine](#concept-policy-engine)
+ [Cedar Schema](#concept-cedar-schema)
+ [Cedar validation](#concept-cedar-validation)
+ [Cedar analysis](#concept-cedar-analysis)
+ [Policy authoring service](#concept-policy-authoring-service)

## Gateway
<a name="concept-gateway"></a>

An Amazon Bedrock AgentCore Gateway provides an endpoint to connect to MCP servers and convert APIs and lambda to MCP compatible tools, providing a single access point for an agent to interact with its tools. A Gateway can have multiple targets, each representing a different tool or set of tools.

## Gateway Target
<a name="concept-gateway-target"></a>

A target defines the APIs or Lambda function that a Gateway will provide as tools to an agent. Targets can be Lambda functions, OpenAPI specifications, Smithy models, or other tool definitions.

## Principal types
<a name="concept-principal-types"></a>

Cedar policies use principals to represent the entity making an authorization request. Policy in AgentCore supports two principal types depending on how your AgentCore Gateway is configured for authentication:
+  **AgentCore::OAuthUser** - Represents OAuth-authenticated users. When a AgentCore Gateway uses OAuth authorization, the principal is created from the JWT token’s `sub` claim. OAuth principals support tags that contain JWT claims such as username, scope, role, etc.
+  **AgentCore::IamEntity** - Represents IAM-authenticated callers. When a AgentCore Gateway uses AWS\$1IAM authorization, the principal is created from the caller’s IAM ARN. IAM principals have an `id` attribute containing the full IAM ARN, which can be used for account-based or role-based access control.

## Cedar
<a name="concept-cedar"></a>

 [Cedar](https://docs.cedarpolicy.com) is an open-source policy language developed by AWS for writing and enforcing authorization policies. Cedar policies are human-readable, analyzable, and can be validated against a schema. Policy in AgentCore uses Cedar to provide precise, verifiable access control for gateway tools.

## Cedar Policy
<a name="concept-cedar-policy"></a>

A Cedar policy is a declarative statement that permits or forbids access to gateway tools. Each policy specifies who (principal) can perform what action (tool invocation) on which resource (gateway) under what conditions. Policies are evaluated for every tool invocation request.

## Policy engine
<a name="concept-policy-engine"></a>

The policy engine is the core component of Policy in AgentCore that stores and evaluates Cedar policies. When you create policies, they apply to every gateway which is associated with the engine, as long as the policy scope matches the request. For every tool invocation, the policy engine evaluates all applicable policies against the request to determine whether to allow or deny access. The engine enforces default-deny and forbid-wins semantics automatically.

## Cedar Schema
<a name="concept-cedar-schema"></a>

A Cedar schema defines the structure of entities, actions, and context for policy validation. The policy engine automatically generates a schema from the gateway’s tool definitions, mapping each tool to an action and defining the expected input parameters. The schema ensures policies are validated at creation time, catching errors before deployment.

## Cedar validation
<a name="concept-cedar-validation"></a>

Cedar validation checks that policies are syntactically correct and comply with the schema. When you associate policies to a gateway, the policy engine validates them against the auto-generated schema to ensure they reference valid actions, use correct data types, and access only defined context fields. Validation catches errors before policies are deployed, preventing runtime authorization failures.

## Cedar analysis
<a name="concept-cedar-analysis"></a>

Cedar analysis uses automated reasoning to examine policies and detect potential issues. Policy in AgentCore uses automated reasoning to identify policies that always allow (no conditions restrict access) or always deny (forbid policies with no exceptions), helping ensure policies implement intended access control rather than being overly permissive or unnecessarily restrictive.

## Policy authoring service
<a name="concept-policy-authoring-service"></a>

The policy authoring service automatically converts natural language authorization requirements into Cedar policies. When you submit a natural language policy, the service generates syntactically correct Cedar code, validates it against the gateway schema, and runs automated analysis to detect potential issues. This ensures all generated policies are valid and helps identify overly permissive or restrictive rules before deployment.

# AgentCore Gateway and Policy in AgentCore IAM Permissions
<a name="policy-permissions"></a>

This guide provides the required IAM permissions for using Amazon Bedrock AgentCore Gateway with Policy in AgentCore for fine-grained authorization control using Cedar policies.

## Overview
<a name="policy-permissions-overview"></a>

When integrating Amazon Bedrock AgentCore Gateway with Policy in AgentCore, two distinct IAM roles are required:

1.  **Gateway Execution Role** - The IAM role that Amazon Bedrock AgentCore Gateway assumes at runtime to invoke targets and evaluate Cedar policies

1.  **Resource Management Role** - The IAM role that administrators use to create and manage Amazon Bedrock AgentCore Gateway and Policy in AgentCore resources

Both roles serve different purposes and require specific permissions. The Gateway Execution Role needs permissions to run Amazon Bedrock AgentCore Gateway operations, while the Resource Management Role needs permissions to configure and manage Amazon Bedrock AgentCore Gateway and Policy in AgentCore resources.

## Gateway Execution Role
<a name="policy-permissions-execution-role"></a>

The Gateway Execution Role is assumed by the Amazon Bedrock AgentCore Gateway service when processing requests. This role requires permissions to:
+ Evaluate Cedar policies through Policy in AgentCore
+ Invoke targets such as Lambda functions and API Gateway endpoints
+ Write logs and traces to CloudWatch and X-Ray
+ Access secrets for authentication configurations

**Important**  
The execution role must include these three permissions to use Amazon Bedrock AgentCore Gateway with Policy in AgentCore: . `bedrock-agentcore:AuthorizeAction` - Evaluates Cedar policies for authorization decisions . `bedrock-agentcore:PartiallyAuthorizeActions` - Lists tools the caller is authorized to invoke . `bedrock-agentcore:GetPolicyEngine` - Retrieves the policy engine configuration Without these permissions, the Gateway cannot perform policy authorization. This manifests in two ways: attaching a Policy Engine to an existing Gateway will result in an InternalServerException, and all tool invocations will be denied by default even if you have permit policies configured.

### Trust Policy
<a name="policy-permissions-execution-trust"></a>

The Gateway Execution Role must trust the `bedrock-agentcore.amazonaws.com` service principal.

**Important**  
Replace the following placeholders: \$1 *us-east-1* with the AWS Region \$1 *123456789012* with the AWS account ID

```
{
"Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowBedrockAgentCoreAssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": "bedrock-agentcore.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "123456789012"
        },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:bedrock-agentcore:us-east-1:123456789012:*"
        }
      }
    }
  ]
}
```

### Permission Policy
<a name="policy-permissions-execution-permissions"></a>

This policy grants the Amazon Bedrock AgentCore Gateway the necessary permissions to evaluate Cedar policies through Policy in AgentCore. The permissions are split into two statements following least-privilege principles.

**Important**  
Replace these placeholders: \$1 *us-east-1* with the AWS Region \$1 *123456789012* with the AWS account ID \$1 *<gateway-id>* with the Gateway ID (or use \$1 for all gateways) \$1 *<policy-engine-id>* with the policy engine ID (or use \$1 for all policy engines)

```
{
"Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "PolicyEngineConfiguration",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:GetPolicyEngine"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:policy-engine/<policy-engine-id>"
      ]
    },
    {
      "Sid": "PolicyEngineAuthorization",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:AuthorizeAction",
        "bedrock-agentcore:PartiallyAuthorizeActions"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:policy-engine/<policy-engine-id>",
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/<gateway-id>"
      ]
    }
  ]
}
```

**Note**  
\$1 Additional permissions may be required depending on the Amazon Bedrock AgentCore Gateway integration type (e.g., Lambda functions, API Gateway endpoints). These permissions are not included here as they vary based on the specific integration. \$1 For Production: Replace the placeholders with specific resource IDs (e.g., `policy-engine/my-policy-engine-id` instead of `policy-engine/<policy-engine-id>` ) to follow least-privilege principles, or use wildcards ( \$1 ) to allow access to all resources of that type.

## Resource Management Role
<a name="policy-permissions-management-role"></a>

The Resource Management Role is used by administrators to create and manage Amazon Bedrock AgentCore Gateway and Policy in AgentCore resources. This role requires permissions to:
+ Create, update, and delete Gateways and Gateway targets
+ Create, update, and delete Policy Engines and Cedar policies
+ Pass the Gateway Execution Role to Amazon Bedrock AgentCore Gateway resources during creation
+ Tag resources for organization and management
+ Read IAM role information to validate execution role configurations

This role is separate from the Gateway Execution Role and is only needed when setting up or modifying Amazon Bedrock AgentCore Gateway and Policy in AgentCore configurations.

### Permission Policy
<a name="policy-permissions-management-permissions"></a>

**Important**  
Replace these placeholders: \$1 *us-east-1* with the AWS Region \$1 *123456789012* with the AWS account ID

```
{
"Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "GatewayManagement",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:CreateGateway",
        "bedrock-agentcore:UpdateGateway",
        "bedrock-agentcore:GetGateway",
        "bedrock-agentcore:DeleteGateway",
        "bedrock-agentcore:ListGateways",
        "bedrock-agentcore:InvokeGateway",
        "bedrock-agentcore:CreateGatewayTarget",
        "bedrock-agentcore:UpdateGatewayTarget",
        "bedrock-agentcore:GetGatewayTarget",
        "bedrock-agentcore:DeleteGatewayTarget",
        "bedrock-agentcore:ListGatewayTargets"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/*"
      ]
    },
    {
      "Sid": "PolicyEngineManagement",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:CreatePolicyEngine",
        "bedrock-agentcore:UpdatePolicyEngine",
        "bedrock-agentcore:GetPolicyEngine",
        "bedrock-agentcore:DeletePolicyEngine",
        "bedrock-agentcore:ListPolicyEngines"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:policy-engine/*"
      ]
    },
    {
      "Sid": "PolicyManagement",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:CreatePolicy",
        "bedrock-agentcore:UpdatePolicy",
        "bedrock-agentcore:GetPolicy",
        "bedrock-agentcore:DeletePolicy",
        "bedrock-agentcore:ListPolicies"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:policy-engine/*/policy/*"
      ]
    },
    {
      "Sid": "PolicyGeneration",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:StartPolicyGeneration",
        "bedrock-agentcore:GetPolicyGeneration",
        "bedrock-agentcore:ListPolicyGenerations",
        "bedrock-agentcore:ListPolicyGenerationAssets"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:policy-engine/*/policy-generation/*"
      ]
    },
    {
      "Sid": "IAMPassRole",
      "Effect": "Allow",
      "Action": [
        "iam:PassRole"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/*BedrockAgentCore*"
      ],
      "Condition": {
        "StringEquals": {
          "iam:PassedToService": "bedrock-agentcore.amazonaws.com"
        }
      }
    },
    {
      "Sid": "IAMReadAccess",
      "Effect": "Allow",
      "Action": [
        "iam:GetRole",
        "iam:GetRolePolicy",
        "iam:ListAttachedRolePolicies",
        "iam:ListRolePolicies"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/*"
      ]
    },
    {
      "Sid": "PolicyScopeManagement",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:ManageResourceScopedPolicy",
        "bedrock-agentcore:ManageAdminPolicy"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/*"
      ]
    }
  ]
}
```

**Important**  
The `ManageResourceScopedPolicy` and `ManageAdminPolicy` actions are permission-only gates that control what types of Cedar policies administrators can create: \$1 `ManageResourceScopedPolicy` - Grants permission to create Cedar policies that target specific gateway ARNs (e.g., policies applying to `gateway/my-gateway-123` ) \$1 `ManageAdminPolicy` - Grants permission to create Cedar policies with wildcards (e.g., policies applying to gateway/\$1 ) Both permissions are required for full policy management capability. These are not API operations but rather authorization checks that determine the scope of Cedar policies that can be created through the Policy Management APIs.

**Note**  
While the Resource field is included for consistency, these permission-only actions primarily gate capability at the action level rather than at the resource level.

## When Are Role Updates Required?
<a name="policy-permissions-when-required"></a>

Determine whether Policy in AgentCore permissions need to be added to the Amazon Bedrock AgentCore Gateway execution role based on how the Amazon Bedrock AgentCore Gateway was created.

 **Scenario 1: Gateway Created with AgentCore CLI**   
 **Status:** Action required  
The AgentCore CLI creates a gateway execution role with scoped permissions for target invocation and outbound authentication, but does not include Policy in AgentCore permissions. You must manually add the `AuthorizeAction` , `PartiallyAuthorizeActions` , and `GetPolicyEngine` permissions documented in this guide to the gateway execution role.

 **Scenario 2: Custom Execution Role**   
 **Status:** Action required  
Custom IAM roles require the Policy in AgentCore permissions documented in this guide to be added manually. Follow the permission policies in the sections above.

 **Scenario 3: Production Least-Privilege Configuration**   
 **Status:** Action required  
For production environments, scope the Policy in AgentCore permissions to specific resource ARNs rather than using wildcards. Replace policy-engine/\$1 and gateway/\$1 with the specific policy engine and gateway IDs in your permission policies.

## Troubleshooting
<a name="policy-permissions-troubleshooting"></a>

This section covers common issues when configuring IAM permissions for Amazon Bedrock AgentCore Gateway with Policy in AgentCore.

### InternalServerException During Policy Evaluation
<a name="policy-permissions-error-403"></a>

 **Symptom:** Gateway returns `InternalServerException - Policy evaluation failed` when attaching a Policy Engine to an existing Gateway, and all tool invocations are denied by default even with permit policies configured.

 **Root Cause:** The Gateway Execution Role is missing the required Policy in AgentCore permissions. Without these permissions, the Gateway cannot perform policy authorization.

 **Solution:** Ensure the Gateway Execution Role includes these three permissions:

```
{
  "Effect": "Allow",
  "Action": [
    "bedrock-agentcore:PartiallyAuthorizeActions",
    "bedrock-agentcore:AuthorizeAction",
    "bedrock-agentcore:GetPolicyEngine"
  ],
  "Resource": [
    "arn:aws:bedrock-agentcore:REGION:ACCOUNT:policy-engine/*",
    "arn:aws:bedrock-agentcore:REGION:ACCOUNT:gateway/*"
  ]
}
```

**Note**  
If you attach a Policy Engine to an existing Gateway using the Policy Engine console, the IAM permissions may not be automatically updated. You must manually add these permissions to the Gateway’s Service-Linked Role.

### Silent Failures in LOG\$1ONLY Mode
<a name="policy-permissions-error-silent"></a>

 **Symptom:** Policy engine appears to work in LOG\$1ONLY mode but fails silently without proper error messages.

 **Root Cause:** Missing `bedrock-agentcore:GetPolicyEngine` permission causes silent failures that only surface when switching to ENFORCED mode.

 **Solution:** Always include `bedrock-agentcore:GetPolicyEngine` in the Gateway Execution Role, even when using LOG\$1ONLY mode for testing.

### Policy Engine Not Found Error
<a name="policy-permissions-error-not-found"></a>

 **Symptom:** Amazon Bedrock AgentCore Gateway returns errors indicating it cannot find or access the policy engine.

 **Root Cause:** The Gateway Execution Role’s policy uses incorrect ARN patterns or is missing the policy-engine resource.

 **Solution:** Ensure both the policy-engine AND gateway ARNs are included in the Resource array:

```
"Resource": [
  "arn:aws:bedrock-agentcore:us-east-1:123456789012:policy-engine/<policy-engine-id>",
  "arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/<gateway-id>"
]
```

**Note**  
Both `AuthorizeAction` and `PartiallyAuthorizeActions` require access to BOTH the policy-engine and gateway resources.

### Debugging Tips
<a name="policy-permissions-debugging-tips"></a>

1.  **Enable CloudWatch Logs** - Configure detailed logging for the Amazon Bedrock AgentCore Gateway to capture policy evaluation details

1.  **Review X-Ray Traces** - Check AWS X-Ray traces to identify where authorization checks are failing

1.  **Start with LOG\$1ONLY Mode** - Use LOG\$1ONLY mode initially to test Cedar policies without blocking requests

1.  **Verify All Four Permissions** - Ensure `AuthorizeAction` , `PartiallyAuthorizeActions` , AND `GetPolicyEngine` are all present

1.  **Switch to ENFORCED Mode** - Only after verifying all permissions work in LOG\$1ONLY mode, switch to ENFORCED mode

## Example: Creating Both IAM Roles
<a name="policy-permissions-example"></a>

The following example demonstrates how to create both required IAM roles using the AWS CLI.

### Step 1: Create Gateway Execution Role
<a name="policy-permissions-example-execution"></a>

```
# Create the trust policy file
cat > gateway-trust-policy.json <<EOF
{
"Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "bedrock-agentcore.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "123456789012"
        },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:bedrock-agentcore:us-east-1:123456789012:*"
        }
      }
    }
  ]
}
EOF

# Create the IAM role
aws iam create-role \
  --role-name MyGatewayExecutionRole \
  --assume-role-policy-document file://gateway-trust-policy.json
```

### Step 2: Attach Permissions to Gateway Execution Role
<a name="policy-permissions-example-attach"></a>

```
# Create the permission policy file
cat > gateway-permissions.json <<EOF
{
"Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "PolicyEngineConfiguration",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:GetPolicyEngine"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:policy-engine/*"
      ]
    },
    {
      "Sid": "PolicyEngineAuthorization",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:AuthorizeAction",
        "bedrock-agentcore:PartiallyAuthorizeActions"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:policy-engine/*",
        "arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/*"
      ]
    }
  ]
}
EOF

# Attach the policy to the role
aws iam put-role-policy \
  --role-name MyGatewayExecutionRole \
  --policy-name GatewayPolicyEnginePermissions \
  --policy-document file://gateway-permissions.json
```

**Note**  
This example shows only the Policy in AgentCore permissions. Additional permissions for Amazon Bedrock AgentCore Gateway targets (Lambda, API Gateway, etc.) should be added based on your specific integration requirements.

### Step 3: Next Steps
<a name="policy-permissions-example-next"></a>

After configuring the execution role with the required Policy in AgentCore permissions, proceed to create and configure Policy resources. For detailed guidance, refer to:
+ Creating a Policy Engine - See the [Create a policy engine](policy-create-engine.md) 
+ Writing Cedar Policies - See the [Cedar Policy Language Reference](https://docs.cedarpolicy.com) 

## Best Practices
<a name="policy-permissions-best-practices"></a>

1.  **Use Separate Roles** - Maintain distinct roles for Amazon Bedrock AgentCore Gateway execution and resource management

1.  **Apply Least Privilege** - Start with specific resource ARNs rather than wildcards in production

1.  **Test with LOG\$1ONLY Mode** - Always test policy engine integration in LOG\$1ONLY mode before enforcing policies

1.  **Enable Monitoring** - Configure CloudWatch Logs and X-Ray tracing for troubleshooting and observability

1.  **Version Control Policies** - Store Cedar policies in version control alongside infrastructure code

1.  **Use Resource Tags** - Apply tags to organize and manage Amazon Bedrock AgentCore Gateway and Policy in AgentCore resources

1.  **Regular Security Audits** - Periodically review IAM policies to ensure they follow least privilege principles

# Create a policy engine
<a name="policy-create-engine"></a>

A policy engine is a collection of policies that evaluates and authorizes agent tool calls. When associated with a gateway, the policy engine intercepts all agent requests and determines whether to allow or deny each action based on the defined policies.

**Topics**
+ [Prerequisites](#policy-engine-prerequisites)
+ [Create a policy engine](#create-policy-engine-methods)
+ [Using the policy engine ARN](#policy-engine-arn-usage)

## Prerequisites
<a name="policy-engine-prerequisites"></a>

Before creating a policy engine, ensure you have a gateway setup. For more information, see [Building a gateway](https://docs.aws.amazon.com//bedrock-agentcore/latest/devguide/gateway-building.html).

## Create a policy engine
<a name="create-policy-engine-methods"></a>

The following shows how to create a policy engine.

**Example**  

1. Run the following code in a terminal to create a policy engine using the AWS CLI:

   ```
   aws bedrock-agentcore-control create-policy-engine \
     --name my_policy_engine \
     --description "My Policy Engine"
   ```

   The `policyEngineArn` in the response is the ARN to use when creating policies or associating with gateway.

1. The following Python code shows how to create a policy engine using the AWS Python SDK (Boto3):

   ```
   import boto3
   
   client = boto3.client('bedrock-agentcore-control')
   
   response = client.create_policy_engine(
       name='my_policy_engine',
       description='My Policy Engine'
   )
   
   print(f"Policy Engine ID: {response['policyEngineId']}")
   print(f"Policy Engine ARN: {response['policyEngineArn']}")
   ```

## Using the policy engine ARN
<a name="policy-engine-arn-usage"></a>

The `policyEngineArn` returned when creating a policy engine is used for two main purposes:
+  **Creating policies** - Use the ARN when adding policies to the engine
+  **Associating with gateways** - Use the ARN to enable policy enforcement on gateways

For more information about creating policies, see [Create a policy](policy-create-policies.md).

# Create a policy
<a name="policy-create-policies"></a>

Policy in Amazon Bedrock AgentCore uses Cedar as its authorization language to control access to tools and resources. This guide explains how to understand Cedar policies and write authorization requirements in natural language that can be automatically converted to Cedar. Natural language policy generation requires a deployed AgentCore Gateway and policy engine.

Cedar is a formal policy language that provides precise, verifiable access control. When working with AgentCore Gateway authorization:
+  **Understand Cedar policies** - Read and interpret existing Cedar policies to understand access control rules
+  **Write in natural language** - Express authorization requirements using clear, precise natural language
+  **Convert to Cedar** - Use policy authoring service to automatically generate Cedar policies from natural language
+  **Verify policies** - Review generated Cedar policies to ensure they match your requirements

You don’t need to memorize Cedar syntax. Focus on understanding policy structure and writing precise natural language requirements.

**Topics**
+ [Understanding Cedar policies](policy-understanding-cedar.md)
+ [Policy scope](policy-scope.md)
+ [Policy conditions](policy-conditions.md)
+ [Authorization flow](policy-authorization-flow.md)
+ [Schema constraints](policy-schema-constraints.md)
+ [Limitations](policy-limitations-section.md)
+ [Common policy patterns](policy-common-patterns.md)
+ [Time-based policy support](policy-time-based.md)

# Understanding Cedar policies
<a name="policy-understanding-cedar"></a>

Policy in AgentCore uses Cedar policies to control access to AgentCore Gateway tools. This section explains Cedar policy structure, evaluation semantics, and key concepts.

**Topics**
+ [Example policy](#policy-example)
+ [Policy structure](#policy-structure)
+ [Policy effects](#policy-effects)
+ [Default deny](#policy-default-deny)
+ [Authorization evaluation](#policy-authorization-evaluation)
+ [Policy independence](#policy-independence)
+ [Policy evaluation algorithm](#policy-evaluation-algorithm)

## Example policy
<a name="policy-example"></a>

Consider a refund processing tool with these requirements:
+ Only the user "John" can process refunds
+ Refunds are limited to \$1500 or less

The Cedar policy that enforces these requirements:

```
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"RefundTool__process_refund",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:your-region:your-account-id:gateway/refund-gateway"
)
when {
  principal.hasTag("username") &&
  principal.getTag("username") == "John" &&
  context.input.amount < 500
};
```

This policy allows refund processing only when the user is "John" and the refund amount is less than \$1500.

## Policy structure
<a name="policy-structure"></a>

Cedar policies consist of three main components:

1.  **Effect** - Determines whether to allow or deny access ( `permit` or `forbid` )

1.  **Scope** - Specifies the principal, action, and resource the policy applies to

1.  **Condition** - Defines additional logic that must be satisfied ( `when` or `unless` ) and can refer to the tool parameters (through the context) and the OAuth token (through the tags)

## Policy effects
<a name="policy-effects"></a>

Cedar policies use two effects to control access:
+  `permit` - Allows the action to proceed
+  `forbid` - Denies the action

## Default deny
<a name="policy-default-deny"></a>

All actions are denied by default. If no policies match a request, Cedar returns DENY. You must explicitly write permit policies to allow actions.

## Authorization evaluation
<a name="policy-authorization-evaluation"></a>

Cedar uses a forbid-overrides-permit evaluation model:

1. Cedar evaluates all policies that apply to the request

1. If any forbid policy matches, the result is DENY

1. If at least one permit policy matches and no forbid policies does, the result is ALLOW

1. If no policies match, the result is DENY (default deny)

## Policy independence
<a name="policy-independence"></a>

Each Cedar policy evaluates independently. A policy’s evaluation depends only on:
+ The scope (principal, action, resource)
+ The context and tags

Policies do not reference or depend on other policies.

## Policy evaluation algorithm
<a name="policy-evaluation-algorithm"></a>

When a request is evaluated, the policy engine determines the authorization decision using the following algorithm:

1. If any `forbid` policy matches the request, the decision is DENY.

1. If no `forbid` policy matches the request and at least one `permit` policy matches, the decision is ALLOW.

1. If neither `forbid` nor `permit` policies match the request, the decision is DENY.

This evaluation model enforces a **default deny** posture.

A `forbid` policy can never result in an ALLOW decision. The `unless` clause on a `forbid` policy specifies conditions under which that `forbid` policy does not apply; it does **not** grant permission and does not override a matching `permit` policy.

# Policy scope
<a name="policy-scope"></a>

The scope defines what the policy applies to. Every Cedar policy specifies three components:

**Topics**
+ [Entities and namespaces](#policy-entities-namespaces)
+ [Principal](#policy-principal)
+ [Action](#policy-action)
+ [Resource](#policy-resource)

```
permit(
  principal is AgentCore::OAuthUser,    // WHO is making the request
  action == AgentCore::Action::"...",   // WHAT they want to do
  resource is AgentCore::Gateway::"..." // WHICH resource they want to access
)
```

## Entities and namespaces
<a name="policy-entities-namespaces"></a>

Cedar uses entities to represent principals, actions, and resources. All entities in AgentCore Gateway use the AgentCore namespace.

Entity format: `Namespace::EntityType::"identifier"` 

## Principal
<a name="policy-principal"></a>

The principal identifies the entity making the authorization request. The principal type depends on how your AgentCore Gateway is configured for authentication.

### OAuth User Principal
<a name="policy-principal-oauth"></a>

When using OAuth authorization, the principal is an `AgentCore::OAuthUser` :

```
principal is AgentCore::OAuthUser
```

Components:
+  `principal` - The entity making the authorization request
+  `AgentCore::OAuthUser` - Entity type representing OAuth-authenticated users
+  `is` - Type check operator (matches any OAuthUser entity)

Principals are OAuth-authenticated users. Each user has a unique ID from the JWT sub claim.

### IAM Entity Principal
<a name="policy-principal-iam"></a>

When using AWS\$1IAM authorization, the principal is an `AgentCore::IamEntity` :

```
principal is AgentCore::IamEntity
```

Components:
+  `principal` - The entity making the authorization request
+  `AgentCore::IamEntity` - Entity type representing IAM-authenticated callers
+  `is` - Type check operator (matches any IamEntity)

IAM principals have an `id` attribute containing the caller’s IAM ARN. You can use pattern matching on this attribute to implement account-based or role-based access control.

## Action
<a name="policy-action"></a>

The action specifies the operation being requested:

```
action == AgentCore::Action::"RefundTool__process_refund"
```

Components:
+  `action` - The operation being requested
+  `AgentCore::Action::"RefundTool__process_refund"` - Specific action entity
+  `==` - Exact match operator (only this specific action)

Actions represent tool calls in the MCP AgentCore Gateway. Each tool has a corresponding action entity.

### Multiple actions
<a name="policy-action-wildcards"></a>

Cedar does **not** support wildcard actions. Each action must be referenced explicitly using the exact action identifier ( `AgentCore::Action::"ToolName__operation"` ). To group multiple tools under a single rule, use a **Gateway Target** (an Action Group) and write policies against that target.

For example, to allow access only to tools whose names start with Read, you can create a Gateway Target called ReadToolsTarget that includes each such tool, and then write a policy like:

```
permit(
  principal,
  action in AgentCore::Action::"ReadToolsTarget",
  resource == AgentCore::Gateway::"<gateway-arn>"
);
```

This will permit all tools included in that target depending on the policy’s effect.

## Resource
<a name="policy-resource"></a>

The resource identifies the target of the request:

```
resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/refund-gateway"
```

Components:
+  `resource` - The target of the request
+  `AgentCore::Gateway` - Entity type representing gateway instances
+  `==` - Exact match operator (matches this specific AgentCore Gateway)

The AgentCore Gateway is the MCP server that routes tool calls.

### Resource specificity requirements
<a name="policy-resource-specificity"></a>

When specifying one or more specific actions, you must use specific AgentCore Gateway ARNs:

```
// Required: Specific Gateway ARN for specific action(s)
resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/refund-gateway"
```

This applies to:
+ Single action: `action == AgentCore::Action::"ToolName"` 
+ Multiple specific actions: `action in [AgentCore::Action::"Tool1", AgentCore::Action::"Tool2"]` 

Use type checks only when matching any action:

```
// For policies covering any action (not specific tools)
resource is AgentCore::Gateway
```

Examples:

```
// Blocks all actions
forbid(principal, action, resource);

// Allow any CallTool action
permit(principal, action in AgentCore::Action::"CallTool", resource is AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/refund-gateway");
```

Specific AgentCore Gateway ARNs provide:
+ Security isolation between AgentCore Gateway instances
+ Separation of production and development environments
+ Fine-grained access control per AgentCore Gateway

# Policy conditions
<a name="policy-conditions"></a>

Conditions add fine-grained logic to policies using `when` and `unless` clauses:

```
when {
  principal.hasTag("username") &&
  principal.getTag("username") == "refund-agent" &&
  context.input.amount < 500
}
```

## Condition types
<a name="policy-condition-types"></a>
+  `when { …​ }` - Policy applies only if the condition is true
+  `unless { …​ }` - Policy applies only if the condition is false

## Tool arguments
<a name="policy-tool-arguments"></a>

 `context.input` contains the arguments passed to the tool call:

```
context.input.amount < 500
```

When a user calls `RefundTool__process_refund` with arguments like:

```
{
  "orderId": "12345",
  "amount": 450,
  "reason": "Defective product"
}
```

The policy can access these values:
+  `context.input.orderId` → "12345"
+  `context.input.amount` → 450
+  `context.input.reason` → "Defective product"

Policies can make decisions based on specific tool call parameters.

## Principal attributes
<a name="policy-principal-attributes"></a>

Principal attributes differ based on the authentication type configured for your AgentCore Gateway.

### OAuth claims (tags)
<a name="policy-oauth-claims"></a>

For OAuth-authenticated gateways, JWT claims from the OAuth token are stored as tags on the OAuthUser entity. Example JWT claims:

```
{
  "sub": "user-123",
  "username": "refund-agent",
  "scope": "refund:write admin:read",
  "role": "admin"
}
```

These claims become tags on the principal entity. Check if a tag exists:

```
principal.hasTag("username")
```

Get a tag value:

```
principal.getTag("username") == "refund-agent"
```

Pattern matching:

```
principal.getTag("scope") like "*refund:write*"
```

### IAM entity attributes
<a name="policy-iam-attributes"></a>

For IAM-authenticated gateways, the principal has an `id` attribute containing the caller’s IAM ARN. IAM principals do not support tags.

The `principal.id` attribute contains the full IAM ARN in one of these formats:
+  **IAM user:** `arn:aws:iam::123456789012:user/username` 
+  **IAM role (assumed):** `arn:aws:sts::123456789012:assumed-role/role-name/session-name` 
+  **IAM role:** `arn:aws:iam::123456789012:role/role-name` 

Use the `like` operator with wildcards to match patterns in the IAM ARN:

```
// Match specific AWS account
principal.id like "*:123456789012:*"

// Match specific IAM role
principal.id like "arn:aws:iam::*:role/AdminRole"

// Match any role in a specific account
principal.id like "arn:aws:iam::123456789012:role/*"

// Match assumed role sessions
principal.id like "arn:aws:sts::*:assumed-role/ServiceRole/*"
```

## Logical operators
<a name="policy-logical-operators"></a>

Combine multiple conditions using logical operators:
+  `&&` - AND (all conditions must be true)
+  `||` - OR (at least one condition must be true)
+  `!` - NOT (negates a condition)

Example:

```
principal.hasTag("username") &&              // User must have username tag
principal.getTag("username") == "refund-agent" &&  // Username must be "refund-agent"
context.input.amount < 500                   // Amount must be less than $500
```

# Authorization flow
<a name="policy-authorization-flow"></a>

Amazon Bedrock AgentCore Gateway evaluates Cedar policies against incoming requests. This section explains how authorization information flows from the request to policy evaluation.

## Request processing
<a name="policy-request-processing"></a>

Amazon Bedrock AgentCore Gateway processes two key pieces of information from each request:

1.  **JWT Token** - Contains OAuth claims about the user:

   ```
   {
     "sub": "12345678-1234-1234-1234-123456789012",
     "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_Vg2efaoGO",
     "username": "refund-agent",
     "scope": "aws.cognito.signin.user.admin refund:write",
     "role": "admin",
     "department": "finance"
   }
   ```

1.  **MCP Tool Call Request** - The actual tool invocation:

   ```
   {
     "jsonrpc": "2.0",
     "id": 1,
     "method": "tools/call",
     "params": {
       "name": "RefundTool__process_refund",
       "arguments": {
         "orderId": "12345",
         "amount": 450,
         "reason": "Defective product"
       }
     }
   }
   ```

## Cedar authorization request
<a name="policy-cedar-authorization-request"></a>

The Gateway extracts information from both sources and constructs a Cedar authorization request.

 **Complete Authorization Request:** 

```
{
  "principal": "AgentCore::OAuthUser::\"12345678-1234-1234-1234-123456789012\"",
  "action": "AgentCore::Action::\"RefundTool__process_refund\"",
  "resource": "AgentCore::Gateway::\"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/refund-gateway\"",
  "context": {
    "input": {
      "orderId": "12345",
      "amount": 450,
      "reason": "Defective product"
    }
  }
}
```

 **Components:** 

Principal  
Created from the JWT token’s sub claim:  

```
AgentCore::OAuthUser::"12345678-1234-1234-1234-123456789012"
```

Action  
Extracted from the tool name:  

```
AgentCore::Action::"RefundTool__process_refund"
```

Resource  
The Gateway instance:  

```
AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/refund-gateway"
```

Context  
Contains the tool arguments:  

```
{
  "input": {
    "orderId": "12345",
    "amount": 450,
    "reason": "Defective product"
  }
}
```

 **Entity Store** - The JWT claims are stored as tags on the OAuthUser entity:

```
{
  "uid": {
    "type": "AgentCore::OAuthUser",
    "id": "12345678-1234-1234-1234-123456789012"
  },
  "attrs": {
    "id": "12345678-1234-1234-1234-123456789012"
  },
  "tags": {
    "username": "refund-agent",
    "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_Vg2efaoGO",
    "scope": "aws.cognito.signin.user.admin refund:write",
    "role": "admin",
    "department": "finance"
  }
}
```

## Policy evaluation
<a name="policy-evaluation"></a>

Cedar evaluates:

1.  **Principal check:** Is the principal an OAuthUser? ✓ (matches)

1.  **Action check:** Is the action RefundTool\$1\$1process\$1refund? ✓ (matches)

1.  **Resource check:** Is the resource the refund gateway? ✓ (matches)

1.  **Condition checks:** 
   + Does principal have username tag? ✓ (yes, from JWT)
   + Is username = "refund-agent"? ✓ (yes)
   + Is context.input.amount < 500? ✓ (450 < 500)

 **Result:** ALLOW - All checks pass, the refund is authorized.

# Schema constraints
<a name="policy-schema-constraints"></a>

Policies for Amazon Bedrock AgentCore Gateway must validate against a specific Cedar schema that is automatically generated from the Gateway’s MCP tool manifest. This schema defines what’s possible in your policies.

**Topics**
+ [Principal Types](#policy-principal-type)
+ [Resource Type](#policy-resource-type)
+ [Actions](#policy-actions)
+ [Context](#policy-context)
+ [What You Cannot Do](#policy-limitations)

## Principal Types
<a name="policy-principal-type"></a>

The principal type depends on the authentication method configured for your AgentCore Gateway:

 `AgentCore::OAuthUser`   
+ Used for OAuth-authenticated gateways
+ Has an `id` attribute (from JWT sub claim)
+ Supports tags for OAuth claims (username, scope, role, etc.)

 `AgentCore::IamEntity`   
+ Used for IAM-authenticated gateways (AWS\$1IAM authorizer)
+ Has an `id` attribute containing the caller’s IAM ARN
+ Does not support tags; use pattern matching on `principal.id` for access control

## Resource Type
<a name="policy-resource-type"></a>
+ Must be `AgentCore::Gateway` 
+ Represents the MCP Gateway instance
+ Can be matched by type ( `is` ) or specific ARN ( `==` )
+ Must use specific ARNs to refer to specific actions

## Actions
<a name="policy-actions"></a>
+ Each MCP tool becomes an action: `AgentCore::Action::"ToolName"` 
+ All tool actions inherit from CallTool → Mcp hierarchy
+ Example: `Action::"RefundTool__process_refund"` is a CallTool

## Context
<a name="policy-context"></a>
+ Only available context is `context.input` 
+ Contains the tool’s input parameters as defined in the MCP manifest
+ Each tool has a typed input structure (e.g., RefundTool\$1\$1\$1process\$1refundInput)
+ Parameter types are automatically mapped from JSON Schema to Cedar types:
  + string → String
  + integer → Long
  + boolean → Bool
  + number → Decimal

## What You Cannot Do
<a name="policy-limitations"></a>
+ Cannot reference entity types outside AgentCore namespace
+ Cannot access context fields other than `context.input` 
+ Cannot use custom attributes on OAuthUser (use tags instead)
+ Cannot define new entity types in policies

# Limitations
<a name="policy-limitations-section"></a>

Cedar policies and the current Amazon Bedrock AgentCore Gateway implementation have certain limitations that affect policy authoring and functionality.

## Cedar language limitations
<a name="policy-cedar-limitations"></a>

The following limitations are inherent to the Cedar policy language:
+  **No floating-point numbers** - Cedar does not support float types. Use Decimal for fractional values (limited to 4 decimal places)
+  **No regular expressions** - Pattern matching is limited to the like operator with \$1 wildcards

## Current implementation limitations
<a name="policy-implementation-limitations"></a>

The following limitations are specific to the current Amazon Bedrock AgentCore Gateway implementation:
+  **Custom claims in NL2Cedar** - to use custom claims with NL2Cedar, provide the custom claims in the prompt
+  **Limited decimal precision** - Decimal values are limited to 4 decimal places and a specific range
+  **Max policy size** - 10 KB per individual policy
+  **Max total policy size per resource** - 200 KB combined across all policies per resource within a policy engine
+  **Cedar schema size** - supported schemas size under 100 KB
+  **Max Policies per Engine** - 1,000
+  **Max Policy Engines per account** - 1,000

These implementation limitations may be addressed in future releases.

# Common policy patterns
<a name="policy-common-patterns"></a>

These examples demonstrate frequently used Cedar policy patterns. The patterns work with both OAuth and IAM authentication—select the appropriate principal type for your AgentCore Gateway configuration. For details on principal attributes, see [Principal attributes](policy-conditions.md#policy-principal-attributes).

These patterns apply regardless of authentication type.

## Emergency shutdown
<a name="policy-emergency-shutdown"></a>

Disable all tool calls across the entire Gateway:

```
forbid(
  principal,
  action,
  resource
);
```

 **Use case:** Emergency shutdown, maintenance mode, or incident response.

 **Effect:** Overrides all permit policies due to forbid-wins semantics.

## Disable specific tool
<a name="policy-disable-specific-tool"></a>

Disable a specific tool while keeping others operational:

```
forbid(
  principal,
  action == AgentCore::Action::"RefundTool__process_refund",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/refund-gateway"
);
```

 **Use case:** Temporarily disable a problematic tool without affecting other functionality.

## Block user access
<a name="policy-block-user-access"></a>

Prevent specific users or accounts from performing any actions:

### OAuth: Block specific user
<a name="policy-oauth-block-user"></a>

Block a user by matching their username tag:

```
forbid(
  principal is AgentCore::OAuthUser,
  action,
  resource
)
when {
  principal.hasTag("username") &&
  principal.getTag("username") == "suspended-user"
};
```

 **Use case:** Immediately revoke access for a compromised or suspended user account.

### IAM: Block specific account
<a name="policy-iam-block-account"></a>

Block callers from a specific AWS account:

```
forbid(
  principal is AgentCore::IamEntity,
  action,
  resource
)
when {
  principal.id like "*:444455556666:*"
};
```

 **Use case:** Block test or unauthorized accounts from accessing production tools.

## Role-based access control
<a name="policy-role-based-patterns"></a>

Restrict access based on roles. OAuth uses role tags; IAM uses role ARN patterns.

### OAuth: Using role tags
<a name="policy-oauth-role-based"></a>

Permit access only to users with specific roles:

```
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"AdminAPI__delete_resource",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/admin"
)
when {
  principal.hasTag("role") &&
  (principal.getTag("role") == "admin" || principal.getTag("role") == "manager")
};
```

 **Use case:** Allow administrative operations only for users with admin or manager roles.

### IAM: Using IAM role ARNs
<a name="policy-iam-role-based"></a>

Permit access only to callers using specific IAM roles:

```
permit(
  principal is AgentCore::IamEntity,
  action == AgentCore::Action::"AdminAPI__delete_resource",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/admin"
)
when {
  principal.id like "arn:aws:iam::*:role/AdminRole"
};
```

 **Use case:** Allow administrative operations only for callers using the AdminRole IAM role.

 **Variations:** 

```
// Match assumed role sessions
principal.id like "arn:aws:sts::*:assumed-role/AdminRole/*"

// Match any role in a specific account
principal.id like "arn:aws:iam::123456789012:role/*"
```

## Data type operations
<a name="policy-data-type-operations"></a>

Cedar supports various data types in conditions. These examples use OAuth principals ( `AgentCore::OAuthUser` ). For IAM-authenticated gateways, use `AgentCore::IamEntity` instead - the input validation logic remains identical.

### Integers (Long)
<a name="policy-integers"></a>

```
// Check if passenger count is exactly 2
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"TravelAPI__search_flights",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/travel"
)
when {
  context.input.passengers == 2
};
```

### Strings
<a name="policy-strings"></a>

```
// Check if payment method is credit card
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"PaymentAPI__process_payment",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/payment"
)
when {
  context.input.paymentMethod == "credit-card"
};
```

### Lists (Sets)
<a name="policy-lists"></a>

```
// Check if country is in allowed list
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"ShippingAPI__calculate_rate",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/shipping"
)
when {
  ["US", "CA", "MX"].contains(context.input.country)
};
```

### Checking for Optional Fields
<a name="policy-optional-fields"></a>

```
// Require optional field to be present
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"OrderAPI__create_order",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/order"
)
when {
  context.input has shippingAddress
};
```

# Time-based policy support
<a name="policy-time-based"></a>

Policy in AgentCore supports time-based restrictions in Cedar policies through the `context.system.now` datetime value. This enables you to enforce policies based on specific dates, times, or time ranges.

**Topics**
+ [How it works](#policy-time-based-how)
+ [Absolute date and time range restrictions](#policy-time-absolute)
+ [Daily recurring time restrictions](#policy-time-daily)
+ [Combined date and time restrictions](#policy-time-combined)
+ [Timezone handling](#policy-time-timezone)
+ [Using natural language to generate time-based policies](#policy-time-natural-language)

## How it works
<a name="policy-time-based-how"></a>

During policy evaluation, the current UTC timestamp is provided as part of evaluation context:

```
// Current datetime in UTC
context.system.now
```

You can use Cedar’s datetime functions to create time-based conditions:
+  `datetime("YYYY-MM-DDTHH:MM:SSZ")` — Create a datetime value
+  `duration("Xh")` — Create a duration (hours, minutes, seconds)
+  `.toTime()` — Extract time of day from datetime
+ Comparison operators: `<` , `⇐` , `>` , `>=` , `==` 

## Absolute date and time range restrictions
<a name="policy-time-absolute"></a>

Enforce policies within specific calendar periods.

### Example: Promotional period policy
<a name="policy-time-absolute-example"></a>

```
permit(
  principal,
  action == AgentCore::Action::"RefundToolTarget___refund",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/my-gateway"
)
when {
  context.system.now >= datetime("2025-01-01T00:00:00Z") &&
  context.system.now < datetime("2025-01-31T23:59:59Z")
};
```

 **Use case:** Allow refunds only during January 2025.

## Daily recurring time restrictions
<a name="policy-time-daily"></a>

Enforce policies based on time of day that recur daily.

### Example: Business hours policy
<a name="policy-time-daily-example"></a>

```
permit(
  principal,
  action == AgentCore::Action::"RefundToolTarget___refund",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/my-gateway"
)
when {
  duration("9h") <= context.system.now.toTime() &&
  context.system.now.toTime() <= duration("17h")
};
```

 **Use case:** Allow refunds only during business hours (9 AM–5 PM UTC daily).

## Combined date and time restrictions
<a name="policy-time-combined"></a>

Combine absolute dates with daily time restrictions.

### Example: Limited-time promotion with daily hours
<a name="policy-time-combined-example"></a>

```
permit(
  principal,
  action == AgentCore::Action::"DiscountToolTarget___apply_discount",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/my-gateway"
)
when {
  // Valid dates: Feb 1-28, 2025
  context.system.now >= datetime("2025-02-01T00:00:00Z") &&
  context.system.now < datetime("2025-03-01T00:00:00Z") &&
  // Valid hours: 9am-9pm UTC daily
  duration("9h") <= context.system.now.toTime() &&
  context.system.now.toTime() <= duration("21h")
};
```

 **Use case:** Allow discount tool only during February 2025, between 9 AM and 9 PM UTC daily.

## Timezone handling
<a name="policy-time-timezone"></a>

All datetime values must be in UTC. The Policy Engine does not support timezone conversions or timezone-aware policies.

When specifying times in your policies, always use UTC. If your business operates in a different timezone, convert your local times to UTC before creating the policy.

## Using natural language to generate time-based policies
<a name="policy-time-natural-language"></a>

The policy authoring service can generate time-based policies from natural language descriptions.

### Example: Generate business hours policy
<a name="policy-time-nl-example"></a>

```
aws bedrock-agentcore-control start-policy-generation \
  --policy-engine-id MyEngine-abc123 \
  --name BusinessHoursOnly \
  --content '{
    "rawText": "Allow refunds only during business hours 9am to 5pm UTC"
  }' \
  --resource '{
    "arn": "arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/MyGateway-xyz789"
  }'
```

Generated policy:

```
permit(
  principal,
  action == AgentCore::Action::"RefundToolTarget___refund",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/MyGateway-xyz789"
)
when {
  duration("9h") <= context.system.now.toTime() &&
  context.system.now.toTime() <= duration("17h")
};
```

### Best practices for natural language
<a name="policy-time-nl-best-practices"></a>
+  **Be explicit about times** — Use "9am to 5pm UTC" instead of "business hours"
+  **Always specify UTC** — Include "UTC" to avoid ambiguity
+  **Use ISO format for dates** — Use "2025-01-01" instead of "January 1st"
+  **Provide specific time ranges** — Avoid vague terms like "daytime" or "after hours"

Good examples of natural language prompts:

```
"Allow refunds only between 9am and 5pm UTC"
"Allow payments except between 2am and 4am UTC daily"
"Allow discounts only from 2025-02-01 to 2025-02-28"
"Permit high-value transactions between 8am and 8pm UTC"
```

# Writing policies in natural language
<a name="policy-natural-language"></a>

Policy in AgentCore will automatically select the optimal region within your geography to process your inference requests made through Policy authoring service. This maximizes available compute resources, model availability, and delivers the best customer experience. Your data will remain stored only in the region where the request originated, however, input prompts and output results may be processed outside that region. All data will be transmitted encrypted across Amazon’s secure network.

Policy in AgentCore will securely route your inference requests to available compute resources within the geographic area where the request originated, as follows:
+ Inference requests originating in European Union will be processed within the European Union.
+ Inference requests originating in the United States will be processed within the United States.
+ Inference requests originating in APAC will be processed within APAC.

**Topics**
+ [Overview](#nl2cedar-overview)
+ [Example](#nl2cedar-example)
+ [Policy effects](#nl2cedar-policy-effects)
+ [Authorization semantics](#nl2cedar-authorization-semantics)
+ [Policy elements](#nl2cedar-policy-elements)
+ [Policy examples](#nl2cedar-policy-examples)
+ [Condition syntax](#nl2cedar-condition-syntax)
+ [Combining conditions](#nl2cedar-combining-conditions)
+ [Common pitfalls](#nl2cedar-common-pitfalls)

## Overview
<a name="nl2cedar-overview"></a>

Cedar provides precise access control, but requires learning formal syntax. NL2Cedar enables you to:

1. Write authorization requirements in natural language

1. Automatically convert to Cedar syntax

1. Verify generated policies match your requirements

**Note**  
Natural language policy generation requires a deployed AgentCore Gateway and policy engine. The service uses the AgentCore Gateway schema to generate valid Cedar policies. See [Getting started with Policy in AgentCore](policy-getting-started.md) for setup instructions.

**Note**  
Natural language is flexible, but precision is essential for security. Policies must be clear and unambiguous.

## Example
<a name="nl2cedar-example"></a>

The refund policy from the previous section can be expressed in natural language:

 **Natural language:** 

Allow principal with username "refund-agent" to process refunds when the refund amount is less than \$1500.

 **Converts to Cedar:** 

```
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"RefundTool__process_refund",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/refund-gateway"
)
when {
  principal.hasTag("username") &&
  principal.getTag("username") == "refund-agent" &&
  context.input.amount < 500
};
```

## Policy effects
<a name="nl2cedar-policy-effects"></a>

Authorization policies have two possible effects: permit and forbid.

**Topics**
+ [Permit policies](#nl2cedar-permit-policies)
+ [Forbid policies](#nl2cedar-forbid-policies)

### Permit policies
<a name="nl2cedar-permit-policies"></a>

Permit policies specify what users can do:
+ "Allow user refund-agent to process refunds"
+ "Permit users with role director to approve decisions"
+ "Authorize users with scope admin:write to update coverage"

### Forbid policies
<a name="nl2cedar-forbid-policies"></a>

Forbid policies specify what users cannot do:
+ "Block users from accessing high-sensitivity models"
+ "Deny junior underwriters from approving decisions"
+ "Forbid users from processing refunds when risk validation is pending"

## Authorization semantics
<a name="nl2cedar-authorization-semantics"></a>

Understanding how Cedar evaluates policies is crucial for writing effective authorization rules. Cedar follows three fundamental principles:
+  **By default, everything is denied** - If no policy explicitly permits an action, it’s automatically blocked
+  **Forbid always wins** - If any forbid policy matches, access is denied even if permit policies also match
+  **At least one permit required** - For access to be granted, at least one permit policy must match AND no forbid policies can match

 **Why use forbid policies if everything is denied by default?** 

Forbid policies ensure that specific actions cannot be mistakenly permitted. Even if someone writes a broader permit policy, the forbid policy takes precedence and blocks access.

 **Example scenario:** 

```
// Broad permit policy - allows all users to view model results
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"ModelAPI__view_results",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/model"
);

// Forbid policy - blocks access to high-sensitivity results
forbid(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"ModelAPI__view_results",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/model"
)
when {
  context.input.sensitivity == "high"
};
```

 **Result:** Users can view low and medium sensitivity results (permit applies), but high sensitivity results are always blocked (forbid wins).

Use forbid policies for:
+ Explicit security restrictions that must never be overridden
+ Compliance requirements
+ Emergency shutdowns
+ Creating exceptions to broader permit policies

## Policy elements
<a name="nl2cedar-policy-elements"></a>

Authorization policies require three key elements:

1.  **Who** - Which users or roles can perform the action

1.  **What** - Which operations or tools they can use

1.  **When** - Under what conditions or constraints

**Topics**
+ [Principal specification](#nl2cedar-principal-specification)
+ [Action specification](#nl2cedar-action-specification)
+ [Condition specification](#nl2cedar-condition-specification)

### Principal specification
<a name="nl2cedar-principal-specification"></a>

The principal identifies which users, roles, or groups the policy applies to.

Flexible expressions:
+ "Allow the user refund-agent to…​"
+ "Permit users with username refund-agent to…​"
+ "Users with role insurance-agent may…​"
+ "Anyone with the refund:write scope is authorized to…​"
+ "All users can…​"

Be specific about identity:

Incomplete: ❌ "Allow processing refunds under \$1500"

Complete: ✓ "Allow refund-agent to process refunds under \$1500"

### Action specification
<a name="nl2cedar-action-specification"></a>

The "what" identifies which operations, tools, or actions the policy controls.

Flexible action verbs:
+ "Allow users to process refunds"
+ "Permit refund processing"
+ "Users can create applications"
+ "Authorize viewing audit logs"

Be specific about the tool:

Vague: ❌ "Allow users to access models"

Clear: ✓ "Allow data-science team to access the analytics model"

### Condition specification
<a name="nl2cedar-condition-specification"></a>

The "when" specifies under what circumstances the policy applies.

Flexible conditional expressions:
+ "…​when the amount is less than \$1500"
+ "…​if the region is US, CA, or UK"
+ "…​only when approval status is approved-by-manager"
+ "…​provided that the risk score has been submitted"

Be precise with conditions:

Vague: ❌ "Allow transfers when the amount is reasonable"

Precise: ✓ "Allow transfers when the amount is less than \$110,000"

## Policy examples
<a name="nl2cedar-policy-examples"></a>

The following examples demonstrate how to structure natural language policies with clear principals, actions, and conditions.

**Topics**
+ [Example 1: Simple User-Based Policy](#nl2cedar-example-1)
+ [Example 2: Role-Based with Multiple Conditions](#nl2cedar-example-2)
+ [Example 3: Scope-Based Access](#nl2cedar-example-3)
+ [Example 4: Everyone with Constraints](#nl2cedar-example-4)

### Example 1: Simple User-Based Policy
<a name="nl2cedar-example-1"></a>

Allow user refund-agent to process refunds when the amount is less than \$1500.

Elements:
+  **Who:** user refund-agent
+  **What:** process refunds
+  **When:** amount is less than \$1500

### Example 2: Role-Based with Multiple Conditions
<a name="nl2cedar-example-2"></a>

Allow users with role insurance-agent to update coverage when the coverage type is liability or collision and the policy is active.

Elements:
+  **Who:** users with role insurance-agent
+  **What:** update coverage
+  **When:** coverage type is liability or collision AND policy is active

### Example 3: Scope-Based Access
<a name="nl2cedar-example-3"></a>

Allow users with scope travel:book to create flight bookings when the region is not EU and the product is eligible.

Elements:
+  **Who:** users with scope travel:book
+  **What:** create flight bookings
+  **When:** region is not EU AND product is eligible

### Example 4: Everyone with Constraints
<a name="nl2cedar-example-4"></a>

Allow all users to view model results when the data sensitivity is low or medium and the result type is risk-score.

Elements:
+  **Who:** all users
+  **What:** view model results
+  **When:** data sensitivity is low or medium AND result type is risk-score

## Condition syntax
<a name="nl2cedar-condition-syntax"></a>

Conditions are where policies often become ambiguous. Here’s how to write clear, testable conditions.

**Topics**
+ [Numeric Comparisons](#nl2cedar-numeric-comparisons)
+ [String Matching](#nl2cedar-string-matching)
+ [Boolean Conditions](#nl2cedar-boolean-conditions)
+ [Field Existence](#nl2cedar-field-existence)

### Numeric Comparisons
<a name="nl2cedar-numeric-comparisons"></a>

Good examples:
+ "when the amount is less than \$1500"
+ "when the coverage amount is under 5 million"
+ "when the claim exceeds \$110,000,000"
+ "when the passenger count is exactly 2"

Avoid vague terms:
+ ❌ "when the amount is small"
+ ❌ "when the coverage is high"

### String Matching
<a name="nl2cedar-string-matching"></a>

Exact match:
+ "when the region is US"
+ "when the payment method is credit-card"
+ "when the status is approved"

Multiple options:
+ "when the region is US or CA or UK"
+ "when the decision type is approve or refer"

Pattern matching:
+ "when the email contains @example.com"
+ "when the scope contains admin:write"

Negation:
+ "when the region is not EU"
+ "when the classification is not restricted"

### Boolean Conditions
<a name="nl2cedar-boolean-conditions"></a>

Direct checks:
+ "when the product is eligible"
+ "when the risk score is submitted"
+ "when express shipping is requested"

Negation:
+ "when the product is not eligible"
+ "when the risk score is not submitted"

### Field Existence
<a name="nl2cedar-field-existence"></a>

Requiring fields:
+ "when a reason is provided"
+ "when an application ID exists"
+ "when the return date is specified"

## Combining conditions
<a name="nl2cedar-combining-conditions"></a>

Real policies often need multiple conditions. Use clear logical connectors.

**Topics**
+ [AND Logic (All Must Be True)](#nl2cedar-and-logic)
+ [OR Logic (At Least One Must Be True)](#nl2cedar-or-logic)
+ [Complex Logic](#nl2cedar-complex-logic)

### AND Logic (All Must Be True)
<a name="nl2cedar-and-logic"></a>

Use words like: "and", "also", "additionally", "while", "with"

Example:

Allow applications when the region is US and the product is eligible and the territory is active.

### OR Logic (At Least One Must Be True)
<a name="nl2cedar-or-logic"></a>

Use words like: "or", "alternatively", "either"

Example:

Allow approval when the claim exceeds \$110,000,000 or the risk level is high or critical.

### Complex Logic
<a name="nl2cedar-complex-logic"></a>

For complex conditions, use clear structure:

Example:

Allow finalization when the workflow stage is review-complete or approved, and the compliance status is passed, and the authority is manager or director.

## Common pitfalls
<a name="nl2cedar-common-pitfalls"></a>

Avoid these common mistakes when writing natural language policies to ensure they convert correctly to Cedar syntax.

**Topics**
+ [Mistake 1: Vague Principals](#nl2cedar-mistake-1)
+ [Mistake 2: Ambiguous Actions](#nl2cedar-mistake-2)
+ [Mistake 3: Subjective Conditions](#nl2cedar-mistake-3)
+ [Mistake 4: Missing Conditions](#nl2cedar-mistake-4)
+ [Mistake 5: Unclear Logic](#nl2cedar-mistake-5)

### Mistake 1: Vague Principals
<a name="nl2cedar-mistake-1"></a>

Bad: "Allow access to the refund tool"

Good: "Allow user refund-agent to access the refund tool"

### Mistake 2: Ambiguous Actions
<a name="nl2cedar-mistake-2"></a>

Bad: "Allow users to access data"

Good: "Allow users to view patient records"

### Mistake 3: Subjective Conditions
<a name="nl2cedar-mistake-3"></a>

Bad: "Allow transfers when the amount is reasonable"

Good: "Allow transfers when the amount is less than \$110,000"

### Mistake 4: Missing Conditions
<a name="nl2cedar-mistake-4"></a>

Bad: "Allow users with scope admin:write to update coverage"

Good: "Allow users with scope admin:write to update coverage when the policy is active and the coverage type is liability or collision"

### Mistake 5: Unclear Logic
<a name="nl2cedar-mistake-5"></a>

Bad: "Allow when A or B and C"

Good: "Allow when (A or B) and C" or "Allow when A or (B and C)"

# Validate and test policies
<a name="policy-validate-policies"></a>

Before deploying policies to production, Policy in AgentCore provides validation capabilities to catch errors and identify potential issues. Validation works differently depending on whether you are generating policies from natural language or creating and updating policies directly.

Schema checks always run to verify that policies comply with the Cedar schema for your gateways. Semantic validation (automated reasoning) detects security and logic issues and can be controlled through the `validationMode` parameter. For more information about these capabilities and the validation modes, see [Validation and analysis overview](policy-validation-overview.md).

**Topics**
+ [Validation and analysis overview](policy-validation-overview.md)
+ [Policy generation: per-policy validation](policy-generation-validation.md)
+ [Policy create and update: per-policy engine validation](policy-create-update-validation.md)

# Validation and analysis overview
<a name="policy-validation-overview"></a>

## Schema checks
<a name="policy-schema-checks"></a>

Schema checks verify that policies comply with the Cedar schema for your gateways:
+  **Schema compliance** — Checks that policies reference valid actions (tools), use correct data types, and access only defined context fields
+  **Type safety** — Ensures parameter types match the gateway’s tool definitions

## Semantic validation (automated reasoning)
<a name="policy-semantic-validation"></a>

Semantic validation uses automated reasoning to detect potential security and logic issues:
+  **Overly permissive policies** — If created, the policy engine will allow all requests for the specified principal, action, and resource combination
+  **Overly restrictive policies** — If created, the policy engine will deny all requests for the specified principal, action, and resource combination
+  **Ineffective policies** — If created, the policy has no impact: a Permit policy does not allow any requests, or a Forbid policy does not deny any requests. This applies at the policy level during generation, not at the policy engine level

## Validation modes
<a name="policy-validation-modes"></a>

The `validationMode` parameter controls whether semantic validation runs during policy creation and updates. It does **not** affect schema checks, which always run.
+  `FAIL_ON_ANY_FINDINGS` (default) — Both schema checks and semantic validation run. If either produces findings, the policy is rejected.
+  `IGNORE_ALL_FINDINGS` — Only schema checks run. Policies are accepted as long as they pass the schema checks. This is not recommended for production because semantic validation catches security and logic issues that schema checks alone cannot detect.

# Policy generation: per-policy validation
<a name="policy-generation-validation"></a>

When using the policy authoring service to generate policies from natural language, validation and analysis occur **per individual policy** during generation.

## How it works
<a name="policy-generation-validation-how"></a>

1. Natural language is converted to a Cedar policy

1. Each generated policy is validated against the gateway schema

1. Analysis runs on each policy individually

1. Results are available in the generation response

## Example: Generate and validate a policy
<a name="policy-generation-validation-example"></a>

Retrieving generation results is a two-step process: first check the generation status, then list the generated assets to see the policies and their validation findings.

Start a policy generation:

```
aws bedrock-agentcore-control start-policy-generation \
  --policy-engine-id MyEngine-abc123 \
  --name RefundPolicy \
  --content '{
    "rawText": "Allow customer service agents to process refunds up to 500 dollars for orders placed within the last 30 days"
  }' \
  --resource '{
    "arn": "arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/MyGateway-xyz789"
  }'
```

The response includes a policy generation ID and status:

```
{
  "policyGenerationId": "RefundPolicy-def456",
  "policyEngineId": "MyEngine-abc123",
  "status": "GENERATING"
}
```

Check the generation status using `get-policy-generation` :

```
aws bedrock-agentcore-control get-policy-generation \
  --policy-engine-id MyEngine-abc123 \
  --policy-generation-id RefundPolicy-def456
```

The response shows the overall generation status:

```
{
  "policyGenerationId": "RefundPolicy-def456",
  "status": "GENERATED",
  "statusReasons": []
}
```

Once the status is `GENERATED` , list the generated assets to retrieve the policies and their per-policy validation findings:

```
aws bedrock-agentcore-control list-policy-generation-assets \
  --policy-engine-id MyEngine-abc123 \
  --policy-generation-id RefundPolicy-def456
```

The response includes each generated policy with its Cedar definition and validation findings:

```
{
  "policyGenerationAssets": [
    {
      "policyGenerationAssetId": "asset-1",
      "definition": {
        "cedar": {
          "statement": "permit(\n  principal is AgentCore::OAuthUser,\n  action == AgentCore::Action::\"RefundTool__process_refund\",\n  resource == AgentCore::Gateway::\"arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/MyGateway-xyz789\"\n) when {\n  context.input.amount <= 500\n};"
        }
      },
      "findings": [
        {
          "type": "VALID"
        }
      ],
      "rawTextFragment": "Allow customer service agents to process refunds up to 500 dollars"
    },
    {
      "policyGenerationAssetId": "asset-2",
      "definition": {
        "cedar": {
          "statement": "permit(\n  principal,\n  action == AgentCore::Action::\"RefundTool__view_order_history\",\n  resource\n);"
        }
      },
      "findings": [
        {
          "type": "ALLOW_ALL",
          "description": "Overly Permissive: Policy Engine will allow every request for the specified principal (AgentCore::OAuthUser), action (RefundTool__view_order_history) and resource (gateway/*) combination if the policy is added or updated"
        }
      ],
      "rawTextFragment": "Allow customer service agents to view order history"
    }
  ]
}
```

## Validation findings per policy
<a name="policy-generation-findings"></a>

Each generated policy asset includes a `findings` array of `Finding` objects, each with a `type` and `description` . The following examples show different finding types:

A policy that passed validation and analysis:

```
{
  "findings": [
    {
      "type": "VALID"
    }
  ]
}
```

A policy flagged as overly permissive:

```
{
  "findings": [
    {
      "type": "ALLOW_ALL",
      "description": "Overly Permissive: Policy Engine will allow every request for the specified principal (AgentCore::OAuthUser), action (RefundTool__view_order_history) and resource (gateway/*) combination if the policy is added or updated"
    }
  ]
}
```

A policy that could not be generated from the natural language input:

```
{
  "findings": [
    {
      "type": "NOT_TRANSLATABLE",
      "description": "Unsupported Condition Error: The request includes conditions that rely on data or attributes currently not supported."
    }
  ]
}
```

## Common findings for generated policies
<a name="policy-common-findings"></a>

The following table describes the finding types that can be returned for generated policies:


| Finding type | Severity | Description | Recommended action | 
| --- | --- | --- | --- | 
|   `VALID`   |  Success  |  Policy is valid Cedar with no findings. No description is returned for this finding type.  |  No action required. The policy is ready to use.  | 
|   `INVALID`   |  Error  |  The generated Cedar policy contains syntax errors or does not comply with the gateway schema.  |  Review the generated policy for schema violations or syntax issues. Rephrase the natural language input and regenerate.  | 
|   `NOT_TRANSLATABLE`   |  Error  |  Natural language could not be converted to valid Cedar. The request may include conditions that rely on unsupported data or attributes.  |  Double check targeted gateway resource for tools definition.  | 
|   `ALLOW_ALL`   |  Warning  |  Permit policy applies to all principal, action, and resource combinations.  |  Confirm that unrestricted access is intended. Add conditions to restrict the scope if not.  | 
|   `ALLOW_NONE`   |  Warning  |  Permit policy is non-determining because it permits nothing.  |  Review the policy conditions. The policy may contain contradictory or unreachable conditions.  | 
|   `DENY_ALL`   |  Warning  |  Policy denies all actions for all principals.  |  Confirm that a full deny is intended. This overrides all permit policies due to forbid-overrides-permit semantics.  | 
|   `DENY_NONE`   |  Warning  |  Forbid policy is non-determining because it denies nothing.  |  Review the policy conditions. The forbid policy may contain contradictory or unreachable conditions.  | 

# Policy create and update: per-policy engine validation
<a name="policy-create-update-validation"></a>

When creating or updating policies directly (not through generation), validation and analysis takes into account the new policy as well as its interactions with **all preexisting policies** in the policy engine.

## How it works
<a name="policy-create-update-validation-how"></a>

1. The policy is checked against the Cedar schema for **all gateways** associated with the policy engine. Schema checks always run regardless of the validation mode.

1. If the validation mode is set to `FAIL_ON_ANY_FINDINGS`, semantic validation runs in the context of the **entire policy engine**, checking for overly permissive, overly restrictive, and ineffective policies. If either schema checks or semantic validation produces findings, the policy is rejected. For details on each check, see [Validation and analysis overview](policy-validation-overview.md).

**Note**  
With `IGNORE_ALL_FINDINGS`, only schema checks run. Policies are accepted as long as they pass the schema checks. For more information, see [Add policies to the Policy Engine](add-policies-to-engine.md).

## Example: Create a policy with validation
<a name="policy-create-validation-example"></a>

Create a policy with strict validation that rejects policies with any findings:

```
aws bedrock-agentcore-control create-policy \
  --policy-engine-id MyEngine-abc123 \
  --name RestrictRefunds \
  --validation-mode FAIL_ON_ANY_FINDINGS \
  --definition '{
    "cedar": {
      "statement": "forbid(\n  principal,\n  action == Action::\"processRefund\",\n  resource\n) when {\n  context.amount > 1000\n};"
    }
  }'
```

The response indicates the policy is being created:

```
{
  "policyId": "RestrictRefunds-ghi789",
  "status": "CREATING"
}
```

Check the policy status to confirm validation passed:

```
aws bedrock-agentcore-control get-policy \
  --policy-engine-id MyEngine-abc123 \
  --policy-id RestrictRefunds-ghi789
```

When validation passes, the policy becomes active:

```
{
  "policyId": "RestrictRefunds-ghi789",
  "status": "ACTIVE",
  "statusReasons": []
}
```

## Example: Validation failure
<a name="policy-validation-failure-example"></a>

If a policy references an action that doesn’t exist in any associated gateway’s schema, validation fails:

```
aws bedrock-agentcore-control create-policy \
  --policy-engine-id MyEngine-abc123 \
  --name InvalidPolicy \
  --validation-mode FAIL_ON_ANY_FINDINGS \
  --definition '{
    "cedar": {
      "statement": "permit(\n  principal,\n  action == Action::\"nonExistentTool\",\n  resource\n);"
    }
  }'
```

When you check the policy status, the response shows the validation failure:

```
aws bedrock-agentcore-control get-policy \
  --policy-engine-id MyEngine-abc123 \
  --policy-id InvalidPolicy-jkl012
```

```
{
  "policyId": "InvalidPolicy-jkl012",
  "status": "CREATE_FAILED",
  "statusReasons": [
    "Validation failed: Action 'nonExistentTool' is not defined in the schema for any associated gateway"
  ]
}
```

# Use policies
<a name="policy-use-policies"></a>

This section explains how to create and manage Cedar policies.

**Topics**
+ [Add policies to the Policy Engine](add-policies-to-engine.md)
+ [Create gateway with Policy Engine](create-gateway-with-policy.md)
+ [Update existing gateway with Policy Engine](update-gateway-with-policy.md)
+ [Policy enforcement modes](policy-enforcement-modes.md)
+ [Use an AgentCore Gateway with Policy in AgentCore](use-gateway-with-policy.md)
+ [Manage Policies and Policy Engines](manage-policies-engines.md)
+ [Errors](policy-use-errors.md)

# Add policies to the Policy Engine
<a name="add-policies-to-engine"></a>

You can create one or more policies in your policy engine to control how agents interact with your enterprise tools and data through Amazon Bedrock AgentCore Gateway.

**Note**  
Use the policy engine ID from the previous step. The validation mode controls how findings are handled. Schema checks always run regardless of the validation mode. `FAIL_ON_ANY_FINDINGS` runs both schema checks and semantic validation, rejecting the policy if either produces findings. `IGNORE_ALL_FINDINGS` runs only schema checks, and policies are accepted as long as they pass. For more information about validation and the types of findings, see [Validate and test policies](policy-validate-policies.md).

Select one of the following methods:

**Example**  

1. Run the following code in a terminal to create a policy using the AWS CLI:

   ```
   aws bedrock-agentcore-control create-policy \
     --policy-engine-id my-policy-engine-id \
     --name my_policy \
     --validation-mode FAIL_ON_ANY_FINDINGS \
     --description "My Policy" \
     --definition '{
       "cedar": {
         "statement": "my-cedar-policy-statement"
       }
     }'
   ```

1. The following Python code shows how to create a policy using the AWS Python SDK (Boto3):

   ```
   import boto3
   
   client = boto3.client('bedrock-agentcore-control')
   
   response = client.create_policy(
       policyEngineId='my-policy-engine-id',
       name='my_policy',
       validationMode='FAIL_ON_ANY_FINDINGS',
       description='My Policy',
       definition={
           'cedar': {
               'statement': 'my-cedar-policy-statement'
           }
       }
   )
   print(f"Policy ID: {response['policyId']}")
   ```

# Create gateway with Policy Engine
<a name="create-gateway-with-policy"></a>

This section provides examples of creating a gateway with a policy engine associated for policy enforcement.

**Note**  
\$1 The values for the authorization configuration are from when you set up inbound authorization. \$1 If you choose an option that involves specifying an overt gateway service role ARN, ensure that you specify an existing one that you’ve set up. For more information, see Amazon Bedrock AgentCore Gateway service role permissions.

Select one of the following methods:

**Example**  

1. Run the following code in a terminal to create a gateway with a Policy Engine using the AWS CLI:

   ```
   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"]
       }
     }' \
     --policy-engine-configuration '{
       "mode": "ENFORCE",
       "arn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:policy-engine/my_policy_engine"
     }'
   ```

   The gatewayUrl in the response is the endpoint to use when you invoke the gateway.

1. The following Python code shows how to create a gateway with a Policy Engine using the AWS Python SDK (Boto3):

   ```
   import boto3
   
   gateway_client = boto3.client('bedrock-agentcore-control')
   
   response = gateway_client.create_gateway(
       name='my-gateway',
       protocolType='MCP',
       authorizerType='CUSTOM_JWT',
       authorizerConfiguration={
           'customJWTAuthorizer': {
               'allowedClients': ['clientId'],
               'discoveryUrl': 'https://cognito-idp.us-west-2.amazonaws.com/some-user-pool/.well-known/openid-configuration'
           }
       },
       roleArn='arn:aws:iam::123456789012:role/my-gateway-service-role',
       policyEngineConfiguration={
           'mode': 'ENFORCE',
           'arn': 'arn:aws:bedrock-agentcore:us-west-2:123456789012:policy-engine/my_policy_engine'
       }
   )
   print(f"GATEWAY ARN: {response['gatewayArn']}")
   print(f"GATEWAY URL: {response['gatewayUrl']}")
   ```

   The gatewayUrl in the response is the endpoint to use when you invoke the gateway.

# Update existing gateway with Policy Engine
<a name="update-gateway-with-policy"></a>

Associate a policy engine with an existing gateway:

**Example**  

1. Run the following code in a terminal to update a gateway with a Policy Engine using the AWS CLI:

   ```
   aws bedrock-agentcore-control update-gateway \
     --gateway-identifier my-gateway-id \
     --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"]
       }
     }' \
     --policy-engine-configuration '{
       "mode": "ENFORCE",
       "arn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:policy-engine/my_policy_engine"
     }'
   ```

   The gatewayUrl in the response is the endpoint to use when you invoke the gateway.

1. The following Python code shows how to update a gateway with a Policy Engine using the AWS Python SDK (Boto3):

   ```
   import boto3
   
   gateway_client = boto3.client('bedrock-agentcore-control')
   
   response = gateway_client.update_gateway(
       name='my-gateway-name',
       gatewayId='my-gateway-id',
       protocolType='MCP',
       authorizerType='CUSTOM_JWT',
       authorizerConfiguration={
           'customJWTAuthorizer': {
               'allowedClients': ['clientId'],
               'discoveryUrl': 'https://cognito-idp.us-west-2.amazonaws.com/some-user-pool/.well-known/openid-configuration'
           }
       },
       roleArn='arn:aws:iam::123456789012:role/my-gateway-service-role',
       policyEngineConfiguration={
           'mode': 'ENFORCE',
           'arn': 'arn:aws:bedrock-agentcore:us-west-2:123456789012:policy-engine/my_policy_engine'
       }
   )
   
   print(f"GATEWAY ARN: {response['gatewayArn']}")
   print(f"GATEWAY URL: {response['gatewayUrl']}")
   ```

   The gatewayUrl in the response is the endpoint to use when you invoke the gateway.

# Policy enforcement modes
<a name="policy-enforcement-modes"></a>

Enforcement mode defines how the gateway applies policy decisions. The policy engine supports two modes:
+ In `LOG_ONLY` mode, the policy engine evaluates and logs whether the action is would be allowed or denied without enforcing the the decision
+ In `ENFORCE` mode, the policy engine evaluates the action and enforces decisions by allowing or denying agent operations.

# Use an AgentCore Gateway with Policy in AgentCore
<a name="use-gateway-with-policy"></a>

Follow the gateway authorization and authentication guide to obtain the credentials needed for gateway access.

**Topics**
+ [List AgentCore Gateway Tools with Policy in AgentCore](#list-gateway-tools)
+ [Call gateway tools with policy](#call-gateway-tools)
+ [Policy responses](#policy-responses)

## List AgentCore Gateway Tools with Policy in AgentCore
<a name="list-gateway-tools"></a>

Tool listing is treated as a **meta action** . When a principal lists available tools, the policy engine does not evaluate the full context of a specific tool invocation (for example, input parameters).

A principal is only allowed to see tools in the listing that they would be permitted to call by policy. Because the full context of a tool call is not available during listing, this means a principal is allowed to list a tool **if there exists any set of circumstances under which a call to that tool would be permitted**.

As a result, a tool appearing in the list does not guarantee that a subsequent call to that tool will be authorized. The authorization decision for an actual tool invocation is evaluated separately using the full request context, including input parameters.

Select one of the following methods:

**Example**  

1. 

   ```
   curl -X POST \
     https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
     -d '{
       "jsonrpc": "2.0",
       "id": "list-tools-request",
       "method": "tools/list"
     }'
   ```

1. 

   ```
   import requests
   import json
   
   def list_tools(gateway_url, access_token):
       headers = {
           "Content-Type": "application/json",
           "Authorization": f"Bearer {access_token}"
       }
   
       payload = {
           "jsonrpc": "2.0",
           "id": "list-tools-request",
           "method": "tools/list"
       }
   
       response = requests.post(gateway_url, headers=headers, json=payload)
       return response.json()
   
   # Example usage
   gateway_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
   access_token = "YOUR_ACCESS_TOKEN"
   tools = list_tools(gateway_url, access_token)
   print(json.dumps(tools, indent=2))
   ```

   The response returns only the tools that your policies allow you to see. Tools that are denied by policies will not appear in the list.

## Call gateway tools with policy
<a name="call-gateway-tools"></a>

Make tool calls to your gateway. Policy evaluation determines whether the call is allowed or denied.

Select one of the following methods:

**Example**  

1. 

   ```
   # Call a tool to test policy enforcement
   curl -X POST \
     https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
     -d '{
       "jsonrpc": "2.0",
       "id": "test-policy",
       "method": "tools/call",
       "params": {
         "name": "tool_name",
         "arguments": {arguments}
       }
     }'
   ```

1. 

   ```
   import requests
   import json
   
   def call_gateway_tool(gateway_url, access_token, tool_name, arguments):
       headers = {
           "Content-Type": "application/json",
           "Authorization": f"Bearer {access_token}"
       }
   
       payload = {
           "jsonrpc": "2.0",
           "id": "test-policy",
           "method": "tools/call",
           "params": {
               "name": tool_name,
               "arguments": arguments
           }
       }
   
       response = requests.post(gateway_url, headers=headers, json=payload)
       return response.json()
   
   # Example usage
   gateway_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
   access_token = "YOUR_ACCESS_TOKEN"
   result = call_gateway_tool(
       gateway_url,
       access_token,
       "RefundTool__process_refund",
       {
           "orderId": "12345",
           "amount": 450,
           "reason": "Defective product"
       }
   )
   print(json.dumps(result, indent=2))
   ```

## Policy responses
<a name="policy-responses"></a>

When a policy allows the request:

```
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "isError": false,
    "content": [
      {
        "type": "text",
        "text": "ToolResult"
      }
    ]
  }
}
```

When a policy denies the request:

```
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "AuthorizeActionException - Tool Execution Denied: Tool call not allowed due to policy enforcement [No policy applies to the request (denied by default).]"
      }
    ],
    "isError": true
  }
}
```

# Manage Policies and Policy Engines
<a name="manage-policies-engines"></a>

Use these operations to manage your Policy Engines and policies.

**Topics**
+ [List Policy Engines](#list-policy-engines)
+ [Get Policy Engine](#get-policy-engine)
+ [List policies in a Policy Engine](#list-policies-in-engine)
+ [Get Policy](#get-policy)
+ [Update existing policies](#update-existing-policies)
+ [Delete policies](#delete-policies)
+ [Delete Policy Engine](#delete-policy-engine)

## List Policy Engines
<a name="list-policy-engines"></a>

View all Policy Engines in your account.

Select one of the following methods:

**Example**  

1. 

   ```
   aws bedrock-agentcore-control list-policy-engines
   ```

1. 

   ```
   import boto3
   
   client = boto3.client('bedrock-agentcore-control')
   
   response = client.list_policy_engines()
   for engine in response['policyEngines']:
       print(f"Policy Engine: {engine['name']} (ID: {engine['policyEngineId']})")
       print(f"Status: {engine['status']}")
       print(f"Created: {engine['createdAt']}")
       print(f"ARN: {engine['policyEngineArn']}")
   ```

## Get Policy Engine
<a name="get-policy-engine"></a>

Retrieve detailed information about a specific Policy Engine:

**Example**  

1. 

   ```
   aws bedrock-agentcore-control get-policy-engine --policy-engine-id my-policy-engine-id
   ```

1. 

   ```
   import boto3
   
   client = boto3.client('bedrock-agentcore-control')
   
   response = client.get_policy_engine(
       policyEngineId='my-policy-engine-id'
   )
   
   print(f"Policy Engine: {response['name']}")
   print(f"ID: {response['policyEngineId']}")
   print(f"ARN: {response['policyEngineArn']}")
   print(f"Status: {response['status']}")
   print(f"Created: {response['createdAt']}")
   print(f"Updated: {response['updatedAt']}")
   ```

## List policies in a Policy Engine
<a name="list-policies-in-engine"></a>

View all policies within a specific Policy Engine:

**Example**  

1. 

   ```
   aws bedrock-agentcore-control list-policies --policy-engine-id my-policy-engine-id
   ```

1. 

   ```
   import boto3
   
   client = boto3.client('bedrock-agentcore-control')
   
   response = client.list_policies(
       policyEngineId='my-policy-engine-id'
   )
   
   for policy in response['policies']:
       print(f"Policy: {policy['name']} (ID: {policy['policyId']})")
       print(f"Status: {policy['status']}")
       print(f"Description: {policy.get('description', 'No description')}")
       print(f"Created: {policy['createdAt']}")
   ```

## Get Policy
<a name="get-policy"></a>

Retrieve detailed information about a specific policy:

**Example**  

1. 

   ```
   aws bedrock-agentcore-control get-policy --policy-engine-id my-policy-engine-id --policy-id my-policy-id
   ```

1. 

   ```
   import boto3
   
   client = boto3.client('bedrock-agentcore-control')
   
   response = client.get_policy(
       policyId='my-policy-id',
       policyEngineId='my-policy-engine-id'
   )
   
   print(f"Policy: {response['name']}")
   print(f"ID: {response['policyId']}")
   print(f"ARN: {response['policyArn']}")
   print(f"Status: {response['status']}")
   print(f"Created: {response['createdAt']}")
   print(f"Updated: {response['updatedAt']}")
   print(f"Cedar Statement: {response['definition']['cedar']['statement']}")
   ```

## Update existing policies
<a name="update-existing-policies"></a>

Update a policy’s definition.

**Example**  

1. 

   ```
   aws bedrock-agentcore-control update-policy \
     --policy-id my-policy-id \
     --policy-engine-id my-policy-engine-id \
     --definition '{
       "cedar": {
         "statement": "permit(principal, action, resource);"
       }
     }'
   ```

1. 

   ```
   import boto3
   
   client = boto3.client('bedrock-agentcore-control')
   
   client.update_policy(
       policyId='my-policy-id',
       policyEngineId='my-policy-engine-id',
       definition={
           'cedar': {
               'statement': 'permit(principal, action, resource);'
           }
       }
   )
   
   waiter = client.get_waiter('policy_active')
   waiter.wait(PolicyEngineId="my-policy-engine-id", PolicyId="my-policy-id")
   ```

## Delete policies
<a name="delete-policies"></a>

Delete a policy from the Policy Engine.

**Example**  

1. 

   ```
   aws bedrock-agentcore-control delete-policy --policy-engine-id my-policy-engine-id --policy-id my-policy-id
   ```

1. 

   ```
   import boto3
   
   client = boto3.client('bedrock-agentcore-control')
   
   client.delete_policy(policyId='my-policy-id', policyEngineId='my-policy-engine-id')
   waiter = client.get_waiter('policy_deleted')
   waiter.wait(PolicyEngineId="my-policy-engine-id", PolicyId="my-policy-id")
   ```

## Delete Policy Engine
<a name="delete-policy-engine"></a>

Delete an entire Policy Engine and all its policies.

**Note**  
\$1 You cannot delete a Policy Engine that is currently attached to a gateway. First detach it by updating the gateway configuration. \$1 You cannot delete a Policy Engine that has policies in it. First delete all the policies and then delete the engine

**Example**  

1. 

   ```
   aws bedrock-agentcore-control delete-policy-engine --policy-engine-id my-policy-engine-id
   ```

1. 

   ```
   import boto3
   
   client = boto3.client('bedrock-agentcore-control')
   
   client.delete_policy_engine(policyEngineId='my-policy-engine-id')
   ```

# Errors
<a name="policy-use-errors"></a>

Policy in AgentCore operations can return the following types of errors:

AuthorizationError  
The policy engine denied the request.  
HTTP Status Code: 403

AccessDeniedException  
You don’t have permission to perform this operation.  
HTTP Status Code: 403

ConflictException  
The request conflicts with the current state of the resource (e.g., policy name already exists).  
HTTP Status Code: 409

InternalServerException  
An internal server error occurred.  
HTTP Status Code: 500

ResourceNotFoundException  
The specified policy or policy engine does not exist.  
HTTP Status Code: 404

ServiceQuotaExceededException  
You have exceeded the service quota for policies or policy engines.  
HTTP Status Code: 402

ThrottlingException  
The request was throttled due to too many requests.  
HTTP Status Code: 429

ValidationException  
The request contains invalid parameters or the policy statement contains syntax errors.  
HTTP Status Code: 400

# Example policies
<a name="example-policies"></a>

This section provides comprehensive examples of Cedar authorization policies for an insurance management system. These examples demonstrate various Cedar language features and authorization patterns that you can adapt for your own applications.

**Topics**
+ [Available tools](#available-tools)
+ [Authorization policies](#authorization-policies)
+ [Understanding authorization semantics](#authorization-semantics)
+ [Test scenarios](#test-scenarios)
+ [IAM-based authorization examples](#iam-authorization-examples)

## Available tools
<a name="available-tools"></a>

The Insurance API provides five tools for managing insurance policies and claims:

InsuranceAPI\$1\$1get\$1policy  
Retrieve insurance policy details.  
 **Parameters:**   
+  `policyId` (string, required) - The policy identifier

InsuranceAPI\$1\$1file\$1claim  
File an insurance claim.  
 **Parameters:**   
+  `policyId` (string, required) - The policy identifier
+  `claimType` (string, required) - Type of claim (e.g., "health", "property", "auto")
+  `amount` (number, required) - Claim amount
+  `description` (string, optional) - Claim description

InsuranceAPI\$1\$1update\$1coverage  
Update policy coverage.  
 **Parameters:**   
+  `policyId` (string, required) - The policy identifier
+  `coverageType` (string, required) - Type of coverage (e.g., "liability", "collision")
+  `newLimit` (number, required) - New coverage limit

InsuranceAPI\$1\$1get\$1claim\$1status  
Check claim status.  
 **Parameters:**   
+  `claimId` (string, required) - The claim identifier

InsuranceAPI\$1\$1calculate\$1premium  
Calculate insurance premium.  
 **Parameters:**   
+  `coverageType` (string, required) - Type of coverage
+  `coverageAmount` (number, required) - Coverage amount
+  `riskFactors` (object, optional) - Risk assessment factors

## Authorization policies
<a name="authorization-policies"></a>

The following policies demonstrate various Cedar language features and authorization patterns. Each policy includes natural language description, Cedar code, and detailed explanation.

### Policy 1: Multi-action permit
<a name="policy-1-multi-action"></a>

This policy demonstrates how to grant access to multiple related actions using a single policy statement.

 **Natural language:** Allow all principals to get policy and get claim status.

 **Cedar policy:** 

```
permit(
  principal is AgentCore::OAuthUser,
  action in [
    AgentCore::Action::"InsuranceAPI__get_policy",
    AgentCore::Action::"InsuranceAPI__get_claim_status"
  ],
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/insurance"
);
```

 **Explanation:** This policy demonstrates multi-action permits using the `in` operator. Instead of writing separate policies for each read operation, a single policy grants access to multiple related actions. This is useful for grouping similar operations that share the same authorization requirements.

### Policy 2: Scope-based authorization
<a name="policy-2-scope-based"></a>

This policy shows how to use OAuth scopes to control access to specific operations.

 **Natural language:** Allow principals with scope containing "insurance:claim" to file claims.

 **Cedar policy:** 

```
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"InsuranceAPI__file_claim",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/insurance"
)
when {
  principal.hasTag("scope") &&
  principal.getTag("scope") like "*insurance:claim*"
};
```

 **Explanation:** This policy demonstrates OAuth scope validation using tags. The `hasTag` method checks if the tag exists, and `getTag` retrieves its value. The `like` operator with wildcards (\$1) performs pattern matching, allowing flexible scope formats like "insurance:claim", "insurance:claim:write", or "admin insurance:claim".

### Policy 3: Role-based authorization with unless
<a name="policy-3-role-based"></a>

This policy demonstrates using the `unless` clause to create exceptions to restrictions.

 **Natural language:** Block principals from updating coverage unless the principal has role "senior-adjuster" or "manager".

 **Cedar policy:** 

```
forbid(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"InsuranceAPI__update_coverage",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/insurance"
)
unless {
  principal.hasTag("role") &&
  (principal.getTag("role") == "senior-adjuster" || principal.getTag("role") == "manager")
};
```

 **Explanation:** This policy demonstrates the `unless` clause, which inverts the condition logic. The forbid applies unless the user has one of the specified roles. This is useful for creating exceptions to restrictions. The policy also shows OR logic for checking multiple acceptable values.

### Policy 4: String equality with OR logic
<a name="policy-4-string-equality"></a>

This policy shows how to validate input parameters and use OR logic for multiple acceptable values.

 **Natural language:** Allow principals to file claims when the claim type is health, property, or auto.

 **Cedar policy:** 

```
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"InsuranceAPI__file_claim",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/insurance"
)
when {
  context.input has claimType &&
  (context.input.claimType == "health" ||
   context.input.claimType == "property" ||
   context.input.claimType == "auto")
};
```

 **Explanation:** This policy demonstrates accessing tool input parameters via `context.input` and string equality checks with OR logic. The `has` operator first verifies the field exists before accessing it, preventing errors when optional fields are missing.

### Policy 5: Field existence check
<a name="policy-5-field-existence"></a>

This policy demonstrates how to enforce business rules by requiring optional fields.

 **Natural language:** Block principals from filing claims unless a description is provided.

 **Cedar policy:** 

```
forbid(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"InsuranceAPI__file_claim",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/insurance"
)
unless {
  context.input has description
};
```

 **Explanation:** This policy demonstrates enforcing required fields for optional parameters. The description field is optional in the tool schema, but this policy makes it mandatory by forbidding requests that don’t include it. This shows how policies can add business rules beyond schema validation.

### Policy 6: Username-based authorization
<a name="policy-6-username-based"></a>

This policy shows how to grant access based on specific user identities.

 **Natural language:** Allow principals with username "Clare" to update coverage.

 **Cedar policy:** 

```
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"InsuranceAPI__update_coverage",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/insurance"
)
when {
  principal.hasTag("username") &&
  principal.getTag("username") == "Clare"
};
```

 **Explanation:** This policy demonstrates username-based authorization using exact string matching. Combined with Policy 3, this creates a two-part authorization: users must have the username "insurance-agent" AND have the role "senior-adjuster" or "manager" to update coverage.

### Policy 7: Pattern matching with like
<a name="policy-7-pattern-matching"></a>

This policy demonstrates flexible pattern matching using wildcards for category-based access control.

 **Natural language:** Allow principals to calculate premium when the coverage type contains "auto".

 **Cedar policy:** 

```
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"InsuranceAPI__calculate_premium",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/insurance"
)
when {
  context.input has coverageType &&
  context.input.coverageType like "*auto*"
};
```

 **Explanation:** This policy demonstrates flexible pattern matching with the `like` operator. The wildcard \$1 matches any characters, so "auto", "auto-liability", "comprehensive-auto", or "auto-collision" would all match. This is useful when you want to match a category of values rather than exact strings.

### Policy 8: Combined conditions with AND
<a name="policy-8-combined-conditions"></a>

This policy shows how to combine multiple conditions to create complex authorization rules.

 **Natural language:** Allow principals to update coverage when the coverage type is liability or collision and a new limit is provided.

 **Cedar policy:** 

```
permit(
  principal is AgentCore::OAuthUser,
  action == AgentCore::Action::"InsuranceAPI__update_coverage",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/insurance"
)
when {
  context.input has coverageType &&
  context.input has newLimit &&
  (context.input.coverageType == "liability" || context.input.coverageType == "collision")
};
```

 **Explanation:** This policy demonstrates combining multiple conditions with AND logic. All three conditions must be true: coverageType must exist, newLimit must exist, and coverageType must be either "liability" or "collision". This works with Policy 6 to create layered authorization: who can update (Policy 6) and what they can update (Policy 8).

## Understanding authorization semantics
<a name="authorization-semantics"></a>

These policies demonstrate key Cedar authorization semantics:

### Default deny
<a name="default-deny"></a>

If no policy explicitly permits an action, it’s denied. For example, a user without the "insurance:claim" scope cannot file claims even though no policy explicitly forbids it.

### Forbid wins
<a name="forbid-wins"></a>

If any forbid policy matches, the request is denied even if permit policies also match. Policy 5 (forbid without description) overrides Policy 2 (permit with scope) when description is missing.

### Policy layering
<a name="policy-layering"></a>

Multiple policies can apply to the same request:
+ Policy 6 permits insurance-agent to update coverage
+ Policy 3 forbids updates unless user has senior-adjuster or manager role
+ Policy 8 permits updates only for liability or collision types

For a request to succeed, it must satisfy all three: be insurance-agent (Policy 6), have senior-adjuster or manager role (Policy 3), and update liability or collision (Policy 8).

## Test scenarios
<a name="test-scenarios"></a>

The following scenarios demonstrate how the policies work together in practice:

Scenario 1: Regular user viewing policy  
 **User:** username="john", scope="insurance:view"  
 **Action:** get\$1policy  
 **Expected:** ALLOW (Policy 1)

Scenario 2: User filing health claim with description  
 **User:** username="jane", scope="insurance:claim"  
 **Action:** file\$1claim with claimType="health", description="Medical expenses"  
 **Expected:** ALLOW (Policy 2, Policy 4, Policy 5 does not forbid)

Scenario 3: User filing claim without description  
 **User:** username="jane", scope="insurance:claim"  
 **Action:** file\$1claim with claimType="health", no description  
 **Expected:** DENY (Policy 5 forbid wins)

Scenario 4: Insurance agent updating coverage  
 **User:** username="insurance-agent", role="senior-adjuster"  
 **Action:** update\$1coverage with coverageType="liability"  
 **Expected:** ALLOW (Policy 6, Policy 3 does not forbid, Policy 8)

Scenario 5: Insurance agent without senior role  
 **User:** username="insurance-agent", role="agent"  
 **Action:** update\$1coverage with coverageType="liability"  
 **Expected:** DENY (Policy 3 forbid wins)

Scenario 6: Premium calculation for auto coverage  
 **User:** username="anyone", scope="any"  
 **Action:** calculate\$1premium with coverageType="auto-liability"  
 **Expected:** ALLOW (Policy 7, pattern matches "auto")

## IAM-based authorization examples
<a name="iam-authorization-examples"></a>

When your AgentCore Gateway uses AWS\$1IAM authentication instead of OAuth, the principal in Cedar policies is represented as `AgentCore::IamEntity` . IAM principals have an `id` attribute containing the caller’s IAM ARN, which enables account-based and role-based access control using pattern matching.

### Basic IAM entity permit
<a name="iam-policy-basic"></a>

This policy permits any IAM-authenticated caller to use a specific tool:

```
permit(
  principal is AgentCore::IamEntity,
  action == AgentCore::Action::"OrderAPI__get_order",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/order-gateway"
);
```

 **Explanation:** This is the simplest form of IAM policy. It permits any caller authenticated via AWS\$1IAM to call the get\$1order tool. Use this when you only need to verify that callers are IAM-authenticated without additional restrictions.

### Account-based restriction
<a name="iam-policy-account-restriction"></a>

Restrict tool access to callers from specific AWS accounts:

```
permit(
  principal is AgentCore::IamEntity,
  action == AgentCore::Action::"OrderAPI__process_order",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/order-gateway"
)
when {
  principal.id like "*:111122223333:*"
};
```

 **Explanation:** The `principal.id` contains the full IAM ARN (e.g., `arn:aws:iam::111122223333:role/MyRole` ). The pattern \$1:111122223333:\$1 matches any ARN containing that account ID. This restricts access to callers from the specified AWS account only.

### Role-based restriction
<a name="iam-policy-role-restriction"></a>

Restrict administrative tools to specific IAM roles:

```
permit(
  principal is AgentCore::IamEntity,
  action == AgentCore::Action::"AdminAPI__delete_resource",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/admin-gateway"
)
when {
  principal.id like "arn:aws:iam::*:role/AdminRole"
};
```

 **Explanation:** This policy uses pattern matching to restrict access to callers using a specific IAM role name. The wildcard \$1 in the account position allows the role from any account. To restrict to a specific account, use the full account ID: `arn:aws:iam::111122223333:role/AdminRole`.

### IAM with input validation
<a name="iam-policy-combined"></a>

Combine IAM principal matching with tool input validation:

```
permit(
  principal is AgentCore::IamEntity,
  action == AgentCore::Action::"RefundAPI__process_refund",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/refund-gateway"
)
when {
  principal.id like "*:111122223333:*" &&
  context.input has amount &&
  context.input.amount < 1000
};
```

 **Explanation:** This policy combines account-based access control with input validation. Only callers from the specified account can process refunds, and only when the refund amount is less than \$11000. This demonstrates how IAM authorization works alongside the same `context.input` conditions used with OAuth.

### Forbid specific accounts
<a name="iam-policy-forbid"></a>

Block callers from specific AWS accounts from accessing sensitive tools:

```
forbid(
  principal is AgentCore::IamEntity,
  action == AgentCore::Action::"AdminAPI__delete_resource",
  resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/admin-gateway"
)
when {
  principal.id like "*:444455556666:*"
};
```

 **Explanation:** This forbid policy blocks all callers from a third-party vendor account (444455556666) from performing administrative deletions. Even though the vendor may have been granted IAM permissions for other operations, this policy ensures they cannot delete resources. Due to forbid-wins semantics, this takes precedence over any permit policies.

# Advanced features and topics for Policy in AgentCore
<a name="policy-advanced"></a>

This chapter covers some advanced topics and additional information that can help supplement your knowledge of Policy in AgentCore and how you can use it effectively in your applications.

**Topics**
+ [Encrypt your AgentCore policy engine with a customer-managed KMS key](policy-encryption.md)

# Encrypt your AgentCore policy engine with a customer-managed KMS key
<a name="policy-encryption"></a>

Policy in AgentCore provides encryption by default to protect sensitive customer data at rest using AWS owned encryption keys. As an extra layer of protection, Policy in AgentCore allows you to encrypt your policy engines using AWS Key Management Service (AWS KMS) customer managed keys (CMK). This functionality ensures protection of sensitive data via encryption at rest, which helps you:
+ Reduce the operational burden on service’s end to protect sensitive data
+ Maintain control over who can see details of your authorization policies via your own AWS KMS customer managed keys
+ Build security-sensitive applications that meet strict encryption compliance and regulatory requirements

The following sections explain how to configure encryption for new policy engines and manage your encryption keys.

**Note**  
Policy in AgentCore encryption at rest is available in all AWS Regions where Policy in AgentCore is available.

## AWS KMS key types for Policy in AgentCore
<a name="policy-encryption-key-types"></a>

Policy in AgentCore integrates with AWS KMS to manage encryption keys used for encrypting and decrypting customer data. To learn more about key types and states, see [AWS Key Management Service concepts](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html) in the AWS KMS Developer Guide. When you create a new policy engine, you can choose from the following AWS KMS key types to encrypt your data:

### AWS owned key
<a name="policy-encryption-aws-owned"></a>

The default encryption type. Policy in AgentCore owns the key at no additional charge to you and encrypts resource data at rest upon creation. No additional configuration is required in your code or applications to encrypt or decrypt your data using the key owned by Policy in AgentCore. You don’t need to view, manage, use, or audit these keys. For more information, see [AWS owned keys](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-owned-cmk) in the AWS KMS Developer Guide.

### Customer managed key
<a name="policy-encryption-customer-managed"></a>

You create, own, and manage the key in your AWS account. You have full control over the KMS key. AWS KMS charges apply for customer managed keys. For more information, see the [AWS KMS Pricing page](https://aws.amazon.com/kms/pricing/) . For more information about key types, see [Customer managed keys](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#customer-cmk) in the AWS KMS Developer Guide.

When you specify a customer managed key for encryption of a policy engine, Policy in AgentCore encrypts the policy engine and all its child resources (policies, policy generations) with that key. To encrypt a policy engine using a customer managed key, you need to grant access to Policy in AgentCore in your key policy. A key policy is a resource-based policy that you attach to your customer managed key to control access to it. See [Authorizing use of your AWS KMS key for Policy in AgentCore](#policy-encryption-authorize-key) for more details.

In addition, to create an encrypted policy engine with a customer managed key, or to make API calls to a policy engine encrypted by a customer managed key, the IAM user or role which makes the call must also have access to the key. If Policy in AgentCore is unable to access the key, any authorization decisions that involve resources encrypted by that key will be denied. When you do not have access to the key, you will not be able to read, update, or delete resources encrypted by that key, and any create calls to utilize the key for encryption will fail.

**Important**  
Once a customer managed key has been used to encrypt a policy engine, you CANNOT update the resource to use a different key for encryption or remove the key from that policy engine.

## Using AWS KMS and data keys with Policy in AgentCore
<a name="policy-encryption-how-it-works"></a>

The Policy in AgentCore encryption at rest feature uses a KMS key and a hierarchy of data keys to protect your resource data.

**Note**  
Policy in AgentCore supports only symmetric AWS KMS keys. You can’t use an asymmetric KMS key to encrypt your Policy in AgentCore resources.

Policy in AgentCore uses a grant-based model to access your customer managed key. When you create a policy engine with a customer managed key, Policy in AgentCore performs the following steps:

1. Policy in AgentCore validates the key to ensure it is a symmetric encryption key with `ENCRYPT_DECRYPT` key usage and is in the `Enabled` state.

1. Policy in AgentCore creates two AWS KMS grants on your behalf. To create these grants, Policy in AgentCore calls `kms:CreateGrant` using your identity through a [Forward Access Session (FAS)](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_forward_access_sessions.html) . Because the `CreateGrant` call is made with your credentials via FAS, your AWS KMS key policy must grant `kms:CreateGrant` permission to your AWS account principal (not to a service principal). The grants themselves then allow Policy in AgentCore to perform cryptographic operations on your behalf without requiring further caller involvement.

1. All policy data (policies, policy generations, and related resources under the policy engine) is encrypted using your customer managed key.

The two grants serve different purposes:

Policy management grant  
Used for managing policy data. This grant allows encrypt, decrypt, and generate data key operations for creating, reading, updating, and deleting policies and related resources.

Policy evaluation grant  
Used for runtime policy evaluation. This grant allows decrypt and re-encrypt operations so that the policy engine can evaluate Cedar policies against incoming authorization requests.

Both grants are constrained by encryption context using the key `aws:bedrock-agentcore-policy:policy-engine-arn` , which binds the grants to the specific policy engine resource.

When you delete a policy engine with a customer managed key, Policy in AgentCore automatically retires both grants.

**Important**  
If you need to revoke grants manually, always revoke both the policy management grant and the policy evaluation grant. Revoking only one grant does not fully remove the service’s access to your key and may result in inconsistent behavior. You can view and manage grants for your key using the AWS KMS console or the `list-grants` AWS CLI command.

## Authorizing use of your AWS KMS key for Policy in AgentCore
<a name="policy-encryption-authorize-key"></a>

To use a customer managed key with Policy in AgentCore, your AWS KMS key policy must grant permissions to your AWS account. When creating a policy engine, Policy in AgentCore calls `kms:CreateGrant` using your identity through a [Forward Access Session (FAS)](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_forward_access_sessions.html) . As a result, the key policy must grant `kms:CreateGrant` and other required permissions to your account principal (not to a service principal) and uses the `kms:ViaService` condition to ensure the key is only used through Policy in AgentCore.

At a minimum, Policy in AgentCore requires the following permissions on a customer managed key:
+  `kms:CreateGrant` — Create grants for encrypt, decrypt, generate data key, re-encrypt, and describe key operations
+  `kms:Decrypt` — Decrypt data encrypted with the key
+  `kms:GenerateDataKey` — Generate data keys for encrypting policy data
+  `kms:DescribeKey` — Retrieve key metadata to validate key configuration

### Understanding source context
<a name="policy-encryption-source-context"></a>

Source context provides information on the source caller attempting to make AWS KMS actions against a given key. This prevents confusion or misuse of encrypted data by binding context to the source of the data.

When Policy in AgentCore performs AWS KMS operations through grants on your behalf, the source context identifies the Policy in AgentCore resource that initiated the request. You can use source context as additional conditions on the grant-based operations in your key policy to restrict key usage to requests originating from specific accounts or resources.

**Note**  
Source context conditions ( `aws:SourceAccount` and `aws:SourceArn` ) are available on grant-based AWS KMS operations but not on the `kms:CreateGrant` call, which uses a [Forward Access Session](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_forward_access_sessions.html).

For example, you can add `aws:SourceAccount` and `aws:SourceArn` conditions to the KMS operations and validation statements in your key policy to ensure that these operations only succeed when the request originates from your account and for your policy engine resources:

```
{
  "Sid": "Allow Policy for KMS operations with source context",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::111122223333:root"
  },
  "Action": [
    "kms:Decrypt",
    "kms:GenerateDataKey"
  ],
  "Resource": "*",
  "Condition": {
    "StringEquals": {
      "kms:ViaService": "bedrock-agentcore.us-east-1.amazonaws.com",
      "aws:SourceAccount": "111122223333"
    },
    "StringLike": {
      "aws:SourceArn": "arn:aws:bedrock-agentcore:us-east-1:111122223333:policy-engine/*",
      "kms:EncryptionContext:aws:bedrock-agentcore-policy:policy-engine-arn": "arn:aws*:bedrock-agentcore:*:*:policy-engine/*"
    }
  }
}
```

This key policy allows Policy in AgentCore to make AWS KMS calls on your behalf through grants, if the source account is the same as the account that this KMS key lives in. These values should be verifiable when checking CloudTrail audit logs for the KMS key. For more information on global AWS condition keys, see [Using aws:SourceArn or aws:SourceAccount condition keys](https://docs.aws.amazon.com/kms/latest/developerguide/least-privilege.html#key-policy-least-privilege) in the AWS KMS Developer Guide.

### Understanding kms:ViaService
<a name="policy-encryption-via-service"></a>

The `kms:ViaService` condition key limits use of a KMS key to requests from specified AWS services. This condition key applies for [Forward Access Sessions (FAS)](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_forward_access_sessions.html) . For more information on `kms:ViaService` , see [kms:ViaService](https://docs.aws.amazon.com/kms/latest/developerguide/policy-conditions.html#conditions-kms-via-service) in the AWS KMS Developer Guide.

In the key policy, the `kms:ViaService` value follows the format `bedrock-agentcore.REGION.amazonaws.com` , where *REGION* is the AWS Region where your policy engine is created (for example, `bedrock-agentcore.us-east-1.amazonaws.com` ).

### Understanding encryption context
<a name="policy-encryption-context"></a>

Encryption context is a set of key-value pairs that contain additional authenticated data for encryption integrity checks. When you include an encryption context in a request to encrypt data, AWS KMS cryptographically binds the encryption context to the encrypted data. To decrypt the data, you must pass the same encryption context. For more information, see [Encryption context](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#encrypt_context) in the AWS KMS Developer Guide.

Policy in AgentCore uses the following encryption context in all AWS KMS cryptographic operations and can be verified within CloudTrail logs when Policy in AgentCore makes AWS KMS calls on your behalf for encryption and decryption processes:

```
{
  "aws:bedrock-agentcore-policy:policy-engine-arn": "arn:aws:bedrock-agentcore:REGION:ACCOUNT_ID:policy-engine/POLICY_ENGINE_ID"
}
```

You can use this encryption context in your key policy conditions to restrict which policy engines can use the key. For example, the key policy in the following section uses a `kms:EncryptionContext` condition to allow the key to be used only for policy engine resources.

### Complete AWS KMS key policy
<a name="policy-encryption-key-policy"></a>

Based on the concepts in the previous sections, the following example key policy provides the necessary permissions to encrypt a policy engine and use an encrypted policy engine. The policy contains condition keys to conform to security best practices.

**Important**  
Replace the following values in the key policy: \$1 *111122223333* — Replace with your AWS account ID \$1 *us-east-1* — Replace with your AWS Region

```
{
"Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "Allow Policy to create grants",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/ExampleRole"
      },
      "Action": "kms:CreateGrant",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "bedrock-agentcore.us-east-1.amazonaws.com",
          "kms:GrantConstraintType": "EncryptionContextSubset"
        },
        "StringLike": {
          "kms:EncryptionContext:aws:bedrock-agentcore-policy:policy-engine-arn": "arn:aws*:bedrock-agentcore:*:*:policy-engine/*"
        },
        "ForAllValues:StringEquals": {
          "kms:GrantOperations": [
            "Encrypt",
            "Decrypt",
            "GenerateDataKey",
            "GenerateDataKeyWithoutPlaintext",
            "ReEncryptFrom",
            "ReEncryptTo"
          ]
        }
      }
    },
    {
      "Sid": "Allow Policy for KMS operations",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/ExampleRole"
      },
      "Action": [
        "kms:Decrypt",
        "kms:GenerateDataKey"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "bedrock-agentcore.us-east-1.amazonaws.com"
        },
        "StringLike": {
          "kms:EncryptionContext:aws:bedrock-agentcore-policy:policy-engine-arn": "arn:aws*:bedrock-agentcore:*:*:policy-engine/*"
        }
      }
    },
    {
      "Sid": "Allow Policy for KMS validation",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/ExampleRole"
      },
      "Action": "kms:DescribeKey",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "bedrock-agentcore.us-east-1.amazonaws.com"
        }
      }
    }
  ]
}
```

The policy contains the following statements:

Allow Policy to create grants  
Allows the caller to create AWS KMS grants when creating a policy engine. The `kms:GrantConstraintType` condition ensures that grants are constrained by encryption context. The `ForAllValues:StringEquals` condition on `kms:GrantOperations` restricts the grant to only the cryptographic operations that Policy in AgentCore requires.

Allow Policy for KMS operations  
Allows the caller to perform decrypt and generate data key operations through Policy in AgentCore. The encryption context condition ensures these operations are scoped to policy engine resources.

Allow Policy for KMS validation  
Allows the caller to describe the key through Policy in AgentCore. This permission is used during policy engine creation to validate that the key meets the requirements (symmetric, enabled, correct key usage).

**Important**  
Exercise caution when modifying AWS KMS key policies for keys already in use by Policy in AgentCore. If you inadvertently remove necessary permissions from the key policy, Policy in AgentCore will no longer be able to decrypt policy data, and all authorization decisions will be denied. Any operations that require access to the encrypted data (such as creating, reading, updating, or deleting policies) will also fail.

## Prerequisites for encrypting your policy engine
<a name="policy-encryption-prereqs"></a>

Before encrypting your policy engine, ensure that you have fulfilled the following prerequisites:
+ You have access to a KMS key. For information about creating a KMS key, see [Create a KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html) in the AWS KMS Developer Guide.
+ The KMS key must be a **symmetric encryption key** with `ENCRYPT_DECRYPT` key usage.
+ The KMS key must be in the **Enabled** state.
+ The KMS key has a key policy attached that grants the required permissions. See [Complete AWS KMS key policy](#policy-encryption-key-policy) for the required key policy.

For more information about controlling IAM permissions for a KMS key, see [KMS key access and permissions](https://docs.aws.amazon.com/kms/latest/developerguide/control-access.html) in the AWS KMS Developer Guide.

## Creating an encrypted policy engine
<a name="policy-encryption-create"></a>

Before creating an encrypted policy engine, ensure that the customer managed key you are using has the proper key policy statements set for Policy in AgentCore to use the key for encryption and decryption. See [Authorizing use of your AWS KMS key for Policy in AgentCore](#policy-encryption-authorize-key) for the required permissions.

To encrypt your policy engine using the AWS CLI, include the `--encryption-key-arn` parameter when sending a `create-policy-engine` request:

```
aws bedrock-agentcore-control create-policy-engine \
  --name "MyPolicyEngine" \
  --description "Policy engine with customer-managed encryption" \
  --encryption-key-arn "arn:aws:kms:us-east-1:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab"
```

The response includes the policy engine ARN and status:

```
{
  "policyEngineId": "MyPolicyEngine-abc123",
  "name": "MyPolicyEngine",
  "description": "Policy engine with customer-managed encryption",
  "policyEngineArn": "arn:aws:bedrock-agentcore:us-east-1:123456789012:policy-engine/MyPolicyEngine-abc123",
  "status": "CREATING",
  "statusReasons": [],
  "encryptionKeyArn": "arn:aws:kms:us-east-1:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
  "createdAt": "2026-02-24T12:00:00Z",
  "updatedAt": "2026-02-24T12:00:00Z"
}
```

**Note**  
If the KMS key in use by your policy engine is deleted, disabled, or inaccessible due to an incorrect AWS KMS key policy, decryption of resources will fail. This can result in denied authorization decisions. The loss of access can be temporary (a key policy can be corrected) or permanent (a deleted key cannot be restored) depending on the circumstances. We recommend that you [restrict access](https://docs.aws.amazon.com/kms/latest/developerguide/deleting-keys-adding-permission.html) to critical operations such as deleting or disabling the KMS key. Also, we recommend that your organization set up [AWS break-glass access procedures](https://docs.aws.amazon.com/wellarchitected/latest/devops-guidance/ag.sad.5-implement-break-glass-procedures.html) to ensure your privileged users can access AWS in the unlikely event that Policy in AgentCore is inaccessible.

## Limitations
<a name="policy-encryption-limitations"></a>

The following limitations apply to customer managed key encryption for policy engines:
+ You cannot disable encryption for a policy engine once enabled.
+ After you create a policy engine without encryption, you cannot update the policy engine to be encrypted by a customer managed key.
+ After you create a policy engine with a customer managed key, you cannot change the key or remove it from that policy engine. You must create a new policy engine to use a different key.
+ Customer managed key encryption is configured at the policy engine level. All resources under the policy engine, including policies and policy generations, are encrypted using the same customer managed key as the policy engine. You cannot specify different keys for individual resources within a policy engine.
+ After you revoke Policy in AgentCore’s access to a customer managed key for an existing encrypted policy engine, all authorization decisions will be denied because the policy engine can no longer decrypt policy data.

## Troubleshooting
<a name="policy-encryption-troubleshooting"></a>

This section describes common customer managed key related errors you might encounter when using Policy in AgentCore and provides troubleshooting steps to resolve them.

### Access denied: AWS KMS permission issue
<a name="policy-encryption-error-access-denied"></a>

 **Error:** "Access denied for the specified KMS key. Verify the key policy grants the required permissions."

This could mean that the caller lacks the required kms:\$1 action permissions in their IAM policy or AWS KMS key policy, or that the key being referenced does not exist or no longer exists.

 **To resolve this issue:** 

1. Verify that the KMS key ARN is correct and the key exists in the specified Region.

1. Verify that the AWS KMS key policy includes the required statements. See [Complete AWS KMS key policy](#policy-encryption-key-policy).

1. Verify that the caller’s IAM policy includes the required AWS KMS permissions ( `kms:CreateGrant` , `kms:Decrypt` , `kms:GenerateDataKey` , `kms:DescribeKey` ).

1. Check CloudTrail for `kms.amazonaws.com` events to identify which operation was denied and which principal attempted it.

### Validation exception: AWS KMS key configuration
<a name="policy-encryption-error-validation"></a>

 **Error:** "The specified KMS key is not in a usable state. Verify the key is enabled and not pending deletion."

This means that the key being referenced cannot be used for customer managed key encryption due to its current configuration. Possible reasons include:
+ The key is disabled or pending deletion.
+ The key is not a symmetric encryption key.
+ The key does not have `ENCRYPT_DECRYPT` key usage.

 **To resolve this issue:** Verify that the key meets the prerequisites described in [Prerequisites for encrypting your policy engine](#policy-encryption-prereqs).