policy
Control what your AgentCore agent can do — restrict tool calls, enforce business rules, and protect sensitive operations.
When to use
- You want to restrict which tools your agent can call
- You want to enforce business rules (e.g., refunds only under $500)
- You want role-based access control on agent actions
- You want an emergency kill switch for specific tools
- A policy is denying requests you expect to allow (or allowing what you expect to deny)
Input
$ARGUMENTS is optional:
/policy # interactive — asks what you want to restrict
/policy generate # generate Cedar from natural language
/policy debug # diagnose why a policy is allowing/denying
/policy emergency # generate an emergency shutdown policyHow AgentCore policy works
AgentCore Policy enforces Cedar-based authorization rules at the gateway boundary — before any tool call reaches its target. Every tool call is evaluated against your policies in real time.
Default behavior: Without a policy engine attached to your gateway, all tool calls are allowed. Once you attach a policy engine, the default is deny — you must write explicit permit policies for everything you want to allow.
Key concepts:
- Policy engine — the container for your policies, attached to a gateway
- Policy — a Cedar rule that permits or forbids specific actions
forbidoverridespermit— if any forbid policy matches, the action is denied regardless of permit policies
Process
Step 1: Read the project
Read agentcore/agentcore.json to understand:
- What gateways exist (in the
agentCoreGatewaysarray) - Whether a policy engine is already configured (in the
policyEnginesarray)
Step 2: Understand the goal
Ask (or infer from $ARGUMENTS):
"What do you want to control?
- Restrict a tool based on input values (e.g., amount < $500)
- Role-based access (only certain users can call certain tools)
- Block a specific tool entirely
- Emergency shutdown — disable all tools immediately
- Debug why a policy is allowing or denying unexpectedly"
Path A: Set up a policy engine
Step A1: Create the policy engine
# Create and attach to an existing gateway
agentcore add policy-engine \
--name MyPolicyEngine \
--attach-to-gateways MyGateway \
--attach-mode LOG_ONLYStart with LOG_ONLY mode — policies are evaluated and logged but not enforced. This lets you verify your policies work correctly before enabling enforcement.
Switch to ENFORCE when ready:
# Update an existing gateway
agentcore add gateway \
--name MyGateway \
--policy-engine MyPolicyEngine \
--policy-engine-mode ENFORCE(The same --policy-engine and --policy-engine-mode flags work at gateway creation time too.)
Step A2: Deploy to activate
agentcore deploy -yPath B: Write Cedar policies
[!WARNING] Cedar policies that reference a specific gateway ARN in the
resourcefield require the gateway to be deployed first. You cannot add a policy with a gateway ARN before the gateway exists in AWS.Two-phase deployment:
- Deploy the gateway first:
agentcore deploy -y- Get the gateway ARN:
agentcore status --type gateway --json- Add the policy with the real ARN, then deploy again
The
-g/--generateflag also requires a deployed gateway — it calls an AWS API that needs the gateway ARN to convert natural language into Cedar. If you run-gbefore deploying the gateway, it will fail.
Option 1: Natural language generation (easiest)
Requires the gateway to be deployed first — the CLI calls an API that needs the gateway ARN.
# Deploy the gateway first
agentcore deploy -y
# Then generate the policy (--gateway tells the CLI which deployed gateway to use)
agentcore add policy \
--name refund_policy \
--engine MyPolicyEngine \
-g "Allow users with the refund-agent role to process refunds when the amount is less than 500" \
--gateway MyGatewayThe CLI generates Cedar from your description, resolves the gateway ARN automatically, and validates the result. Review the generated policy before deploying.
Policy name rules: letters, numbers, underscores only — no hyphens. refund-policy fails; refund_policy works.
Option 2: Write Cedar directly
Save to a .cedar file and register. If the policy references a gateway ARN in the resource field, you need the ARN from a prior deploy:
# Get the gateway ARN after deploying
agentcore status --type gateway --json | jq -r '.gateways[0].arn'
# Update your .cedar file with the real ARN, then add the policy
agentcore add policy \
--name refund_policy \
--engine MyPolicyEngine \
--source policy.cedarCedar syntax reference
Action name format: AgentCore::Action::"TargetName___tool_name" — three underscores between target name and tool name. This is the most common Cedar mistake.
// TargetName is the gateway target name (from agentcore add gateway-target --name)
// tool_name is the tool name within that target
AgentCore::Action::"RefundTarget___process_refund"
// ^^^
// three underscoresPrincipal types:
AgentCore::OAuthUser— authenticated user via OAuth/JWTAgentCore::IamEntity— IAM-authenticated caller (when gateway uses AWS_IAM auth). Theidattribute contains the full IAM ARN.
Resource format:
AgentCore::Gateway::"arn:aws:bedrock-agentcore:<REGION>:<YOUR_ACCOUNT_ID>:gateway/<GATEWAY_ID>"Get your gateway ARN: agentcore status --type gateway --json | jq -r '.gateways[0].arn'
Common policy patterns
Amount-based restriction:
permit(
principal is AgentCore::OAuthUser,
action == AgentCore::Action::"RefundTarget___process_refund",
resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/my-gateway-id"
)
when {
principal.hasTag("role") &&
principal.getTag("role") == "refund-agent" &&
context.input.amount < 500
};Role-based access (OAuth user):
permit(
principal is AgentCore::OAuthUser,
action == AgentCore::Action::"AdminTarget___delete_record",
resource == AgentCore::Gateway::"arn:..."
)
when {
principal.hasTag("role") &&
["admin", "superuser"].contains(principal.getTag("role"))
};Account-based access (IAM entity):
permit(
principal is AgentCore::IamEntity,
action == AgentCore::Action::"AdminTarget___delete_record",
resource == AgentCore::Gateway::"arn:..."
)
when {
principal.id like "arn:aws:iam::123456789012:*"
};Block a specific tool entirely:
forbid(
principal,
action == AgentCore::Action::"PaymentTarget___transfer_funds",
resource == AgentCore::Gateway::"arn:..."
);Emergency shutdown — disable all tools:
forbid(principal, action, resource);Required field validation:
forbid(
principal is AgentCore::OAuthUser,
action == AgentCore::Action::"InsuranceTarget___file_claim",
resource == AgentCore::Gateway::"arn:..."
)
unless {
context.input has description &&
context.input has priority
};Critical Cedar rules
Always use hasTag() before getTag():
// ❌ Wrong — throws error if tag doesn't exist
when { principal.getTag("role") == "admin" }
// ✅ Correct — check existence first
when {
principal.hasTag("role") &&
principal.getTag("role") == "admin"
}Default deny: Once a policy engine is attached in ENFORCE mode, everything is denied unless a permit policy matches. Write explicit permits for every action you want to allow.
forbid always wins: A forbid policy overrides any permit policy. Use this for emergency shutdowns and hard blocks.
Path C: Test policies before enforcing
LOG_ONLY mode
In LOG_ONLY mode, all requests are allowed but policy decisions are logged to CloudWatch. Use this to verify your policies before switching to ENFORCE.
# Check policy decision logs
agentcore logs --runtime MyAgent --since 1h --query "policy"Look for log entries showing ALLOW or DENY decisions for each tool call.
Validate policy syntax
agentcore add policy \
--name test_policy \
--engine MyPolicyEngine \
--source policy.cedar \
--validation-mode FAIL_ON_ANY_FINDINGSIf the Cedar syntax is invalid, the CLI returns a validation error before creating the policy.
Switch to ENFORCE
Once LOG_ONLY results look correct:
# Update gateway to enforce mode
agentcore add gateway \
--name MyGateway \
--policy-engine MyPolicyEngine \
--policy-engine-mode ENFORCE
agentcore deploy -yPath D: Debug policy failures
"Access denied" on a tool call you expect to allow:
- Check that a
permitpolicy exists for this action — remember, default is deny - Verify the action name format:
TargetName___tool_name(three underscores) - Verify the resource ARN matches your gateway's actual ARN
- Check that
hasTag()is used beforegetTag()in conditions - Check LOG_ONLY logs to see what the policy engine is evaluating
# Check recent policy decisions
agentcore logs --runtime MyAgent --since 1h --query "policy"
agentcore status --type policy-engine"Everything is being denied" after attaching a policy engine:
You attached a policy engine but haven't written any permit policies yet. The default is deny. Write at least one permit policy for the actions you want to allow.
Policy name validation error:
Policy names must match ^[A-Za-z][A-Za-z0-9_]*$ — letters, numbers, underscores only, starts with a letter. No hyphens.
Output
- CLI commands to create the policy engine and policies
- Cedar policy file for the requested use case
- LOG_ONLY testing workflow before enforcement
- Debugging guidance for policy failures