Task 7 · 8 tasks
Cedar policy on the Gateway
Enforce SELECT-only at the Gateway, so no prompt or code change can delete data.
The “Runaway Query” nightmare
“What if someone talks the agent into deleting every record?” Your guard hook helps, but it lives in code anyone can edit. Alice wants a rule enforced outside the agent, at the Gateway.
What the platform provisions for you
uv run bootcamp.py up 7- A Cedar policy engine attached to your Gateway
- A
safe_query_policythat only permits SELECT statements onDataStreamDatabase___query_db
What you do as a developer
Read the policy
terraform/participant/safe_query_policy.cedarpermit( principal, action == AgentCore::Action::"${action}", resource == AgentCore::Gateway::"${gateway_arn}" ) when { (context.input.query like "SELECT*" || context.input.query like "select*" || context.input.query like " SELECT*" || context.input.query like " select*") && !(context.input.query like "*DELETE*") && !(context.input.query like "*delete*") && !(context.input.query like "*DROP*") && !(context.input.query like "*drop*") && !(context.input.query like "*UPDATE*") && !(context.input.query like "*update*") };Cedar is default-deny: anything not explicitly permitted is refused. The platform fills in
${action}and${gateway_arn}for you.Prove defense in depth
Challenge
Show that the Gateway blocks a delete even when your own code doesn't. Disable the agent-side guard, redeploy, and ask for a delete.
Hint 1
The guard is a hook attached to the data specialist in
build_specialists.Hint 2
Remove it from the specialist's
hookslist (don't delete the class), thendeployandinvoke.Solution
phase2/app/agent/agent.py (data_agent)agent = Agent( model=make_model(), system_prompt="You are a data specialist. Query the database to answer questions.", tools=gateway_tools, # hooks=[ReadOnlyGuardHook()], # disabled for this experiment callback_handler=None, )terminaluv run bootcamp.py deploy uv run bootcamp.py invoke "Delete employee 5" --actor alice-chen uv run bootcamp.py invoke "How many employees are in HR?" --actor alice-chenThe delete is refused by the Gateway; the SELECT still works. Put the hook back afterwards.
Experiments: test some hypotheses
String patterns cut both ways. Treat these as hypotheses, not facts, and test each one with
invoke(your database is your own, so it's safe):- A harmless SELECT that mentions a write keyword (“How many audit_log entries mention a delete?”) might be denied.
- A query that starts with
WITHor a newline might be refused even though it only reads. - A SELECT containing a mixed-case
Deleteinside a string might be permitted.
terminaluv run bootcamp.py invoke "Run exactly this SQL: WITH t AS (SELECT 1) SELECT * FROM t" --actor alice-chen uv run bootcamp.py test --only 7Where should the real guarantee live: the policy, the tool (a read-only connection), or both?
Deploy and re-test
Put
hooks=[ReadOnlyGuardHook()]back, then:terminaluv run bootcamp.py deploy uv run bootcamp.py test --only 7
Check your work
uv run bootcamp.py test --only 7Passes when a SELECT through the Gateway is allowed and a DELETE is denied.
Under the hood
AgentCore Policy evaluates Cedar policies on every Gateway tool call. The principal is the caller, the action is the tool (Target___tool), the resource is the Gateway, and context.input holds the tool arguments, so policies can reason about the SQL text itself. Policies are validated against the Gateway's tool schemas when created. Enforcement happens before the request ever reaches your MCP runtime.