QuickStart: Policy Engine in 5 Minutes! 🚀¶
Amazon Bedrock AgentCore Policy enables you to define and enforce fine-grained authorization policies for your AI agents using the Cedar policy language. This guide walks you through creating a Gateway with Policy Engine enforcement to govern agent tool calls.
📚 For more information and detail beyond this quickstart, see the AgentCore Policy Documentation
Overview¶
AgentCore Policy provides:
- Policy Engines: Containers for organizing and managing related policies
- Cedar Policies: Fine-grained authorization rules using Amazon's Cedar policy language
- Gateway Integration: Seamless integration with AgentCore Gateway for runtime policy enforcement
- Deterministic Authorization: Policy evaluation happens outside agent code for consistent security
Prerequisites¶
Before starting, make sure you have the following:
- AWS Account with credentials configured
- Python 3.10+ installed
- IAM permissions for creating roles, Lambda functions, Policy Engines, and using Amazon Bedrock AgentCore
Step 1: Setup and Install¶
Run the following in a terminal to set up the virtual environment:
mkdir agentcore-policy-quickstart
cd agentcore-policy-quickstart
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
Then install the dependencies:
pip install boto3
pip install bedrock-agentcore-starter-toolkit
pip install requests
Step 2: Create Policy Setup Script¶
Create a new file called setup_policy.py and insert the following complete code:
"""
Setup script to create Gateway with Policy Engine
Run this first: python setup_policy.py
"""
from bedrock_agentcore_starter_toolkit.operations.gateway.client import GatewayClient
from bedrock_agentcore_starter_toolkit.operations.policy.client import PolicyClient
from bedrock_agentcore_starter_toolkit.utils.lambda_utils import create_lambda_function
import boto3
import json
import logging
import time
def setup_policy():
# Configuration
region = "us-west-2"
refund_limit = 1000
print("🚀 Setting up AgentCore Gateway with Policy Engine...")
print(f"Region: {region}\n")
# Initialize clients
gateway_client = GatewayClient(region_name=region)
gateway_client.logger.setLevel(logging.INFO)
policy_client = PolicyClient(region_name=region)
policy_client.logger.setLevel(logging.INFO)
# Step 1: Create OAuth authorizer
print("Step 1: Creating OAuth authorization server...")
cognito_response = gateway_client.create_oauth_authorizer_with_cognito("PolicyGateway")
print("✓ Authorization server created\n")
# Step 2: Create Gateway
print("Step 2: Creating Gateway...")
gateway = gateway_client.create_mcp_gateway(
name=None,
role_arn=None,
authorizer_config=cognito_response["authorizer_config"],
enable_semantic_search=False,
)
print(f"✓ Gateway created: {gateway['gatewayUrl']}\n")
# Fix IAM permissions
gateway_client.fix_iam_permissions(gateway)
print("⏳ Waiting 30s for IAM propagation...")
time.sleep(30)
print("✓ IAM permissions configured\n")
# Step 3: Create Lambda function with refund tool
print("Step 3: Creating Lambda function with refund tool...")
refund_lambda_code = """
def lambda_handler(event, context):
amount = event.get('amount', 0)
return {
"status": "success",
"message": f"Refund of ${amount} processed successfully",
"amount": amount
}
"""
session = boto3.Session(region_name=region)
lambda_arn = create_lambda_function(
session=session,
logger=gateway_client.logger,
function_name=f"RefundTool-{int(time.time())}",
lambda_code=refund_lambda_code,
runtime="python3.13",
handler="lambda_function.lambda_handler",
gateway_role_arn=gateway["roleArn"],
description="Refund tool for policy demo",
)
print("✓ Lambda function created\n")
# Step 4: Add Lambda target with refund tool schema
print("Step 4: Adding Lambda target with refund tool schema...")
lambda_target = gateway_client.create_mcp_gateway_target(
gateway=gateway,
name="RefundTarget",
target_type="lambda",
target_payload={
"lambdaArn": lambda_arn,
"toolSchema": {
"inlinePayload": [
{
"name": "process_refund",
"description": "Process a customer refund",
"inputSchema": {
"type": "object",
"properties": {
"amount": {
"type": "integer",
"description": "Refund amount in dollars"
}
},
"required": ["amount"],
},
}
]
},
},
credentials=None,
)
print("✓ Lambda target added\n")
# Step 5: Create Policy Engine
print("Step 5: Creating Policy Engine...")
engine = policy_client.create_or_get_policy_engine(
name="RefundPolicyEngine",
description="Policy engine to regulate refund operations"
)
print(f"✓ Policy Engine: {engine['policyEngineId']}\n")
# Step 6: Create Cedar policy
print(f"Step 6: Creating Cedar policy (refund limit: ${refund_limit})...")
cedar_statement = (
f"permit(principal, "
f'action == AgentCore::Action::"RefundTarget___process_refund", '
f'resource == AgentCore::Gateway::"{gateway["gatewayArn"]}") '
"when { context.input.amount < " + str(refund_limit) + " };"
)
policy = policy_client.create_or_get_policy(
policy_engine_id=engine["policyEngineId"],
name="refund_limit_policy",
description=f"Allow refunds under ${refund_limit}",
definition={"cedar": {"statement": cedar_statement}},
)
print(f"✓ Policy: {policy['policyId']}\n")
# Step 7: Attach Policy Engine to Gateway
print("Step 7: Attaching Policy Engine to Gateway (ENFORCE mode)...")
gateway_client.update_gateway_policy_engine(
gateway_identifier=gateway["gatewayId"],
policy_engine_arn=engine["policyEngineArn"],
mode="ENFORCE"
)
print("✓ Policy Engine attached to Gateway\n")
# Step 8: Save configuration
config = {
"gateway_url": gateway["gatewayUrl"],
"gateway_id": gateway["gatewayId"],
"gateway_arn": gateway["gatewayArn"],
"policy_engine_id": engine["policyEngineId"],
"policy_engine_arn": engine["policyEngineArn"],
"policy_id": policy["policyId"],
"region": region,
"client_info": cognito_response["client_info"],
"refund_limit": refund_limit
}
with open("config.json", "w") as f:
json.dump(config, f, indent=2)
print("=" * 60)
print("✅ Setup complete!")
print(f"Gateway URL: {gateway['gatewayUrl']}")
print(f"Policy Engine ID: {engine['policyEngineId']}")
print(f"Refund limit: ${refund_limit}")
print("\nConfiguration saved to: config.json")
print("\nNext step: Run 'python test_policy.py' to test your Policy")
print("=" * 60)
return config
if __name__ == "__main__":
setup_policy()
Understanding the Setup Script – Step-by-Step Explanation¶
📚 Click to expand detailed explanation
#### Import Required Librariesfrom bedrock_agentcore_starter_toolkit.operations.gateway.client import GatewayClient
from bedrock_agentcore_starter_toolkit.operations.policy.client import PolicyClient
import json
import logging
import time
gateway_client = GatewayClient(region_name=region)
policy_client = PolicyClient(region_name=region)
permit(principal,
action == AgentCore::Action::"RefundTarget___process_refund",
resource == AgentCore::Gateway::"<gateway-arn>")
when {
context.input.amount < 1000
};
Step 3: Run the Setup¶
Execute the setup script:
python setup_policy.py
What to expect: The script will take about 2-3 minutes to complete.
Step 4: Test the Policy¶
Create a file called test_policy.py:
"""
Test Policy Engine with direct HTTP calls to Gateway
Run after setup: python test_policy.py
"""
import json
import sys
import requests
from bedrock_agentcore_starter_toolkit.operations.gateway.client import GatewayClient
def test_refund(gateway_url, bearer_token, amount):
"""Test a refund request - print raw response"""
response = requests.post(
gateway_url,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {bearer_token}",
},
json={
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "RefundTarget___process_refund",
"arguments": {"amount": amount}
},
},
)
print(f"Status Code: {response.status_code}")
print(f"Response Body: {json.dumps(response.json(), indent=2)}")
return response
def main():
print("=" * 60)
print("🧪 Testing Policy Engine")
print("=" * 60 + "\n")
# Load configuration
try:
with open("config.json", "r") as f:
config = json.load(f)
except FileNotFoundError:
print("❌ Error: config.json not found!")
print("Please run 'python setup_policy.py' first.")
sys.exit(1)
gateway_url = config["gateway_url"]
refund_limit = config["refund_limit"]
print(f"Gateway: {gateway_url}")
print(f"Refund limit: ${refund_limit}\n")
# Get access token
print("🔑 Getting access token...")
gateway_client = GatewayClient(region_name=config["region"])
token = gateway_client.get_access_token_for_cognito(config["client_info"])
print("✅ Token obtained\n")
# Test 1: Refund $500 (should be allowed)
print(f"📝 Test 1: Refund $500 (Expected: ALLOW)")
print("-" * 40)
test_refund(gateway_url, token, 500)
print()
# Test 2: Refund $2000 (should be denied)
print(f"📝 Test 2: Refund $2000 (Expected: DENY)")
print("-" * 40)
test_refund(gateway_url, token, 2000)
print()
print("=" * 60)
print("✅ Testing complete!")
print("=" * 60)
if __name__ == "__main__":
main()
Run the test:
python test_policy.py
What You've Built¶
Through this tutorial, you've created:
- MCP Server (Gateway): A managed endpoint for tools
- Lambda function: Mock refund processing tool
- Policy Engine: Cedar-based policy evaluation system
- Cedar Policy: Governance rule allowing refunds under $1000
- OAuth authentication: Secure access using Cognito tokens
Troubleshooting¶
| Issue | Solution |
|---|---|
| "AccessDeniedException" | Check IAM permissions for bedrock-agentcore:* |
| Gateway not responding | Wait 30-60 seconds after creation for DNS propagation |
| OAuth token expired | Tokens expire after 1 hour, script gets new one automatically |
Cleanup¶
Create a file called cleanup_policy.py:
"""
Cleanup script to remove Gateway and Policy Engine resources
Run this to clean up: python cleanup_policy.py
"""
from bedrock_agentcore_starter_toolkit.operations.gateway.client import GatewayClient
from bedrock_agentcore_starter_toolkit.operations.policy.client import PolicyClient
import json
def cleanup():
with open("config.json", "r") as f:
config = json.load(f)
# Clean up Policy Engine first
print("🧹 Cleaning up Policy Engine...")
policy_client = PolicyClient(region_name=config["region"])
policy_client.cleanup_policy_engine(config["policy_engine_id"])
print("✓ Policy Engine cleaned up\n")
# Then clean up Gateway
print("🧹 Cleaning up Gateway...")
gateway_client = GatewayClient(region_name=config["region"])
gateway_client.cleanup_gateway(config["gateway_id"], config["client_info"])
print("✅ Cleanup complete!")
if __name__ == "__main__":
cleanup()
Run the cleanup:
python cleanup_policy.py
Next Steps¶
- Custom Lambda Tools: Create Lambda functions with your business logic
- Add Your Own APIs: Extend your Gateway with OpenAPI specifications for real services
- Production Setup: Configure VPC endpoints, custom domains, and monitoring
- Advanced Policies: Create more complex Cedar policies with multiple conditions
- Policy Generation: Use natural language to generate Cedar policies (see CLI reference)
CLI Reference¶
For advanced operations using the AgentCore CLI, including policy generation from natural language and detailed policy management, see the Policy CLI Reference.