Policy Enforcement¶
The gateway evaluates every API request against Cedar policies before it reaches the route handler.
How It Works¶
- Action auto-discovery: Routes are introspected at startup to build a mapping of
(HTTP method, path pattern) → Cedar action. No static list to maintain. - Principal resolution: Extracted from request headers (
X-Agent-Id,X-Cred-*,X-AWS-Access-Key-Id). - Cedar evaluation: The
PolicyEnforcerevaluatespermit(principal, action, resource)?for each request. - Default-deny: When Cedar is active with no loaded policies, all non-exempt requests are denied.
Cedar Actions¶
Actions are derived automatically from route definitions:
/api/v1/memory/{namespace} POST → Action::"memory:store_memory"
/api/v1/memory/{namespace}/{key} GET → Action::"memory:retrieve_memory"
/api/v1/agents/{name}/chat POST → Action::"agents:chat_with_agent"
Example Policies¶
// Allow everyone to list and view agents
permit(principal, action == Action::"agents:list_agents", resource);
permit(principal, action == Action::"agents:get_agent", resource);
// Allow a specific agent to use memory
permit(
principal == Agent::"research-assistant",
action == Action::"memory:store_memory",
resource
);
// Deny code execution for all agents
forbid(principal, action == Action::"code_interpreter:execute_code", resource);
Configuration¶
enforcement:
backend: "agentic_primitives_gateway.enforcement.cedar.CedarPolicyEnforcer"
config:
policy_refresh_interval: 30 # Seconds between policy reloads
seed_policies:
- description: "Allow all"
policy_body: 'permit(principal, action, resource);'
Seed Policies¶
Policies in seed_policies are loaded into a "seed" policy engine at startup. This ensures enforcement works even with the noop (in-memory) policy provider.
Exempt Paths¶
These paths are never enforced:
/healthz,/readyz/metrics/docs,/redoc,/openapi.json/ui/*/api/v1/providers/api/v1/policy/*(policy management itself)
Principals¶
The middleware resolves the principal from the AuthenticatedPrincipal contextvar first (set by the auth middleware when JWT auth is configured). If no authenticated principal is present, it falls back to header-based derivation.
Resolution order:
- Authenticated principal (always set for non-exempt paths):
AuthenticatedPrincipalcontextvar →User::"alice"(from JWTsubclaim or API key mapping) - Header fallback (exempt paths only):
X-Agent-Id: my-agent→Agent::"my-agent" - Header fallback:
X-Cred-{service}-*→Service::"{service}" - Header fallback:
X-AWS-Access-Key-Id: AKIA...→AWSPrincipal::"AKIA..." - Last resort (exempt paths only):
Agent::"anonymous"
Non-exempt paths always have an authenticated principal (the auth middleware returns 401 if credentials are missing). The header-based fallback and Agent::"anonymous" are only reachable on exempt paths, which are skipped by enforcement anyway.