Tenant Isolation Reference
This page documents how tenant identity is configured, mapped, and enforced across Zelkor.
JWT Configuration
Identity comes from a verified JWT. The platform validates the token and maps it to a tenant ID. There is no default tenant — if the claim is missing or validation fails, the request is rejected immediately.
Configuration in values.yaml:
yaml
platform:
tenants:
jwt:
issuer: "https://your-idp.example.com"
audiences:
- "zelkor-platform"
remoteJwksUri: "https://your-idp.example.com/.well-known/jwks.json"
jwksEgressCIDRs:
- "203.0.113.0/24"
tenantClaims:
- "tenant_id"
- "org_id"
- "sub"
# Optional mapping from IDP org names to internal tenant IDs
orgMappings:
"idp-org-uuid-1": "tenant-a"
"idp-org-uuid-2": "tenant-b"issuer must equal the JWT iss claim. remoteJwksUri must be the HTTPS JWKS URL the IdP publishes. When NetworkPolicies are on, set jwksEgressCIDRs to the IdP CIDRs (TCP 443). Do not set issuer or remoteJwksUri to an in-cluster Service URL that only answers with a public Host header. For those IdPs, put the keys in a ConfigMap (--jwks-file / jwksConfigMap). See JWT rejected (401).
IDM Integration Options
Zelkor uses standard JWKS (JSON Web Key Set) validation. It integrates with any Identity Management (IDM) system that issues signed JWTs:
- Okta / Auth0: Set
issuerandremoteJwksUrito your authorization server's endpoints (e.g..well-known/jwks.json). Use a custom claim (e.g.,org_id) intenantClaims. - Microsoft Entra ID (Azure AD): Use the v2.0 endpoint for
issuerandremoteJwksUri. ThetenantClaimsis typicallytid(tenant ID) or a mapped app role. - Keycloak: Point
remoteJwksUrito the realm's certs endpoint (/realms/<realm>/protocol/openid-connect/certs). - Custom IDP: Serve a static JWKS endpoint. If your IDP issues opaque UUIDs but your agent expects readable names, use
orgMappingsto translate them (e.g.,b2f4...: tenant-a).
Tool Filtering vs. Forwarding
The platform enforces tenant isolation differently depending on the tool backend.
Native MCP Servers
Native servers apply strict filters based on the tenant ID. The agent cannot bypass these.
- Postgres: The MCP server injects
tenant_id = :tenantinto queries or relies on Postgres Row-Level Security (RLS) configured for the connection role. - Qdrant: The MCP server wraps vector operations with a strict payload filter:
must: [{key: "tenant_id", match: {value: "the-tenant"}}].
Extra MCP Backends
For backends registered via workspace.tools, Zelkor forwards the tenant identity but does not natively filter the data (as it does not control the external SaaS).
The identity is forwarded as an HTTP header (e.g., X-Tenant-ID) to the extra backend. The external backend is responsible for enforcing its own isolation.
zelkor token mint & localSigning
For local development, testing, or fully air-gapped deployments without an IdP, you can enable Zelkor's native localSigning fallback feature. This allows the platform to act as its own signer.
Configuration in values.yaml for a single-tenant isolated environment:
yaml
platform:
tenants:
jwt:
localSigning:
enabled: true
# Automatically generate a token for this tenant during install.
# For a static-key experience in an isolated environment, set a long TTL.
seedTenant: "tenant-a"
seedTokenTTL: "8760h" # 1 yearWhen enabled (which is the default in profiles/values-local.yaml used by the quickstart script), you can also mint valid JWTs using the CLI:
bash
# Mint a token for a specific tenant
zelkor token mint --release zelkor-platform --tenant "tenant-a"
# Mint a token with a specific time-to-live (default 1h)
zelkor token mint --release zelkor-platform --tenant "tenant-b" --ttl "24h"The resulting token can be passed in the Authorization: Bearer <token> header to the AI Gateway or agent endpoints.