Task 2 — Enforce access contracts with model RBAC and quotas

Part of the Govern AI models and agents through an API gateway lab. New here? Start with Getting started.

Starting here on its own? You need the Citadel hub deployed (azd up), a sample spoke deployed, and the onboarded backends from Task 1 — an access contract can only allow models the gateway actually serves. From the Labfiles/G-govern-ai-through-a-gateway folder, run python setup/check_env.py --task 2 to confirm you’re ready.

Continuing from a previous task? If you just finished Task 1, you already onboarded the backends and confirmed the model catalogue is reachable. You can go straight into this task — the notebook here creates its own access contracts and doesn’t depend on any temporary contract you created in Task 1’s all-models test.


Routing every call through the gateway (Task 1) is only useful if the gateway can say no. An access contract is how Citadel grants a workload scoped, metered access: which models it may call, and how many tokens it may spend.

What is an access contract?

In Citadel, an access contract is an API Management product (with a policy) plus a subscription (which issues an API key). The product policy encodes the governance rules for that workload:

  • Model-level RBAC via an allowedModels list — the gateway rejects any request for a model that isn’t on the workload’s list.
  • Capacity via the llm-token-limit policy — a per-minute rate and a longer-period quota, measured in tokens rather than requests.
  • Optional integrations — resolve endpoint and key secrets from Key Vault, and/or auto-create a Microsoft Foundry connection so Foundry agents can use the contract.

A workload authenticates with just its subscription key; the contract does the rest.

Define and deploy the access contracts

  1. In VS Code, open the notebook 3. citadel-access-contracts-tests.ipynb from the workshop folder and select the workshop/.venv kernel.

  2. Run Steps 0–2 to initialize variables, verify your Azure CLI sign-in, and initialize the APIM client.

  3. Review Step 3 – Define Access Contract Configurations. The notebook defines three contracts, each representing a different workload with different governance needs:

    Access contract Integration Represents
    Sales-Assistant Key Vault only An agent running on Azure (AKS / ACA / App Service)
    HR-ChatAgent Key Vault + Foundry connection A Foundry-hosted agent
    Support-Bot Direct (no integration) A custom hosted agent

    Notice how each contract sets its own allowed_models list (model RBAC) and its own token capacity (tokens_per_minute, token_quota, token_quota_period).

  4. Run Step 4 to generate the per-contract parameter files, then Step 4.1 to deploy all three access contracts with Bicep. Run Step 4.2 to print the Foundry connection name(s) the deployment created — you’ll reuse these in Task 5.

  5. Run Step 5 to retrieve the subscription API key for each contract from its APIM subscription.

Validate enforcement and throttling

  1. Run Step 6 – Test API Requests Across All Access Contracts. Each contract sends a request with its own key. Confirm that requests for allowed models succeed and that a request for a model outside a contract’s allowedModels list is rejected — that’s model RBAC working.

  2. Run Step 7 – Run Load Test and Step 8 – Visualize Results. The load test bursts requests through each contract so you can see the token quota and per-minute limits kick in as throttled (429) responses.

  3. Run Step 9 – Compare Token Bucket Behavior to see how contracts with different capacity allocations throttle differently under the same load.

Why meter in tokens instead of requests?

A single chat request can consume a handful of tokens or tens of thousands, so a request count is a poor proxy for cost or load. LLM spend is billed per token, so Citadel’s contracts cap tokens per minute and a longer-period token quota. That maps governance limits directly to the thing you actually pay for — and the usage records you’ll explore in Task 3 are token-based for the same reason.

Leave the notebook’s optional Cleanup cell set to False — later tasks (especially Task 5) reuse the Sales-Assistant, HR-ChatAgent, and Support-Bot contracts you just created.

✅ Checkpoint: Three access contracts are deployed. Allowed-model requests succeed, disallowed-model requests are rejected, and bursts of traffic are throttled once a contract hits its token limit. The gateway can now enforce who gets what.


Next: Task 3 — Observe usage, cost, and throttling