Skip to main content

Multi-Tenant Data Isolation: Preventing Cross-Organization Contamination

Multi-Tenant Data Isolation: Preventing Cross-Organization Contamination

Shared AI infrastructure is only safe when the boundaries are explicit. A single gateway can serve multiple organizations, business units, or regulated environments, but that is exactly where cross-organization contamination starts if identity, routing, and policy context are ambiguous. Keeptrusts gives you the controls to isolate by API key, request header, route, and policy chain so one tenant's traffic does not inherit another tenant's provider path, access rules, or review surface.

Use this page when

  • You run one Keeptrusts gateway for multiple organizations, teams, or regulated customer environments.
  • You need to prevent one tenant's request from being routed with another tenant's credentials or controls.
  • You want an isolation model that is testable from policy config rather than hidden in application code.

Primary audience

  • Primary: Technical Engineers
  • Secondary: Technical Leaders, AI Agents

The problem

Cross-tenant contamination rarely looks dramatic at first. It usually starts as a convenience decision.

One API key is reused across multiple customers because onboarding needs to happen quickly. One route handles every /v1/chat/completions call because the payloads look similar. One policy chain serves everyone because "we can tighten it later." Over time, these shortcuts create a system where a support tenant can inherit an engineering route, a regulated customer can fall back to a general provider target, or an event reviewer can no longer tell which organization actually generated the request.

The second problem is missing identity. If requests do not consistently include tenant and user headers, the gateway has very little context to enforce minimum rules. It can forward traffic, but it cannot tell whether the caller should have access to a tool, whether the request belongs to the correct organization, or whether the resulting audit record is attributed correctly.

The third problem is mixed isolation layers. Some teams try to solve tenant separation only with network boundaries, others only with API keys, and others only with model routing. None of those is sufficient alone. A secure shared gateway needs key isolation, identity validation, and deterministic route selection at the same time.

The solution

Keeptrusts gives you a composable answer built from three documented capabilities.

Use Routes and Consumer Groups to segment inbound traffic by API key and request path. Consumer groups identify the caller by hashed key and can assign a tenant-specific upstream or chain. Routes can then match on headers such as X-Org-ID so the tenant identity in the request must agree with the tenant identity implied by the key.

Use RBAC to require specific identity headers on every request. This turns tenant attribution from an application convention into an enforcement rule. Missing X-User-ID, X-Org-ID, or X-User-Role values stop the request before it reaches an upstream provider.

Use Conditional Chains Configuration when some tenants require stricter controls than others. That lets you raise the bar for one organization, path, or gateway without forking your entire configuration estate.

The result is simple to explain: key-based segmentation decides who the caller is, route matching decides which tenant path applies, and RBAC decides whether the request is complete enough to proceed.

Implementation

This configuration isolates two tenants that share one gateway. Each tenant has its own consumer group, its own route match, and the same baseline identity requirements.

pack:
name: tenant-isolation
version: "1.0.0"
enabled: true

providers:
targets:
- id: alpha-zdr
provider: openai
model: gpt-5.4-mini-mini
secret_key_ref:
env: OPENAI_ALPHA_KEY

- id: beta-zdr
provider: openai
model: gpt-5.4-mini-mini
secret_key_ref:
env: OPENAI_BETA_KEY

consumer_groups:
key_header: Authorization
groups:
- name: alpha
api_keys:
- "sha256:8ed3f6ad685b959ead7022518e1af76cd816f8e8ec7ccdda1ed4018e8f2223f8"
upstream: alpha-zdr
chain:
- rbac
- pii-detector
- audit-logger

- name: beta
api_keys:
- "sha256:f44e64e75f3948e9f73f8dfa94721c4ce8cbb4f265c4790c702b2d41cfbf2753"
upstream: beta-zdr
chain:
- rbac
- pii-detector
- audit-logger

routes:
- name: alpha-chat
path: "/v1/chat/completions"
headers:
X-Org-ID: alpha
upstream: alpha-zdr
priority: 20

- name: beta-chat
path: "/v1/chat/completions"
headers:
X-Org-ID: beta
upstream: beta-zdr
priority: 20

policy:
rbac:
deny_if_missing:
- X-User-ID
- X-Org-ID
- X-User-Role
require_auth: true
roles:
analyst:
allowed_tools:
- search
- summarize
denied_tools:
- dangerous_*
admin:
allowed_tools:
- "*"
denied_tools: []

pii-detector:
action: redact
redaction:
marker_format: label
include_metadata: true

audit-logger: {}

The important detail is not any single field. It is the agreement between them.

The caller's API key resolves the consumer group first. That means the request already belongs to alpha or beta before route matching begins. The route then checks the X-Org-ID header. If the caller presents an alpha key but sends X-Org-ID: beta, the request no longer fits the intended path. RBAC adds a second guardrail by refusing requests that do not carry the identity headers you rely on for attribution and downstream review.

This is stronger than "use a different upstream per customer." It means tenant identity exists at the key boundary, the request boundary, and the policy boundary at once.

A practical rollout pattern is to start with one tenant and one default route, then onboard additional tenants only when they receive their own consumer-group hash and route match. Do not share a temporary API key between organizations just to accelerate onboarding. That is exactly how contamination starts.

Once the config is in place, validate it with kt policy lint, then use kt events to review recent decision records and confirm that request attribution is now deterministic and easy to explain.

Results and impact

Teams that implement tenant isolation at the gateway usually see three benefits quickly.

The first is clean attribution. Reviewers and incident responders can tell which organization, user, and route produced a request without reconstructing that context from application logs.

The second is lower blast radius. A mistake in one tenant's routing or provider credentials no longer quietly spills over into another tenant's traffic.

The third is better customer trust. Isolation stops being a promise buried in architecture diagrams and becomes something you can point to in configuration, validation output, and decision events.

Key takeaways

  • Use Routes and Consumer Groups to isolate callers by hashed API key and path.
  • Use RBAC to require tenant and user identity on every request.
  • Make the key identity and the request identity agree. Do not rely on one without the other.
  • Add Conditional Chains Configuration when one tenant needs stricter controls than another.
  • Treat multitenancy as a runtime enforcement problem, not a naming convention.

Next steps