> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Residency & Customer-Managed Keys

> Pin an AI agent's upstream egress to a region, and encrypt its data at rest under a key your own KMS gates. Both fail closed.

# Data Residency & Customer-Managed Keys

Two per-agent controls for teams with a regulatory constraint on where their
prompts go and who can decrypt what the gateway keeps.

Both **fail closed**. If the gateway cannot prove a destination is in your
region, or cannot obtain your key, it refuses the request — it does not fall
back to a global endpoint or to a KnoxCall-held key.

<Note>
  Set both on the agent, not the gateway: a team usually has one gateway and
  several agents, and residency is a property of the workload, not the container.
</Note>

## Data residency

Set `data_residency_region` on an agent to one of `us`, `eu`, `uk`, `ca`, `au`,
`jp`, `in`.

```bash theme={"dark"}
curl -X PATCH https://api.knoxcall.com/v1/ai-gateway/agents/$AGENT_ID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data_residency_region": "eu"}'
```

From then on, every upstream call this agent makes on the `/v1/ai` data plane —
the primary route, **every fallback route**, the output-schema retry, the
semantic-cache embedder, and your PII analyzer sidecar if you have configured one
— must target an endpoint KnoxCall classifies as serving that region. Anything
else is refused with `403 residency_violation` before that call is made.

<Warning>
  **The `/v1/mcp` plane is not covered yet.** An MCP server's `upstream_url` is
  dialled without a residency check, so tool-call arguments and results from an
  agent's MCP tools can leave the region even when the agent is pinned. If you are
  pinning for a regulatory reason, do not attach MCP servers to that agent until
  this lands. Tracked as AIGW-77.
</Warning>

The fallback path is the one that matters. An unpinned failover is exactly how a
Frankfurt workload ends up in `us-east-1` at 3am: the primary 5xxs, the gateway
does what it was configured to do, and nothing in the request looks wrong
afterwards. A pinned agent skips an out-of-region fallback and surfaces the
primary's error instead.

### What KnoxCall classifies

| Endpoint shape                               | Region                                             |
| -------------------------------------------- | -------------------------------------------------- |
| `bedrock-runtime.<aws-region>.amazonaws.com` | from the AWS region (`eu-west-2` → **UK**, not EU) |
| `<gcp-region>-aiplatform.googleapis.com`     | from the Vertex region                             |
| `<azure-region>.api.cognitive.microsoft.com` | from the Azure region                              |
| `eu.api.openai.com`                          | EU                                                 |
| `api.mistral.ai`                             | EU                                                 |
| `api.cohere.com`                             | US                                                 |

### What it refuses, deliberately

| Endpoint                                                                   | Why                                                                                                                                                                                                                                                                |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `api.anthropic.com`                                                        | Anthropic's public API is a single global endpoint. Use Bedrock or Vertex in your region.                                                                                                                                                                          |
| `api.openai.com`                                                           | OpenAI's default endpoint is global. Use `eu.api.openai.com` for EU.                                                                                                                                                                                               |
| `generativelanguage.googleapis.com`                                        | Google's Generative Language API is global. Use a regional Vertex endpoint.                                                                                                                                                                                        |
| `<resource>.openai.azure.com` and `<resource>.cognitiveservices.azure.com` | These are two hostnames for the SAME Azure resource, and `<resource>` is a name its creator chose from a global namespace — nothing stops an East US resource being called `westeurope`. Neither can prove a region. Use the regional Cognitive Services endpoint. |
| anything else                                                              | A host KnoxCall cannot classify is refused, not allowed.                                                                                                                                                                                                           |

<Warning>
  **Unclassifiable means refused.** The three global endpoints above are exactly
  the hosts most likely to be left in a route by accident, so "unknown = allow"
  would make the pin decorative. If you need an endpoint we do not classify, open
  a ticket — we would rather add a documented rule than have you turn the pin off.
</Warning>

### What this control is, precisely

It is an **administrative control on destination selection**. A pinned agent may
only egress to endpoints KnoxCall has classified as serving the pinned region.

It stops misconfiguration and silent drift, which is the failure mode that
actually produces residency incidents. It is **not** a cryptographic or network
guarantee: if you point your own route at a host you have classified in-region
and it is not, you are exporting your own data and no gateway can stop that.
Every vendor's "data residency" feature is this control. Ours says so.

### Auditing it

Each `ai_gateway_usage` row records the region the agent was pinned to **at the
time of that call**, so a residency audit reads evidence rather than the agent's
current configuration. It is returned by the usage export alongside cost and
attribution.

## Customer-managed encryption keys (CMEK)

Set `cmek_key_id` on an agent to the id of one of your tenant master keys. That
agent's PII token map — the reversible map behind [streaming PII
redaction](/ai-gateway/pii-redaction), which holds the original values — is then
encrypted under that key rather than the tenant's current active key.

### Prerequisite: BYOK

`cmek_key_id` must name a key whose `wrap_method` is `customer_kms` — a key your
own AWS/GCP/Azure KMS wraps. See [Bring your own key](/ai-gateway/byo-key).

**A key KnoxCall wraps is refused**, with `503 cmek_unavailable`. This is the
load-bearing check: without it, "CMEK enabled" could resolve to a
platform-wrapped key and you would have a green checkbox and no custody.

### What happens when the key is unavailable

Every one of these refuses the data-plane request with `503 cmek_unavailable`:

* the key does not exist, or is not this tenant's;
* the key is not customer-managed;
* your tenant has no active master key;
* your tenant's active key is no longer customer-managed (you rotated off BYOK);
* your KMS refuses to unwrap it (a revoked grant, a disabled key, an outage).

Nothing is written under a different key, and nothing is written in the clear.
Revoking the grant in your KMS therefore stops the agent within the key-cache
TTL — five minutes for BYOK keys — which is the same revocation contract the
rest of BYOK carries.

<Note>
  **Reads are not gated.** A KnoxCall envelope names its own key version, so rows
  written before you attached a CMEK still decrypt. Refusing to read them would
  destroy data you are entitled to see. Re-wrapping history under a new key is the
  BYOK rewrap sweep's job, not this setting's.
</Note>

### Key rotation

`cmek_key_id` names your customer-managed key **chain**, not one frozen version.
Rotating your tenant master key the normal way keeps the agent working: writes
follow whatever version of that chain is currently active. What is refused is a
chain that stops being customer-managed — if you rotate back onto KnoxCall's
platform wrap, the agent refuses rather than silently accepting a key we can
unwrap.

### Scope today

CMEK covers the agent's **PII token map** — the reversible `(surrogate →
original)` store, which is the one place the gateway durably holds your original
values.

Two honest limitations:

* **The response cache is not encrypted at all.** `ai_gateway_cache_entries`
  stores response bodies as plain bytes, and the buffered path caches AFTER
  detokenization — so for an agent with `pii_detokenize_response` on, the
  original values would sit in that table in the clear for the cache TTL. Rather
  than leave that beside a customer-managed key, **an agent with a `cmek_key_id`
  does not use the response cache at all.** You lose the cache; you do not lose
  custody.
* **The MCP plane's stored configuration** (`ai_gateway_mcp_servers`) is not
  covered. Its upstream credentials are envelope-encrypted through the normal
  tenant key — customer-managed too when BYOK is configured for the tenant — but
  they do not follow the per-agent pin.
