Overview
The commercial API gateway market has narrowed around a small set of vendors — IBM, MuleSoft, Apigee — whose products were designed for a world where the gateway was a monolithic appliance and the API portfolio was owned by a central team. Cloud-native architectures have eroded both assumptions. Service teams deploy independently, traffic patterns are heterogeneous, and the gateway is no longer a single enforcement point but one of several places where policy lives.
Kong and Envoy are the two open-source runtimes that have gained production traction in regulated environments. They are not interchangeable: Kong is a purpose-built API gateway with a plugin model and a management layer. Envoy is a general-purpose L7 proxy designed to be programmed by a control plane. Both can enforce TLS, authentication, and rate limits at the edge — but they do it differently, and the right choice depends on where policy needs to live and who needs to author it.
This article covers both, with enough depth on configuration that you can deploy either in a bank environment and have it pass a security review.
This article covers Kong Gateway (OSS and Enterprise 3.x) and Envoy Proxy 1.30 in standalone mode and as the Istio sidecar/ingress. It does not cover Gloo Edge, Ambassador, or APISIX. For IBM API Connect, see the companion article in this series.
Kong architecture
Kong is built on top of Nginx and lua-nginx-module (OpenResty). The proxy core is Nginx — battle-tested for throughput and connection handling. Kong wraps it with a plugin execution engine in Lua (and increasingly Go via the PDK), a declarative configuration layer, and optionally a control-plane database (PostgreSQL) or a DB-free declarative mode (kong.yaml).
The separation between control and data plane is a first-class concept in Kong Enterprise and an emerging pattern in the OSS version. In the DB-less mode — which is what you want in Kubernetes — the proxy reads a declarative kong.yaml file that is mounted as a ConfigMap or served from a Kong Konnect control plane. There is no shared state in the proxy tier; this makes the data plane purely stateless and scale-safe.
Plugins execute in phases tied to the Nginx request lifecycle: init_worker, access, header_filter, body_filter, log. A plugin can short-circuit the pipeline at any phase — kong.response.exit() in the access phase rejects before any upstream call is made. This is the correct design for auth and rate-limit plugins.
Envoy & service mesh
Envoy is a C++ L7 proxy built by Lyft and donated to the CNCF. Unlike Kong, it is not a gateway product — it is a proxy runtime designed to be configured entirely by an external control plane via the xDS API (Listener Discovery Service, Route Discovery Service, Cluster Discovery Service, Endpoint Discovery Service). Istio, which is the dominant Kubernetes service mesh, uses Envoy as its data plane and acts as the xDS control plane.
In financial services, Envoy appears in two roles:
- As the Istio ingress gateway — a dedicated Envoy instance at the cluster edge, replacing an external load balancer or Kong for intra-cluster north-south traffic.
- As the Istio sidecar — one Envoy per pod, handling east-west mTLS, circuit breaking, retries, and telemetry entirely transparently to the application.
The key difference from Kong: Envoy’s configuration is xDS-driven, which means you need a control plane (Istio, Consul Connect, or a custom xDS server) to manage it at scale. You do not write YAML that describes a proxy configuration — you write CRDs (VirtualService, Gateway, DestinationRule) that Istio translates to xDS and pushes to Envoy. This is powerful but adds an abstraction layer; when something goes wrong, you need to understand both the Istio CRD model and the Envoy xDS translation.
Envoy supports WebAssembly (Wasm) extensions via the proxy-wasm ABI. This allows custom filters compiled to Wasm to run inside Envoy’s filter chain without forking the binary. For bank-specific policy enforcement (custom PEP logic, SAMA-specific audit headers), a Wasm filter avoids the overhead of an external authorisation call while keeping the core binary unmodified.
Kong vs Envoy: when each wins
These tools solve overlapping problems from different angles. The decision is not Kong or Envoy — most mature Kubernetes environments run Envoy as the sidecar mesh and Kong (or an Istio ingress gateway) at the cluster boundary. But when budget, operational capacity, or deployment target forces a choice, here are the trade-offs that hold up in practice.
| Dimension | Kong Gateway 3.x | Envoy / Istio 1.22 |
|---|---|---|
| Configuration model | Declarative YAML (deck) or Admin API. Human-readable, version-controllable directly. |
xDS via control plane (Istio CRDs). Requires understanding two abstraction layers. |
| Plugin / filter ecosystem | Large Lua/Go plugin library. Custom plugins via PDK. Kong Hub for third-party. | Envoy native filters + Wasm extensions. Fewer out-of-the-box; more flexible at the byte level. |
| mTLS enforcement | Configured per service in Kong. External cert manager integration for rotation. | Automatic, cluster-wide via PeerAuthentication. Cert rotation handled by Istio CA. |
| Rate limiting | First-class plugin with Redis backend for cluster-wide counters. Per consumer, per route, per service. | Not native — requires an external rate-limit service (e.g. Ratelimit by Envoy project) or a Wasm filter. |
| Operational footprint | Kong proxy + optionally Kong Manager + PostgreSQL. Manageable for a small team. | Envoy sidecar per pod + Istio control plane (istiod). Higher resource cost; requires Istio operational expertise. |
| Fit for north-south API gateway | Excellent. Designed for this role. | Adequate via Istio ingress gateway, but lacks consumer management, developer portal, and API catalogue. |
| Fit for east-west service mesh | Poor — Kong is not a sidecar proxy. | Excellent. The canonical choice. |
| Migration from IBM API Connect | Closer semantic mapping: services, routes, plugins map to APIs, products, policies. | More distant — Istio CRDs do not naturally express quota plans or consumer app subscriptions. |
The practical answer for a SAIB-style environment: use Kong at the network edge (external partner APIs, SAMA Open Banking endpoints) and Istio/Envoy for east-west service mesh. Kong enforces the consumer contract — auth, quota, transformations; Istio enforces the service-to-service contract — mTLS identity, circuit breaking, traffic policy.
Security configuration
Two security requirements surface in every SAMA security audit for an open-source gateway: mTLS for all external partner traffic and FAPI 2.0-compliant OAuth for open banking endpoints. Neither is configured out of the box; both require deliberate plugin or filter chain setup.
Kong: mTLS termination and client certificate verification
Kong terminates TLS on its proxy listeners. Mutual TLS requires configuring a CA certificate in Kong and attaching it to the relevant service or route. The mtls-auth plugin (Kong Enterprise) or the request-termination + Nginx ssl_verify_client combination (OSS) enforces client certificate presence and validity.
# Step 1: register the partner CA as a CA certificate in Kong
_format_version: "3.0"
ca_certificates:
- id: partner-ca-01
cert: |
-----BEGIN CERTIFICATE-----
# PEM of the partner CA bundle
-----END CERTIFICATE-----
# Step 2: define the service and route
services:
- name: payments-core
url: https://payments.svc.internal/v1
tls_verify: true
ca_certificates: [ internal-ca-01 ]
routes:
- name: partner-payments-route
hosts: [ api.acme-bank.com ]
paths: [ /partner/payments ]
protocols: [ https ]
plugins:
# mtls-auth enforces client cert against the registered CA
- name: mtls-auth
config:
ca_certificate_ids: [ partner-ca-01 ]
revocation_check_mode: SKIP # use STRICT if CRL/OCSP is reachable
skip_consumer_lookup: false
authenticated_group_by: DN # map cert DN to Kong consumer
The authenticated_group_by: DN setting is load-bearing for partner onboarding. It maps the Distinguished Name of the client certificate to a Kong consumer, which means rate-limit plugins downstream can count requests per partner without requiring an additional API key exchange. This is the standard pattern for SAMA Open Banking B2B channels where the partner cert is the identity credential.
Kong: OIDC / FAPI 2.0 with the openid-connect plugin
The openid-connect plugin (Kong Enterprise) handles token introspection, JWT validation, and PAR (Pushed Authorisation Request) flows required by FAPI 2.0. Configure it with proof_of_possession_mtls: true to enforce the certificate-bound access token requirement from FAPI 2.0.
plugins:
- name: openid-connect
route: open-banking-accounts-route
config:
issuer: https://idp.acme-bank.com/realms/ob-prod/.well-known/openid-configuration
client_id: kong-rs
client_secret: {vault://env/KONG_IDP_SECRET} # never inline secrets
auth_methods:
- bearer
- introspection
introspection_endpoint: https://idp.acme-bank.com/realms/ob-prod/protocol/openid-connect/token/introspect
introspection_endpoint_auth_method: client_secret_basic
cache_introspection: true
introspection_hint: access_token
# FAPI 2.0: certificate-bound tokens (RFC 8705)
proof_of_possession_mtls: true
proof_of_possession_auth_methods_validation: true
scopes_required: [ accounts:read ]
consumer_claim: sub
consumer_by: [ username ]
upstream_headers_claims:
- claim: sub
header: X-Authenticated-Sub
- claim: acr
header: X-Auth-Class
The {vault://env/KONG_IDP_SECRET} syntax is Kong’s native vault reference. It resolves at runtime from an environment variable or a HashiCorp Vault / AWS Secrets Manager backend. Never paste a client secret into a kong.yaml that lives in a Git repository — even an internal one. A SAMA security audit will flag hardcoded secrets in configuration files as a critical finding.
Rate limiting in Kong
Kong’s rate-limiting-advanced plugin (Enterprise) or rate-limiting (OSS) implements sliding-window counters backed by Redis. The advanced plugin supports multiple sliding windows simultaneously, which is the correct model for a financial API that has both a burst constraint (requests per second) and a contractual quota (requests per day).
plugins:
- name: rate-limiting-advanced
route: partner-payments-route
config:
identifier: consumer # key per authenticated consumer, not per IP
window_type: sliding
limit:
- 50 # burst: 50 req / second
- 100000 # daily quota: 100 000 req / day
window_size:
- 1 # seconds for burst window
- 86400 # seconds for daily window
sync_rate: 10 # sync Redis counter every 10 req (balances accuracy vs latency)
strategy: redis
redis:
host: redis-sentinel.svc.internal
port: 26379
sentinel_master: mymaster
password: {vault://env/REDIS_AUTH_TOKEN}
ssl: true
ssl_verify: true
error_code: 429
error_message: Rate limit exceeded
hide_client_headers: false # expose X-RateLimit-* headers to consumers
Three configuration decisions here that matter in production:
identifier: consumer— counts per authenticated Kong consumer, not per IP. This is the only correct model once you have mTLS or OIDC authentication in place. IP-based rate limiting is trivially bypassed by a partner behind NAT or a load balancer.sync_rate: 10— each Kong node writes to Redis every 10 requests rather than every request. This reduces Redis load by an order of magnitude at high throughput. The trade-off: a consumer can briefly exceed their limit by up to10 × node_countrequests before the global counter catches up. For daily quotas this is immaterial; for burst limits you may want a lower sync rate.- Redis Sentinel, not a single Redis node. The rate-limit counter is in-memory in Redis. If Redis goes down and
strategy: redisis set, Kong falls back to allowing all requests (fail-open) unless you configurefault_tolerant: false. Sentinel gives you HA without changing the fail-open behaviour.
Migration from commercial gateway
Migrating from IBM API Connect or MuleSoft API Manager to Kong is a project, not a deployment. The semantic mapping is close but not exact, and the operational model — how you deploy, test, and rollback a configuration change — is completely different. A dark-launch migration is the only pattern that consistently works without an outage window.
-
Inventory and categorise existing APIs
Export the full API catalogue from the current gateway. Categorise each API by traffic tier (internal, partner, public), auth mechanism (OAuth, mTLS, API key), and rate-limit policy. Flag any APIs with
gatewayscriptor XSLT transforms — these require the most translation effort. -
Build the Kong declarative config skeleton
Map each API to a Kong service and route in a
kong.yamlfile. Attach auth plugins first, rate-limit second, transform plugins last. Usedeck validateto catch structural errors before any deployment. -
Deploy Kong in shadow mode alongside the existing gateway
Route a copy of production traffic to Kong using traffic mirroring at the load balancer (NGINX
mirrordirective, HAProxyhttp-request send-spoe, or AWS ALB mirroring). Kong processes the requests but discards the responses; you compare access logs from both gateways for auth failures, policy mismatches, and latency divergence. -
Canary the lowest-risk route
Pick an internal API (not customer-facing, not payment-critical) and shift 5% of live traffic to Kong. Monitor for error-rate regression and latency spikes for 24 hours. Increase in 10% increments until 100%.
-
Migrate partner and external APIs
These require consumer migration: re-issuing API keys or provisioning Kong consumers with the same client certificates. Coordinate with partners on the changeover date. Keep the old gateway running as a fallback for 30 days — partners will miss comms.
-
Decommission the old gateway
Only after zero traffic for 14 days on the old gateway. Check analytics and SIEM for any lingering requests. Archive the old gateway config — you will need it for an audit question about the migration period.
Payment APIs carry SAMA oversight obligations. A cut-over that causes even a brief outage on a settlement window is a regulatory incident. Schedule payment API migrations for mid-week, mid-morning, with the core banking team on standby, and a tested rollback procedure that gets you back to the old gateway in under 5 minutes.
Production topology
A production Kong deployment on Kubernetes follows the hybrid mode pattern: a Kong Konnect or self-hosted control plane manages config; stateless Kong data-plane pods run in the workload cluster. This matches the DB-less design — config is fetched from the control plane at startup and cached in-memory, so pod restarts are safe even if the control plane is temporarily unreachable.
Three topology rules that hold up in regulated environments:
- The load balancer must do TLS passthrough, not termination. Kong is the TLS termination point. Terminating at the LB and re-encrypting to Kong means the client certificate is lost before it reaches the
mtls-authplugin. Partner mTLS breaks silently if the LB terminates. - Rate-limit counters must be in Redis, not in-memory. With three Kong data-plane pods, each pod maintains independent in-memory counters if you use
strategy: local. A consumer can make3 × burst_limitrequests before any pod rejects. Redis strategy gives you accurate global counters at the cost of a Redis round-trip per sync. - Kong does not replace Istio inside the cluster. Kong enforces the edge contract. Istio enforces the service-to-service contract. Both are necessary in a regulated environment where the audit expects mTLS on every hop, not just the edge.
Observability
Kong exposes a Prometheus metrics endpoint at /metrics on the status port (default 8100). The key metrics for a financial API gateway are latency percentiles by route, upstream error rates, and rate-limit rejection counts.
# Enable the Prometheus plugin globally
plugins:
- name: prometheus
config:
per_consumer: true # label metrics by consumer name
status_code_metrics: true
latency_metrics: true
upstream_health_metrics: true
bandwidth_metrics: false # high cardinality; disable unless needed
# Grafana alert: p99 latency spike on the payments route
# histogram_quantile(0.99,
# sum(rate(kong_latency_bucket{route="partner-payments-route"}[5m])) by (le))
# > 500 (alert if p99 exceeds 500ms for 5 minutes)
For Envoy/Istio, the telemetry comes from the sidecar and the ingress gateway automatically. Istio generates three types: access logs (per request), Prometheus metrics (aggregated), and distributed traces via Zipkin/Jaeger. The combination gives you the full picture: Kong sees the consumer identity and the rate-limit decision; Istio sees the intra-cluster hop latency and the mTLS handshake.
Send Kong access logs to your SIEM (Splunk, QRadar) via the tcp-log or http-log plugin, not by tail-following pod stdout. Pod stdout is ephemeral; the log plugin writes to an endpoint that is available even during pod restarts. For SAMA audit purposes, you need a durable, tamper-evident audit log of every request that crosses the regulated boundary — pod logs alone do not satisfy this.
Common pitfalls
Kong Manager cannot write configuration to a DB-less deployment. If you use DB-less (the correct choice for Kubernetes), Kong Manager is read-only. Teams frequently discover this after spending a day trying to edit a route in the UI and finding that changes do not persist across pod restarts. Manage configuration exclusively via deck sync from a Git-controlled kong.yaml.
By default, Istio injects Envoy sidecars into every pod in a namespace with the istio-injection: enabled label. This includes Kong pods. The sidecar will intercept Kong’s outbound connections to upstream services and apply mTLS — which is correct behaviour — but it will also intercept Kong’s connections to its own status port and Redis, which can break health checks and rate-limit sync in non-obvious ways. Label Kong pods with sidecar.istio.io/inject: "false" unless you have explicitly tested the sidecar-injected behaviour.
sync_rate trade-off at low quotasA sync_rate of 10 with 3 Kong pods means a consumer on a 15-requests-per-day free-tier plan could make up to 30 requests before the rate limiter kicks in (each pod accumulates 10 locally before syncing). For high-volume commercial plans this error is negligible; for tight free-tier quotas it matters. Either lower the sync rate or implement a hard Redis check for low-quota consumers.
When a partner renews their mTLS client certificate, the new certificate must be registered in Kong (via the consumers API or deck sync) before the old certificate expires. There is no automatic cert-rotation mechanism in Kong OSS. Build the renewal workflow into your partner onboarding runbook and add a 60-day expiry alert.
Decision framework
The question is not whether Kong or Envoy is the “better” gateway — it is which tool best fits the specific enforcement point and the team operating it. In a regulated bank the decision looks like this:
| Enforcement point | Recommended tool | Rationale |
|---|---|---|
| External partner APIs (SAMA Open Banking, ISO 20022 connectors) | Kong Gateway | Consumer management, mTLS-cert-to-consumer mapping, per-consumer rate limits, and a developer portal are native. FAPI 2.0 OIDC plugin exists. |
| Internal east-west service-to-service traffic | Istio / Envoy sidecar | Automatic mTLS with workload identity (SPIFFE/SVID). No per-service configuration needed. Zero-trust posture for free. |
| Intra-cluster north-south (app services calling APIs within the same cluster) | Istio ingress gateway | Envoy-based; shares the control plane. Avoids a second technology for intra-cluster routing. |
| Migration path from IBM API Connect | Kong (dark-launch) | Closest semantic mapping to the IBM model. deck toolchain enables Git-controlled config comparable to the IBM apic CLI workflow. |
| Custom byte-level protocol manipulation | Envoy + Wasm filter | When you need to operate below the HTTP semantic layer (e.g. custom TLS extension negotiation, binary protocol inspection), Envoy’s filter chain is the right primitive. |
Neither tool eliminates the need for an API lifecycle process — catalogue, versioning, consumer onboarding, rate-limit contracts. Kong provides a lightweight version of that process out of the box. Envoy does not. If the teams consuming your APIs are internal and operate in the same Kubernetes cluster, the Istio-only model is clean and low overhead. If you have external partners, SAMA-mandated open banking endpoints, or a developer community, Kong’s consumer model is the differentiator, and the cost of running it alongside Istio is justified.