Tenant Isolation: Kong Workspaces vs Envoy Namespaces
Multi-tenant gateways fail in one of two ways: a tenant sees or edits another tenant’s configuration, or one tenant’s traffic starves another’s capacity. Both are isolation failures, but they live at different layers — one is a control-plane and RBAC problem, the other a data-plane and rate-limit-key problem — and the two leading approaches solve them very differently. Kong 3.x Workspaces partition entities inside one shared control plane and enforce access with RBAC; Envoy and Istio lean on Kubernetes namespaces plus per-namespace route discovery (RDS) to give each tenant an independently pushed route table. This page puts them head to head on blast radius, config management, and rate-limit-key isolation, with production config for each.
Prerequisite concepts
This page assumes the three-layer isolation model — routing, policy, and upstream — laid out in multi-tenant routing strategies; read that first, because “tenant isolation” only means something once you decide which of those layers must be separated. The wider context of where tenant scoping sits relative to route matching and config propagation is in the advanced routing and API versioning overview, which frames why isolation belongs in the data plane and not only in application code. If per-tenant quota is your primary concern, the rate limiting and throttling mechanics underpin the counter-key discussion below.
The two isolation models
A Kong Workspace is a named logical partition inside a single Kong control plane. Services, routes, consumers, plugins, and credentials each belong to exactly one workspace, and Kong RBAC roles grant read or write on a per-workspace basis. Crucially, all workspaces are served by the same shared data-plane workers: isolation is administrative and configuration-scoped, not process-scoped. Two tenants in two workspaces share proxy CPU, the same router, and the same compiled config generation.
An Envoy/Istio namespace boundary is Kubernetes-native. Each tenant owns (or is assigned) a namespace; their routing intent — Istio VirtualService and DestinationRule resources, or raw Envoy RouteConfiguration — is compiled into a per-namespace route table and delivered to the sidecars or gateway pods that serve that namespace through RDS. Namespace-scoped RBAC governs who can edit those resources, and NetworkPolicy can wall off traffic between namespaces. Each tenant’s route config is an independently versioned, independently pushed resource.
The diagram makes the core trade-off visible: Kong concentrates tenants into one shared, cheaply operated fleet with administrative separation; Istio spreads them across independent route tables and pods with stronger separation but more moving parts.
Config management and RBAC scoping
Kong Workspaces shine when one platform team operates many tenants and wants a single admin surface with delegated, scoped access. You create a workspace per tenant, place that tenant’s entities inside it, and bind an RBAC role that can only touch that workspace:
# Kong 3.x (Enterprise) — create a tenant workspace and a scoped RBAC role
curl -sX POST http://kong-cp:8001/workspaces \
--data "name=tenant-alpha"
# Create a role and grant it write only within tenant-alpha's endpoints
curl -sX POST http://kong-cp:8001/rbac/roles \
--data "name=alpha-admin"
curl -sX POST http://kong-cp:8001/rbac/roles/alpha-admin/endpoints \
--data "workspace=tenant-alpha" \
--data "endpoint=*" \
--data "actions=create,read,update,delete"
Entities are then declared inside the workspace, and the same declarative config the platform already uses gets a workspace scope:
# Kong 3.x — decK config applied into the tenant-alpha workspace
# deck gateway sync --workspace tenant-alpha tenant-alpha.yaml
_format_version: "3.0"
services:
- name: alpha-orders
url: http://alpha-orders.internal:8080
routes:
- name: alpha-orders-route
paths: ["/orders"]
# Tenant is disambiguated by host, not a shared path prefix,
# so one tenant cannot shadow another's routes.
hosts: ["alpha.api.example.com"]
plugins:
- name: rate-limiting
config:
minute: 600
policy: redis
redis_host: redis.internal
# Counter key is scoped to this consumer within this workspace.
fault_tolerant: true
Istio takes the config boundary down to the Kubernetes namespace. Each tenant’s routing lives in resources in their namespace, and exportTo: ["."] keeps a VirtualService visible only within that namespace so it cannot be referenced or shadowed cross-tenant:
# Istio (Envoy 1.32+ data plane) — namespace-scoped route, not exported cross-namespace
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: alpha-orders
namespace: tenant-alpha
spec:
hosts: ["alpha.api.example.com"]
exportTo: ["."] # visible only inside tenant-alpha namespace
gateways: ["tenant-alpha/tenant-gw"]
http:
- match:
- uri: { prefix: "/orders" }
route:
- destination:
host: alpha-orders.tenant-alpha.svc.cluster.local
RBAC is enforced by Kubernetes itself: a Role and RoleBinding in tenant-alpha let a tenant team edit their own VirtualService objects and nothing in tenant-beta. The config boundary and the access boundary are the same object, which is conceptually cleaner than Kong’s separate workspace-plus-RBAC pairing but requires Kubernetes and per-namespace CI wiring.
Blast radius and failure domains
This is where the two diverge most sharply. Because Kong compiles all workspaces into one router served by one shared data-plane generation, a bad config push, a control-plane outage, or a data-plane crash is a shared failure domain — workspace RBAC protects against a tenant admin editing the wrong entity, but not against a fleet-wide config or capacity event. Kong hybrid mode narrows this by keeping the data plane serving its last-good cached config if the control plane goes down, but the data plane itself remains shared.
Per-namespace RDS scoping gives independent failure domains: each tenant’s RouteConfiguration is pushed as its own resource, so a malformed route for tenant A is rejected in isolation and never recompiles tenant B’s table. Push tenant A to dedicated gateway pods per namespace and even a data-plane crash is contained. The cost is operational surface area — more pods, more RDS streams, more control-plane load — which is exactly the trade the multi-tenant routing strategies overview frames as shared-versus-dedicated across the routing, policy, and upstream layers.
Rate-limit key isolation
The subtlest isolation failure is a shared counter. Being in different workspaces or namespaces does not, by itself, separate rate-limit counters if both tenants share one Redis and the key does not carry a tenant discriminator. In Kong, attach the plugin per workspace and rely on the consumer plus route scope so counters cannot collide; if you share Redis across workspaces, confirm the effective key includes a tenant-unique element:
# Kong 3.x — per-tenant rate limit; key derives from consumer + route scope.
# Attach inside each workspace so counters never share a namespace.
plugins:
- name: rate-limiting
config:
minute: 600
policy: redis
redis_host: redis.internal
redis_database: 3 # separate logical DB per tenant tier is a coarse guard
fault_tolerant: true
In Envoy, tenant identity must be an explicit rate-limit descriptor so the rate-limit service keys on it. The route contributes a tenant descriptor derived from the matched virtual host, and the global rate-limit service buckets on that key:
# Envoy 1.32+ — per-tenant descriptor drives the global rate limit service
route:
cluster: alpha_orders
rate_limits:
- actions:
- request_headers:
header_name: "x-tenant-id"
descriptor_key: "tenant"
- remote_address: {} # per-client within the tenant bucket
The rule for both gateways: the counter namespace must contain the tenant identity end to end, or one tenant exhausting its quota can decrement another tenant’s budget through a colliding key.
Decision matrix
| Dimension | Kong 3.x Workspaces | Envoy / Istio namespace + RDS |
|---|---|---|
| Isolation layer | Logical entities + RBAC in one control plane | Kubernetes namespace + per-namespace route table |
| Data-plane sharing | Shared fleet, one router, one config gen | Can be per-namespace gateway pods |
| Config blast radius | Shared — fleet-wide push/outage affects all | Per-tenant RouteConfig, independently pushed |
| Access control | Kong RBAC roles scoped to workspace | Kubernetes RBAC on namespaced resources |
| Rate-limit isolation | Per-workspace plugin; guard shared Redis key | Explicit tenant descriptor to rate-limit service |
| Operational cost | Low — one CP, one admin surface | Higher — namespaces, pods, RDS streams, CI |
| Best fit | One platform team, many tenants, shared capacity | Strong separation, tenant-owned namespaces, K8s-native |
The matrix resolves to a single question: is administrative separation on shared capacity sufficient, or do tenants need independent failure domains? Kong Workspaces are the pragmatic answer to the former; namespace plus RDS scoping, up to dedicated gateway deployments, is the answer to the latter.
Gotchas and failure signals
Shared Redis counter collision. Two workspaces or namespaces pointing at the same Redis logical database without a tenant discriminator in the key silently share a budget. The signal is one tenant getting throttled by another tenant’s traffic — 429s that do not correlate with the throttled tenant’s own request rate.
Host-based routing gaps in Kong workspaces. Kong routes are matched globally across workspaces on the shared router; if two workspaces define routes on overlapping paths without distinct hosts, the router can match the wrong workspace’s route. Always disambiguate tenants by host or a tenant-unique path segment, not a bare shared prefix.
Istio exportTo left at default. Without exportTo: ["."], a VirtualService is visible cluster-wide and can be referenced from other namespaces, quietly breaking the isolation you assumed. The signal is cross-namespace traffic appearing in a tenant gateway’s access logs.
Kong control-plane outage as a shared event. Because the data plane is shared, a control-plane failure during a push can leave the whole fleet on stale config. Monitor the config version across data-plane nodes and keep old routes alive through a deprecation window rather than deleting on cutover.
Validation
- Each tenant’s entities live in exactly one workspace (Kong) or one namespace (Istio); no tenant can read or edit another’s config.
- RBAC is scoped per workspace (Kong roles) or per namespace (Kubernetes
RoleBinding) and tested with a deliberately under-privileged token. - Tenants are disambiguated by host or a tenant-unique path segment — never a bare shared path prefix on the same router.
- Rate-limit counter keys include a tenant discriminator end to end; a shared Redis database is verified not to collide across tenants.
- Envoy routes carry an explicit
tenantrate-limit descriptor; Kong rate-limit plugins are attached per workspace. - Blast-radius requirement is documented: shared fleet (workspaces) vs per-namespace/per-pod failure domains chosen deliberately against the tenant SLA.
-
exportTo: ["."](or equivalent scoping) is set on tenantVirtualServiceresources so they are not visible cross-namespace. - Config version is monitored across the shared Kong data plane so a push or control-plane outage is detected as a fleet-wide event.
FAQ
What is the difference between a Kong Workspace and an Envoy or Istio namespace for tenant isolation?
A Kong Workspace is a logical partition inside one Kong control plane and shared data-plane fleet: entities such as services, routes, consumers, and plugins live in a named workspace, and RBAC roles scope who can read or write them. Isolation is administrative and configuration-level, not process-level, because all workspaces are served by the same proxy workers. An Istio namespace plus per-namespace RDS is a Kubernetes-native boundary where each tenant’s routes are a separate RouteConfiguration pushed to the sidecars or gateways that serve that namespace, and namespace-scoped RBAC and NetworkPolicy govern access. Kong Workspaces optimize for one operational team managing many tenants on shared infrastructure; namespace scoping optimizes for stronger config and network separation, often with tenants owning their own namespaces.
Do Kong Workspaces isolate rate-limit counters between tenants?
Not automatically by the mere fact of being in different workspaces. A rate-limiting plugin instance is scoped to the entity it is attached to (a service, route, or consumer) within a workspace, and its counter key is derived from that scope plus the consumer or credential. If two workspaces share the same Redis instance and you do not include a workspace or tenant discriminator in the key, counters can collide. The correct pattern is to attach the plugin per workspace and ensure the counter namespace includes the tenant identity, so one tenant exhausting its quota cannot decrement another tenant’s budget.
Which approach gives a smaller blast radius when a tenant config change goes wrong?
Per-namespace RDS scoping in Envoy or Istio generally gives the smaller blast radius because each tenant’s RouteConfiguration is a separate resource pushed independently; a malformed route for one tenant is rejected or applied in isolation and does not recompile another tenant’s routes. Kong Workspaces share one router and one data-plane config: workspace RBAC prevents a tenant admin from editing another workspace, but a bad config push or a control-plane outage affects the whole shared fleet. If independent failure domains per tenant are a hard requirement, separate namespaces, or in the strongest case separate gateway deployments, beat logical workspaces.
Can I run per-tenant Kong Workspaces and still share one data-plane fleet?
Yes, and that is the intended model. Kong hybrid mode runs one control plane that holds all workspaces and pushes a single compiled config to a shared data-plane fleet, so tenants are separated administratively through workspaces and RBAC while sharing proxy capacity. This is cost-efficient and simple to operate, but it means the data plane is a shared failure domain and a shared performance domain: a noisy tenant’s traffic competes for the same workers, so pair workspaces with per-tenant rate limits and, where SLAs demand it, dedicated upstream pools or separate data-plane node groups.
Parent: Multi-Tenant Routing Strategies
Related
- Advanced Routing & API Versioning — where tenant isolation sits in the routing, policy, and upstream layers of a request path.
- Rate Limiting & Throttling Strategies — counter-key design and Redis-backed limits that make per-tenant quotas safe.
- Security Boundaries & Zero-Trust — trust boundaries and credential scoping that complement config-level tenant isolation.