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.

Scope

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 & WASM plugins

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.

DimensionKong Gateway 3.xEnvoy / 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.

kong-mtls-service.yamlyaml
# 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.

kong-oidc-fapi2.yamlyaml
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
Vault references, not inline secrets

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).

kong-rate-limit.yamlyaml
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 to 10 × node_count requests 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: redis is set, Kong falls back to allowing all requests (fail-open) unless you configure fault_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.

  1. 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 gatewayscript or XSLT transforms — these require the most translation effort.

  2. Build the Kong declarative config skeleton

    Map each API to a Kong service and route in a kong.yaml file. Attach auth plugins first, rate-limit second, transform plugins last. Use deck validate to catch structural errors before any deployment.

  3. 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 mirror directive, HAProxy http-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.

  4. 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%.

  5. 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.

  6. 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.

Never cut over a payment API on a Friday

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-auth plugin. 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 make 3 × burst_limit requests 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.

prometheus-plugin.yamlyaml
# 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.

SIEM forwarding

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

DB-less and the Kong Manager UI

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.

Istio injects sidecars into Kong pods unless you opt out

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.

The sync_rate trade-off at low quotas

A 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.

Certificate rotation requires consumer update

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 pointRecommended toolRationale
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.