← Course Home
Module 4

Policy Enforcement with Cedar & Gateway Security

Why Amazon Bedrock AgentCore chose Cedar, how Cedar policies are structured, and how the Gateway becomes the single choke point for every agent-to-tool request.

⏱ ~30 min · Policy (Cedar) + Gateway
SURFACE · POLICY (CEDAR)

Why Cedar for Agentic Workflows

Cedar is the open-source authorization language behind Amazon Verified Permissions. AWS chose it for agent authorization because security decisions about non-deterministic agents must themselves be deterministic and auditable.

Deterministic

The same request + policies always yields the same decision. No model in the loop, no ambiguity.

Auditable

Policies are declarative text you can review, diff, and put under change control.

Formally verifiable

Cedar is designed for analysis — you can reason about what a policy set does before it ships.

Two rules that define Cedar's posture Forbid always wins — a single forbid overrides every permit. And the baseline is default deny: an agent has no permissions until a policy explicitly grants them.

Why it fits agents: you can't predict what an agent will try, but you can guarantee what it will be allowed to do. Cedar turns an unpredictable actor into a bounded one.

Cedar Policy Structure for Amazon Bedrock AgentCore

Every Cedar policy answers three questions: who (Principal), what (Action), and on what (Resource) — optionally gated by conditions.

Principal
Who

Which agent or identity.

+
Action
What

Which operation.

+
Resource
On what

Which tool or data.

Permit — scoped, conditional access

// Permit agent X to invoke tool Y, business hours only permit( principal == Agent::"portfolio-agent", action == Action::"invoke", resource == Tool::"market-data" ) when { context.hour >= 9 && context.hour < 18 };

Forbid — an override that always wins

// No agent may ever read PII-tagged memory namespaces forbid( principal, action == Action::"read", resource ) when { resource.tag == "PII" };
Authoring aid — natural language to Cedar You can describe intent in plain language and have it translated into Cedar through a neuro-symbolic loop: an LLM drafts the policy, then Cedar Analysis validates it with symbolic reasoning. A schema generated from your MCP tool descriptions means policies are checked against real tool and parameter names, and the analyzer catches grant-all, deny-all, and impossible conditions before the policy ships.
The real entity types The examples above are simplified for readability. In Amazon Bedrock AgentCore, Cedar entities are namespaced — principals like AgentCore::OAuthUser, actions as AgentCore::Action::"<target>___<tool>", and the resource is the gateway itself: AgentCore::Gateway::"<gateway-arn>". Note the triple underscore joining target name to tool name — a detail that bites people on their first policy.

The same permit, written the way Amazon Bedrock AgentCore actually expects it

permit( principal is AgentCore::OAuthUser, action == AgentCore::Action::"market-data-target___get_quote", resource == AgentCore::Gateway::"<gateway-arn>" ) when { principal.hasTag("department") && principal.getTag("department") == "Engineering" };

Why conditions are the powerful part: a single policy can constrain two very different data sources. Principal tags come from the JWT — the LLM cannot hallucinate or alter them. Tool arguments in context.input come from the LLM's own tool call — so Cedar is where you bound them to sane values. Unexpected arguments get rejected deterministically.

INTERACTIVE DEMO

Cedar Policy Playground

Build a request the way an agent would, then evaluate it against a fixed policy set. Watch Cedar decide — and see why. This runs entirely in your browser; no AWS needed.

1 · Build the request
2 · Cedar decision
Build a request and press Evaluate.
Active policy set — the matched policy highlights on evaluate
permit portfolio-agent may invoke Tool:market-data when business hours
permit any agent may read / write its own Memory:session
permit trading-agent may executeTrade on Tool:trade-api when approval attached
forbid any access to Memory:pii-namespace (forbid always wins)
default everything not explicitly permitted is denied

Try these on camera: (1) portfolio-agent · invoke · market-data with hours on → ALLOW; turn hours off → DENY (condition fails → default deny). (2) any request touching pii-namespace → DENY even if a permit exists (forbid wins). (3) trading-agent · executeTrade · trade-api → DENY until you attach approval.

SURFACE · GATEWAY

Amazon Bedrock AgentCore Gateway as the Security Choke Point

The Gateway is where policy meets traffic. Every agent-to-tool request flows through it, Cedar evaluates the request, and the Gateway allows or denies. One place to enforce, one place to audit.

01
Agent request

Agent asks to call a tool.

02
Gateway

Intercepts every request.

03
Policy eval

Cedar decides allow / deny.

04
Tool or deny

Call proceeds, or is blocked + logged.

MCP protocol security

The Gateway mediates Model Context Protocol connections, so tool servers are reached through a governed broker.

Lambda interceptors

Custom code runs before/after policy evaluation — token enrichment, request logging, rate limiting, content scanning.

Guardrails integration

Prompt-attack detection, content filtering, and PII detection applied at the Gateway level.

Controlling the response, not just the request A RESPONSE interceptor (Lambda) runs before the response returns to the agent — it can filter the tool list and redact or sanitize output (e.g., PII) per user. And on tools/list, Cedar's partial evaluation hides any tool that would always be denied, so the agent never sees it.
A choke point only works if it can't be bypassed Every control on this page — policy, guardrails, interceptors — applies only to traffic that actually goes through the Gateway. If a caller can reach the runtime directly, it skips all of them. Close that door explicitly: for IAM (SigV4) runtimes attach a resource-based policy restricting invocation to the gateway's execution role; for OAuth (JWT) runtimes configure allowedWorkloadConfiguration on the authorizer.
Roll it out in LOG_ONLY first A policy engine attached to a gateway defaults to LOG_ONLY: it evaluates every request and writes the decision, but blocks nothing. Validate your rules against real traffic there, then switch to ENFORCE. Going straight to enforce is how you discover a missing baseline permit during business hours — remember the engine is deny-by-default, so without an explicit permit, everything stops.
Order matters: interceptor, then Cedar The REQUEST interceptor runs before policy evaluation. That ordering is the useful part — the interceptor can enrich the request (look up a tenant role, inject an attribute like geography), and Cedar then evaluates rules over that enriched context. Interceptors for anything dynamic or requiring external lookups; Cedar for anything expressible as a logical rule. Cedar can't call DynamoDB or STS; interceptors can't give you an instantly-updatable, auditable deny.

The payoff: because all tool traffic funnels through the Gateway, "tool misuse" from M1 has exactly one place to be stopped — and every attempt, allowed or denied, lands in your audit trail (M6). A forbid rule added via the control-plane API takes effect immediately, which makes it a genuine emergency kill switch — no redeploy.

Sources