Cloud

Migrating from Kong OSS to Envoy Gateway: Complete Guide (2025 Business Model Change)

admin

Executive Summary

CRITICAL UPDATE: Kong Inc. fundamentally changed its business model with Kong Gateway 3.10 (March 2025), discontinuing prebuilt Docker images for Kong OSS and eliminating “free mode” for Kong Gateway Enterprise. Organizations running Kong OSS now face significant operational challenges:

  • No prebuilt Docker images for Kong OSS 3.10+ on Docker Hub
  • Free mode eliminated - running without a license behaves like an expired enterprise license
  • ⚠️ Security risks - stuck on 3.9.x or forced to build from source
  • 💸 Forced monetization - pushed toward paid Kong Enterprise or Konnect

This strategic shift has left thousands of organizations scrambling for alternatives. Envoy Gateway is the recommended migration path—a truly open-source, Kubernetes Gateway API-compliant API gateway backed by the CNCF with no vendor lock-in.

This comprehensive guide provides step-by-step migration strategies, Kong plugin translation patterns, and production-proven best practices for zero-downtime migration.

If you need expert assistance with your Kong to Envoy migration, our Envoy Gateway enterprise support team (1 of only 2 official partners worldwide) can help ensure a smooth, secure transition.


Table of Contents

  1. What Changed: Kong’s Business Model Shift
  2. Why Choose Envoy Gateway
  3. Pre-Migration Assessment
  4. Migration Strategy Options
  5. Step-by-Step Migration Guide
  6. Plugin Translation Reference
  7. Testing & Validation
  8. Rollback Strategy
  9. Post-Migration Optimization
  10. Common Migration Challenges
  11. Production Migration Checklist

What Changed: Kong’s Business Model Shift

Kong Inc. made several strategic changes with Kong Gateway 3.10 (released March 27, 2025) that fundamentally altered the open-source landscape:

1. Discontinued Prebuilt OSS Docker Images

Starting with 3.10, Kong stopped publishing prebuilt Docker images for Kong OSS on Docker Hub. Users must now:

  • Build Docker images from source (significant operational overhead)
  • Accept increased build times, storage costs, and CI/CD complexity
  • Manage their own image security scanning and patching

This change was not prominently announced and caught many organizations by surprise during routine upgrades.

2. Eliminated “Free Mode” for Kong Gateway Enterprise

Kong Gateway Enterprise previously offered a “free mode” that provided limited functionality without a license. Starting with 3.10:

  • No free mode - running without a license now behaves identically to an expired enterprise license
  • Severe functional limitations and degraded performance
  • Forces users toward paid Kong Enterprise or Kong Konnect

3. Security & Compliance Risks

Organizations stuck on Kong OSS 3.9.x face:

  • No security updates for newer vulnerabilities
  • Compliance violations for regulated industries requiring current software
  • Technical debt accumulation from delayed upgrades
  • Risk of supply chain attacks via outdated dependencies

4. Community Response

The Kong community reacted strongly:

  • Discussion on Kong Nation: “Is Opensource support for Kong ceased?”
  • Tetrate launched community-supported Kong OSS Docker images as a stopgap
  • Mass migration to alternatives: Apache APISIX, Traefik, Envoy Gateway

Why This Matters

Kong’s shift represents a classic “open-core squeeze” strategy seen across the industry (Elasticsearch, MongoDB, Redis, HashiCorp Terraform). For organizations requiring:

  • Vendor independence and avoidance of commercial lock-in
  • Predictable costs without surprise licensing changes
  • Community-driven development and transparent roadmaps
  • Cloud-native architecture with Kubernetes-native APIs

Envoy Gateway is the clear alternative, backed by the CNCF with no commercial entity controlling its direction.


Why Choose Envoy Gateway

Envoy Gateway represents the future of Kubernetes API gateways, built on proven cloud-native technologies with strong CNCF governance.

Comparison: Kong OSS vs. Envoy Gateway

FeatureKong OSS (3.9.x)Envoy Gateway
Business ModelOpen-core (abandoned by vendor)Fully open-source (CNCF)
Docker ImagesDiscontinued (3.10+)Official releases on every version
Gateway API CompliancePartial via Kong Ingress ControllerFull native support
Configuration ModelDatabase or declarative YAMLDynamic xDS API + Gateway API
Plugin Ecosystem50+ Kong plugins (many enterprise-only)Envoy filters + Gateway API policies
ObservabilityPrometheus, Datadog, StatsDRich metrics, distributed tracing (Jaeger, Zipkin), access logs
Multi-tenancyKong workspaces (enterprise)Gateway classes (native Kubernetes)
Service Mesh IntegrationKong Mesh (enterprise)Native integration (Istio, Consul, Linkerd)
Protocol SupportHTTP/1.1, HTTP/2, gRPC, WebSocketHTTP/1.1, HTTP/2, HTTP/3/QUIC, gRPC, WebSocket, TCP, UDP
Security ModelPlugin-based, mTLS supportPolicy-driven (RBAC, mTLS, external auth)
Vendor Lock-inKong Inc. dependenciesVendor-neutral CNCF project
Community SupportDeclining (focus on enterprise)Active, growing CNCF community
Enterprise SupportKong Inc. onlyMultiple providers (including Tasrie IT as official partner)

Gateway API Benefits

The Kubernetes Gateway API is the evolution of the Ingress API, offering:

  • Role-oriented design: Separate resources for infrastructure (Gateway) vs. application (HTTPRoute) teams
  • Stronger typing: Explicit, validated configuration with CRDs
  • Extended protocol support: TCP, UDP, gRPC, WebSockets, HTTP/3
  • Portable across implementations: Vendor-neutral specification
  • Expressive routing: Header-based, query parameter, method-based routing
  • Traffic splitting: Native canary, blue-green, A/B testing
  • Policy attachment: Security policies, rate limiting, CORS

Envoy Gateway is a reference implementation of Gateway API, making it the natural migration path for Kong users seeking a modern, vendor-neutral solution.

CNCF Governance

Unlike Kong OSS (controlled by Kong Inc.), Envoy Gateway benefits from:

  • Neutral governance under the Cloud Native Computing Foundation
  • Transparent roadmap driven by community needs
  • Multi-vendor collaboration (Google, Microsoft, Red Hat, solo.io, Tetrate)
  • Long-term sustainability with no single commercial entity controlling direction

Pre-Migration Assessment

Before starting migration, conduct a thorough assessment of your current Kong OSS deployment.

1. Inventory Your Kong Resources

# List all Kong services
kubectl get services -n kong

# List Kong ingress resources (if using Kong Ingress Controller)
kubectl get ingresses --all-namespaces

# List Kong plugins (CRDs if using KIC)
kubectl get kongplugins --all-namespaces
kubectl get kongclusterplugins

# List Kong consumers
kubectl get kongconsumers --all-namespaces

# Export Kong declarative configuration (if using DB-less mode)
kubectl exec -n kong deployment/kong -- kong config db_export /tmp/kong.yaml
kubectl cp kong/$(kubectl get pod -n kong -l app=kong -o jsonpath='{.items[0].metadata.name}'):/tmp/kong.yaml ./kong-backup.yaml

2. Document Current Architecture

Create a comprehensive inventory:

# kong-inventory.yaml
architecture:
  deployment_mode: "DB-less"  # or "Database-backed (PostgreSQL)"
  kong_version: "3.9.1"
  ingress_controller_version: "3.1.3"
  namespaces:
    - kong
    - production

services_count: 45
routes_count: 120

plugins:
  authentication:
    - name: "key-auth"
      routes: 30
    - name: "jwt"
      routes: 15
    - name: "oauth2"
      routes: 8

  traffic_control:
    - name: "rate-limiting"
      routes: 80
    - name: "request-size-limiting"
      routes: 40

  security:
    - name: "cors"
      routes: 50
    - name: "ip-restriction"
      routes: 12

  transformations:
    - name: "request-transformer"
      routes: 25
    - name: "response-transformer"
      routes: 18

consumers_count: 250
upstreams_count: 35

integrations:
  - Prometheus metrics
  - Datadog APM
  - External authentication service
  - PostgreSQL database (if applicable)

3. Identify Migration Complexity

Assess which features require special attention:

Low Complexity (direct translation):

  • Basic HTTP routing
  • Path-based routing
  • Host-based routing
  • TLS termination
  • CORS policies
  • Rate limiting (basic)

Medium Complexity (requires adaptation):

  • Advanced rate limiting (multiple dimensions)
  • Request/response transformations
  • Custom authentication flows
  • Service-level retries and timeouts
  • Circuit breaking

High Complexity (requires redesign):

  • Kong custom plugins (Lua-based)
  • Complex OAuth2 flows
  • Kong consumer management
  • Multi-database backends
  • Kong workspaces (enterprise multi-tenancy)

4. Review Dependencies

# Check Kubernetes version (Gateway API requires 1.25+)
kubectl version --short

# Verify Gateway API CRD availability
kubectl get crd gateways.gateway.networking.k8s.io

# Review current resource utilization
kubectl top pods -n kong
kubectl describe nodes | grep -A 5 "Allocated resources"

5. Backup Current Configuration

Critical: Always maintain backups before migration.

# Backup all Kong resources
kubectl get all -n kong -o yaml > kong-backup-$(date +%F).yaml

# Backup Kong custom resources
kubectl get kongplugins,kongclusterplugins,kongconsumers,kongingresses --all-namespaces -o yaml > kong-crds-backup-$(date +%F).yaml

# Backup Kong declarative config (if DB-less)
# Already covered above

# Backup PostgreSQL database (if database-backed)
kubectl exec -n kong deployment/postgresql -- pg_dump -U kong kong > kong-db-backup-$(date +%F).sql

Migration Strategy Options

Choose the migration strategy that best fits your risk tolerance and operational constraints.

Deploy Envoy Gateway alongside Kong, gradually shift traffic.

Pros:

  • Zero downtime - both systems run simultaneously
  • Easy rollback - instant traffic shift back to Kong
  • Gradual validation - test in production with real traffic
  • Team learning - operations team learns Envoy before full cutover

Cons:

  • Higher resource usage - both gateways consume cluster resources
  • Longer migration - gradual shift takes time
  • Complexity - managing two systems simultaneously

Best for: Production environments, risk-averse organizations, large-scale deployments.

Timeline: 2-4 weeks

Strategy 2: Blue-Green Deployment

Deploy Envoy in “green” environment, switch all traffic at once.

Pros:

  • Fast rollback - instant switch back to Kong (blue)
  • Complete validation - test entire green environment before cutover
  • Clean cutover - single DNS/load balancer change

Cons:

  • Resource intensive - requires full duplicate environment
  • All-or-nothing - no gradual validation with production traffic
  • Risk concentration - all traffic switches at once

Best for: Staging environments, smaller deployments, organizations with excess capacity.

Timeline: 1-2 weeks

Strategy 3: Canary Migration

Route small percentage of traffic to Envoy, gradually increase.

Pros:

  • Risk mitigation - limited blast radius for issues
  • Real-world testing - production traffic validation
  • Data-driven decisions - metrics guide traffic increase

Cons:

  • Complex routing - requires sophisticated traffic splitting
  • Potential inconsistency - users may hit different gateways
  • Longer migration - gradual ramp takes time

Best for: High-traffic environments, organizations with advanced observability, critical production systems.

Timeline: 3-6 weeks

Recommendation Matrix

ScenarioRecommended Strategy
Production, high availability requiredParallel Deployment
Staging or non-critical environmentsBlue-Green Deployment
High-traffic, mission-critical systemsCanary Migration
Small deployment, simple routingBlue-Green Deployment
Complex Kong configurationParallel Deployment
Limited cluster resourcesBlue-Green (in separate cluster)

Step-by-Step Migration Guide

This section provides a comprehensive, production-ready migration guide using the Parallel Deployment strategy.

Phase 1: Preparation (Week 1)

1.1 Install Gateway API CRDs

# Install Gateway API CRDs (v1.2.1 - latest as of Dec 2025)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml

# Verify installation
kubectl get crd gateways.gateway.networking.k8s.io
kubectl get crd httproutes.gateway.networking.k8s.io
kubectl get crd grpcroutes.gateway.networking.k8s.io

1.2 Install Envoy Gateway

# Install Envoy Gateway using Helm
helm repo add envoy-gateway https://gateway.envoyproxy.io
helm repo update

# Create namespace
kubectl create namespace envoy-gateway-system

# Install Envoy Gateway
helm install envoy-gateway envoy-gateway/gateway-helm \
  --namespace envoy-gateway-system \
  --set config.envoyGateway.gateway.controllerName=gateway.envoyproxy.io/gatewayclass-controller

# Verify installation
kubectl get pods -n envoy-gateway-system
kubectl get gatewayclass

Expected output:

NAME             CONTROLLER                                      ACCEPTED   AGE
envoy-gateway    gateway.envoyproxy.io/gatewayclass-controller   True       30s

1.3 Create Gateway Resource

# envoy-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: envoy-gateway
  namespace: envoy-gateway-system
spec:
  gatewayClassName: envoy-gateway
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: envoy-gateway-tls
        namespace: envoy-gateway-system
# Apply Gateway
kubectl apply -f envoy-gateway.yaml

# Verify Gateway status
kubectl get gateway -n envoy-gateway-system
kubectl describe gateway envoy-gateway -n envoy-gateway-system

1.4 Configure TLS Certificates

# If using cert-manager (recommended for automated certificate management)
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml

# Create Certificate resource
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: envoy-gateway-tls
  namespace: envoy-gateway-system
spec:
  secretName: envoy-gateway-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - api.yourdomain.com
  - "*.api.yourdomain.com"
EOF

Phase 2: Route Translation (Week 1-2)

2.1 Translate Simple HTTP Route

Kong Configuration (via Kong Ingress Controller):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-api
  namespace: production
  annotations:
    konghq.com/strip-path: "true"
spec:
  ingressClassName: kong
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /v1/users
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 8080

Envoy Gateway Equivalent (Gateway API HTTPRoute):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example-api-users
  namespace: production
spec:
  parentRefs:
  - name: envoy-gateway
    namespace: envoy-gateway-system
  hostnames:
  - "api.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /v1/users
    backendRefs:
    - name: user-service
      port: 8080
    filters:
    - type: URLRewrite
      urlRewrite:
        path:
          type: ReplacePrefixMatch
          replacePrefixMatch: /

2.2 Translate Route with Rate Limiting

Kong Configuration:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: rate-limit-users
  namespace: production
config:
  minute: 100
  hour: 5000
  policy: local
plugin: rate-limiting
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-api
  namespace: production
  annotations:
    konghq.com/plugins: rate-limit-users
spec:
  # ... ingress spec

Envoy Gateway Equivalent (using RateLimitPolicy):

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: rate-limit-users
  namespace: production
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: example-api-users
  rateLimit:
    type: Global
    global:
      rules:
      - clientSelectors:
        - headers:
          - name: x-user-id
            type: Distinct
        limit:
          requests: 100
          unit: Minute
      - limit:
          requests: 5000
          unit: Hour

2.3 Translate CORS Policy

Kong Configuration:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: cors-policy
  namespace: production
config:
  origins:
  - https://app.example.com
  - https://dashboard.example.com
  methods:
  - GET
  - POST
  - PUT
  - DELETE
  headers:
  - Authorization
  - Content-Type
  exposed_headers:
  - X-Request-ID
  credentials: true
  max_age: 3600
plugin: cors

Envoy Gateway Equivalent:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: cors-policy
  namespace: production
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: example-api-users
  cors:
    allowOrigins:
    - type: Exact
      value: "https://app.example.com"
    - type: Exact
      value: "https://dashboard.example.com"
    allowMethods:
    - GET
    - POST
    - PUT
    - DELETE
    allowHeaders:
    - Authorization
    - Content-Type
    exposeHeaders:
    - X-Request-ID
    allowCredentials: true
    maxAge: 3600s

Phase 3: Traffic Migration (Week 2-3)

3.1 Configure DNS for Gradual Migration

Option A: Weighted DNS (AWS Route 53 example)

# route53-weighted-routing.tf (using Terraform for infrastructure as code)
resource "aws_route53_record" "api_weighted_kong" {
  zone_id = aws_route53_zone.main.zone_id
  name    = "api.example.com"
  type    = "A"

  set_identifier = "kong-gateway"
  weighted_routing_policy {
    weight = 90  # Start with 90% to Kong
  }

  alias {
    name                   = data.kubernetes_service.kong_ingress.status.0.load_balancer.0.ingress.0.hostname
    zone_id               = var.aws_lb_zone_id
    evaluate_target_health = true
  }
}

resource "aws_route53_record" "api_weighted_envoy" {
  zone_id = aws_route53_zone.main.zone_id
  name    = "api.example.com"
  type    = "A"

  set_identifier = "envoy-gateway"
  weighted_routing_policy {
    weight = 10  # Start with 10% to Envoy
  }

  alias {
    name                   = data.kubernetes_service.envoy_gateway.status.0.load_balancer.0.ingress.0.hostname
    zone_id               = var.aws_lb_zone_id
    evaluate_target_health = true
  }
}

For organizations needing Terraform consulting to automate this infrastructure migration, our team specializes in declarative infrastructure for Gateway API resources.

Option B: Header-Based Routing (testing with specific users)

# Use Kong to route specific header traffic to Envoy
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: envoy-migration-routing
  namespace: production
config:
  config:
    - condition: "request.headers['X-Gateway-Test'] == 'envoy'"
      action:
        upstream_url: "http://envoy-gateway.envoy-gateway-system.svc.cluster.local"
plugin: request-transformer-advanced

3.2 Monitor Both Gateways

# prometheus-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: envoy-gateway-metrics
  namespace: envoy-gateway-system
spec:
  selector:
    matchLabels:
      app: envoy-gateway
  endpoints:
  - port: metrics
    interval: 30s
    path: /stats/prometheus

Key metrics to monitor during migration:

  • Request rate: Compare Kong vs. Envoy traffic volume
  • Latency (p50, p95, p99): Ensure Envoy matches or improves Kong performance
  • Error rate (4xx, 5xx): Watch for configuration issues
  • Resource usage: CPU, memory for both gateways

Prometheus queries for comparison:

# Request rate comparison
sum(rate(kong_http_requests_total[5m])) by (service)
sum(rate(envoy_cluster_upstream_rq_total[5m])) by (cluster_name)

# Latency comparison (p95)
histogram_quantile(0.95, sum(rate(kong_latency_bucket[5m])) by (le))
histogram_quantile(0.95, sum(rate(envoy_cluster_upstream_rq_time_bucket[5m])) by (le))

# Error rate
sum(rate(kong_http_requests_total{code=~"5.."}[5m])) / sum(rate(kong_http_requests_total[5m]))
sum(rate(envoy_cluster_upstream_rq_xx{envoy_response_code_class="5"}[5m])) / sum(rate(envoy_cluster_upstream_rq_total[5m]))

For organizations using Prometheus support for monitoring and alerting, our team can help set up comprehensive gateway migration observability.

3.3 Gradual Traffic Shift Schedule

Week 1: 10% Envoy

# Update Route 53 weights
terraform apply -var="kong_weight=90" -var="envoy_weight=10"
  • Monitor for 48 hours
  • Validate error rates < baseline
  • Check latency p95 < Kong baseline + 10%

Week 2: 25% Envoy

terraform apply -var="kong_weight=75" -var="envoy_weight=25"
  • Monitor for 48 hours
  • Run load tests at 25% production traffic
  • Verify resource scaling

Week 2: 50% Envoy

terraform apply -var="kong_weight=50" -var="envoy_weight=50"
  • Monitor for 72 hours
  • Business hours + weekend traffic validation
  • Perform chaos testing (Kubernetes pod failures)

Week 3: 75% Envoy

terraform apply -var="kong_weight=25" -var="envoy_weight=75"
  • Monitor for 48 hours
  • Final pre-cutover validation

Week 3: 100% Envoy

terraform apply -var="kong_weight=0" -var="envoy_weight=100"
  • Monitor for 1 week before decommissioning Kong
  • Keep Kong running in standby for emergency rollback

Phase 4: Monitoring & Validation (Week 3-4)

4.1 Functional Testing

# Test basic HTTP routing
curl -H "Host: api.example.com" http://envoy-gateway-lb.example.com/v1/users

# Test HTTPS with TLS
curl https://api.example.com/v1/users

# Test rate limiting
for i in {1..150}; do
  curl -H "X-User-ID: test-user" https://api.example.com/v1/users
done
# Expect HTTP 429 after 100 requests

# Test CORS preflight
curl -X OPTIONS -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: POST" \
  https://api.example.com/v1/users

4.2 Load Testing

# k6-load-test.js (using k6 for load testing)
import http from 'k6/http';
import { check, sleep } from 'k6';

export let options = {
  stages: [
    { duration: '2m', target: 100 },  // Ramp up to 100 users
    { duration: '5m', target: 100 },  // Stay at 100 users
    { duration: '2m', target: 200 },  // Ramp up to 200 users
    { duration: '5m', target: 200 },  // Stay at 200 users
    { duration: '2m', target: 0 },    // Ramp down to 0 users
  ],
  thresholds: {
    'http_req_duration': ['p(95)<500'],  // 95% of requests under 500ms
    'http_req_failed': ['rate<0.01'],    // Error rate < 1%
  },
};

export default function () {
  let response = http.get('https://api.example.com/v1/users');

  check(response, {
    'status is 200': (r) => r.status === 200,
    'response time < 500ms': (r) => r.timings.duration < 500,
  });

  sleep(1);
}
# Run load test
k6 run --vus 100 --duration 10m k6-load-test.js

4.3 Distributed Tracing

Enable Jaeger tracing for end-to-end request visibility:

# envoy-gateway-tracing.yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ProxyConfig
metadata:
  name: tracing-config
  namespace: envoy-gateway-system
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: Gateway
    name: envoy-gateway
  telemetry:
    tracing:
      provider:
        type: OpenTelemetry
        openTelemetry:
          host: jaeger-collector.observability.svc.cluster.local
          port: 4317
      customTags:
        environment:
          literal:
            value: production
        gateway:
          literal:
            value: envoy-gateway

Plugin Translation Reference

This section provides detailed translation patterns for common Kong plugins to Envoy Gateway equivalents.

Authentication & Authorization

Kong: Key Authentication

Kong Plugin:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: key-auth
config:
  key_names:
  - apikey
  - x-api-key
  hide_credentials: true
plugin: key-auth

Envoy Gateway Equivalent:

# Use external authentication with a custom auth service
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: api-key-auth
  namespace: production
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: example-api-users
  extAuth:
    grpc:
      backendRef:
        name: api-key-auth-service
        port: 9001

Auth Service (example implementation):

# Deploy a custom auth service that validates API keys
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-key-auth-service
  namespace: production
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api-key-auth
  template:
    metadata:
      labels:
        app: api-key-auth
    spec:
      containers:
      - name: auth-service
        image: your-registry/api-key-auth:v1.0.0
        ports:
        - containerPort: 9001
        env:
        - name: REDIS_URL
          value: redis://redis.production.svc.cluster.local:6379

Kong: JWT Authentication

Kong Plugin:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: jwt-auth
config:
  uri_param_names:
  - jwt
  cookie_names:
  - jwt_token
  claims_to_verify:
  - exp
  - nbf
plugin: jwt

Envoy Gateway Equivalent:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: jwt-auth
  namespace: production
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: example-api-users
  jwt:
    providers:
    - name: auth0-provider
      issuer: https://your-tenant.auth0.com/
      audiences:
      - https://api.example.com
      remoteJWKS:
        uri: https://your-tenant.auth0.com/.well-known/jwks.json
      claimToHeaders:
      - claim: sub
        header: x-user-id
      - claim: email
        header: x-user-email

Traffic Control

Kong: Rate Limiting (Advanced)

Kong Plugin:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: advanced-rate-limit
config:
  limit:
  - 100
  - 5000
  window_size:
  - 60
  - 3600
  identifier: consumer
  sync_rate: 10
plugin: rate-limiting-advanced

Envoy Gateway Equivalent:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: advanced-rate-limit
  namespace: production
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: example-api-users
  rateLimit:
    type: Global
    global:
      rules:
      # 100 requests per minute per user
      - clientSelectors:
        - headers:
          - name: x-user-id
            type: Distinct
        limit:
          requests: 100
          unit: Minute
      # 5000 requests per hour per user
      - clientSelectors:
        - headers:
          - name: x-user-id
            type: Distinct
        limit:
          requests: 5000
          unit: Hour

Kong: Request Size Limiting

Kong Plugin:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: request-size-limit
config:
  allowed_payload_size: 10
  size_unit: megabytes
  require_content_length: true
plugin: request-size-limiting

Envoy Gateway Equivalent:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: request-size-limit
  namespace: production
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: example-api-users
  clientIPDetection:
    xForwardedFor:
      numTrustedHops: 1
  # Note: Request size limiting in Envoy Gateway is configured via Envoy filters
  # Requires custom EnvoyPatchPolicy for max_request_bytes
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
metadata:
  name: request-size-limit-patch
  namespace: production
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: example-api-users
  type: JSONPatch
  jsonPatches:
  - type: "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
    name: "envoy.filters.network.http_connection_manager"
    operation:
      op: add
      path: "/route_config/virtual_hosts/0/routes/0/route/max_stream_duration"
      value:
        max_stream_duration: 0s
        grpc_timeout_header_max: 0s
  - type: "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
    name: "envoy.filters.network.http_connection_manager"
    operation:
      op: add
      path: "/common_http_protocol_options"
      value:
        max_request_headers_kb: 60

Simpler approach: Use a Lua filter or external processing for request size validation.

Transformations

Kong: Request Transformer

Kong Plugin:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: request-transformer
config:
  add:
    headers:
    - "X-Gateway: Kong"
    - "X-Request-ID: $(uuid)"
    querystring:
    - "client_id: mobile-app"
  remove:
    headers:
    - "X-Internal-Secret"
  replace:
    headers:
    - "User-Agent: Kong-Gateway"
plugin: request-transformer

Envoy Gateway Equivalent:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example-api-users
  namespace: production
spec:
  parentRefs:
  - name: envoy-gateway
    namespace: envoy-gateway-system
  hostnames:
  - "api.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /v1/users
    filters:
    # Add headers
    - type: RequestHeaderModifier
      requestHeaderModifier:
        add:
        - name: X-Gateway
          value: Envoy-Gateway
        - name: X-Request-ID
          value: "%REQ_ID%"  # Envoy variable for request ID
        remove:
        - X-Internal-Secret
        set:
        - name: User-Agent
          value: Envoy-Gateway
    backendRefs:
    - name: user-service
      port: 8080

Note: For query string manipulation, Envoy Gateway requires custom Lua filters or external processing.

Kong: Response Transformer

Kong Plugin:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: response-transformer
config:
  add:
    headers:
    - "X-Response-Time: $(latency)"
    - "X-Served-By: Kong"
  remove:
    headers:
    - "X-Internal-Version"
plugin: response-transformer

Envoy Gateway Equivalent:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example-api-users
  namespace: production
spec:
  parentRefs:
  - name: envoy-gateway
    namespace: envoy-gateway-system
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /v1/users
    filters:
    - type: ResponseHeaderModifier
      responseHeaderModifier:
        add:
        - name: X-Served-By
          value: Envoy-Gateway
        remove:
        - X-Internal-Version
    backendRefs:
    - name: user-service
      port: 8080

Note: Envoy Gateway doesn’t support dynamic response headers like $(latency) directly. Use observability backends (Prometheus, Jaeger) for latency tracking.

Reliability

Kong: Circuit Breaker (Upstream Healthcheck)

Kong Configuration:

apiVersion: configuration.konghq.com/v1
kind: KongUpstreamPolicy
metadata:
  name: user-service-upstream
config:
  healthchecks:
    active:
      healthy:
        interval: 10
        successes: 2
      unhealthy:
        interval: 5
        http_failures: 3
        tcp_failures: 3

Envoy Gateway Equivalent:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: circuit-breaker-policy
  namespace: production
spec:
  targetRef:
    group: ""
    kind: Service
    name: user-service
  circuitBreaker:
    maxConnections: 1024
    maxPendingRequests: 1024
    maxRequests: 1024
    maxRetries: 3
  healthCheck:
    active:
      type: HTTP
      http:
        path: /health
        expectedStatuses:
        - 200
        - 204
      timeout: 1s
      interval: 10s
      unhealthyThreshold: 3
      healthyThreshold: 2

Kong: Retries

Kong Configuration:

apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
  name: retry-config
route:
  retries: 5

Envoy Gateway Equivalent:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: retry-policy
  namespace: production
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: example-api-users
  retry:
    numRetries: 5
    perRetry:
      timeout: 2s
      backOff:
        baseInterval: 100ms
        maxInterval: 10s
    retryOn:
      httpStatusCodes:
      - 502
      - 503
      - 504
      triggers:
      - connect-failure
      - refused-stream

Testing & Validation

Functional Testing

Create a comprehensive test suite covering all migrated routes:

#!/bin/bash
# test-envoy-migration.sh

set -e

GATEWAY_URL="https://api.example.com"
FAILED_TESTS=0

# Test 1: Basic routing
echo "Test 1: Basic HTTP GET routing..."
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" ${GATEWAY_URL}/v1/users)
if [ "$RESPONSE" -eq 200 ]; then
  echo "✅ PASSED"
else
  echo "❌ FAILED (got $RESPONSE)"
  FAILED_TESTS=$((FAILED_TESTS+1))
fi

# Test 2: CORS preflight
echo "Test 2: CORS preflight request..."
RESPONSE=$(curl -s -X OPTIONS \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: POST" \
  -o /dev/null -w "%{http_code}" \
  ${GATEWAY_URL}/v1/users)
if [ "$RESPONSE" -eq 200 ]; then
  echo "✅ PASSED"
else
  echo "❌ FAILED (got $RESPONSE)"
  FAILED_TESTS=$((FAILED_TESTS+1))
fi

# Test 3: Rate limiting
echo "Test 3: Rate limiting enforcement..."
for i in {1..110}; do
  RESPONSE=$(curl -s -H "X-User-ID: test-user" \
    -o /dev/null -w "%{http_code}" \
    ${GATEWAY_URL}/v1/users)
done
if [ "$RESPONSE" -eq 429 ]; then
  echo "✅ PASSED (rate limit triggered)"
else
  echo "❌ FAILED (expected 429, got $RESPONSE)"
  FAILED_TESTS=$((FAILED_TESTS+1))
fi

# Test 4: Authentication
echo "Test 4: JWT authentication..."
RESPONSE=$(curl -s -H "Authorization: Bearer ${TEST_JWT_TOKEN}" \
  -o /dev/null -w "%{http_code}" \
  ${GATEWAY_URL}/v1/users/me)
if [ "$RESPONSE" -eq 200 ]; then
  echo "✅ PASSED"
else
  echo "❌ FAILED (got $RESPONSE)"
  FAILED_TESTS=$((FAILED_TESTS+1))
fi

# Test 5: TLS termination
echo "Test 5: HTTPS/TLS termination..."
RESPONSE=$(curl -s -v https://api.example.com/v1/users 2>&1 | grep "SSL connection")
if [ -n "$RESPONSE" ]; then
  echo "✅ PASSED"
else
  echo "❌ FAILED"
  FAILED_TESTS=$((FAILED_TESTS+1))
fi

echo ""
echo "========================================="
if [ $FAILED_TESTS -eq 0 ]; then
  echo "✅ All tests passed!"
  exit 0
else
  echo "❌ $FAILED_TESTS test(s) failed"
  exit 1
fi

Performance Testing

# k6-performance-comparison.js
import http from 'k6/http';
import { check, group } from 'k6';
import { Rate, Trend } from 'k6/metrics';

let errorRate = new Rate('errors');
let latencyTrend = new Trend('latency');

export let options = {
  scenarios: {
    baseline_load: {
      executor: 'constant-vus',
      vus: 50,
      duration: '5m',
    },
    spike_test: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '1m', target: 100 },
        { duration: '3m', target: 500 },
        { duration: '1m', target: 0 },
      ],
      startTime: '6m',
    },
  },
  thresholds: {
    'http_req_duration': ['p(95)<500', 'p(99)<1000'],
    'errors': ['rate<0.01'],
  },
};

export default function () {
  group('API Endpoints', function () {
    let res = http.get('https://api.example.com/v1/users');

    check(res, {
      'status is 200': (r) => r.status === 200,
      'response time < 500ms': (r) => r.timings.duration < 500,
    }) || errorRate.add(1);

    latencyTrend.add(res.timings.duration);
  });
}

Chaos Engineering

Use Chaos Mesh to validate resilience:

# chaos-pod-failure.yaml
apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
  name: envoy-gateway-pod-kill
  namespace: chaos-testing
spec:
  action: pod-kill
  mode: one
  selector:
    namespaces:
    - envoy-gateway-system
    labelSelectors:
      app: envoy-gateway
  scheduler:
    cron: "@every 5m"

Run chaos tests and verify:

  • Gateway recovers within SLA (e.g., < 30s)
  • No request failures during pod restart
  • Metrics return to baseline after recovery

Rollback Strategy

Always maintain an emergency rollback plan.

Immediate Rollback (DNS-based)

# Shift 100% traffic back to Kong
terraform apply -var="kong_weight=100" -var="envoy_weight=0"

Rollback time: 5-10 minutes (DNS TTL dependent)

Application-Level Rollback

If using header-based routing:

# Remove X-Gateway-Test header routing
kubectl delete kongplugin envoy-migration-routing -n production

Rollback time: < 1 minute

Gateway Resource Rollback

# Disable Envoy Gateway routes
kubectl delete httproute --all -n production

# Traffic automatically falls back to Kong Ingress

Rollback time: < 2 minutes

Rollback Decision Criteria

Trigger rollback if:

  • Error rate > 1% sustained for > 5 minutes
  • Latency p95 > 2x baseline sustained for > 10 minutes
  • Availability < 99.9% in any 15-minute window
  • Critical business functionality fails (payments, authentication, etc.)

Post-Migration Optimization

After successful migration, optimize Envoy Gateway for production performance.

1. Resource Tuning

# Adjust Envoy Proxy resource limits based on observed usage
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: production-proxy-config
  namespace: envoy-gateway-system
spec:
  provider:
    type: Kubernetes
    kubernetes:
      envoyDeployment:
        replicas: 3
        pod:
          resources:
            limits:
              cpu: "2000m"
              memory: "2Gi"
            requests:
              cpu: "1000m"
              memory: "1Gi"
          autoscaling:
            minReplicas: 3
            maxReplicas: 10
            metrics:
            - type: Resource
              resource:
                name: cpu
                target:
                  type: Utilization
                  averageUtilization: 70

2. Connection Pooling

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: connection-pool-optimization
  namespace: production
spec:
  targetRef:
    group: ""
    kind: Service
    name: user-service
  loadBalancer:
    type: RoundRobin
  proxyProtocol:
    version: V1
  tcpKeepalive:
    idleTime: 7200s
    interval: 75s
    probes: 9

3. Caching (if applicable)

For read-heavy APIs, consider implementing response caching:

# Note: Envoy Gateway doesn't have built-in HTTP caching yet
# Use a caching layer like Varnish or CDN (CloudFront, Cloudflare)
# Or implement application-level caching

4. Decommission Kong

After 1-2 weeks of stable Envoy operation:

# Scale down Kong deployment
kubectl scale deployment kong -n kong --replicas=0

# Wait 1 week for final validation

# Remove Kong resources
kubectl delete namespace kong

# Remove Kong CRDs
kubectl delete crd kongplugins.configuration.konghq.com
kubectl delete crd kongclusterplugins.configuration.konghq.com
kubectl delete crd kongconsumers.configuration.konghq.com
kubectl delete crd kongingresses.configuration.konghq.com

# Remove DNS records
terraform destroy -target=aws_route53_record.api_weighted_kong

Common Migration Challenges

Challenge 1: Kong Custom Plugins (Lua)

Problem: Custom Lua plugins have no direct Envoy equivalent.

Solution:

  1. Rewrite as Envoy Wasm filter (Rust, C++, Go)
  2. Use External Processing API (gRPC service for custom logic)
  3. Move logic to application layer (sidecar, service code)

Example: External Processing for custom authentication

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
  name: custom-auth-processor
  namespace: production
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: example-api-users
  extProc:
  - backendRefs:
    - name: custom-auth-service
      port: 9002
    processingMode:
      requestHeaderMode: SEND
      responseHeaderMode: SKIP

Challenge 2: Kong Consumer Management

Problem: Kong consumers (API key/JWT credential storage) don’t map to Envoy.

Solution:

  1. Migrate to external IdP (Keycloak, Auth0, Okta)
  2. Use Kubernetes Secrets for API keys with external auth service
  3. Implement custom credential service (Redis-backed auth)
# Example: Migrate Kong consumers to Keycloak
# 1. Export Kong consumers
# 2. Import to Keycloak as users/clients
# 3. Configure Envoy Gateway JWT auth with Keycloak JWKS

Challenge 3: Database-Backed Kong Configuration

Problem: Kong using PostgreSQL for config; Envoy Gateway is declarative only.

Solution:

  1. Export Kong config to declarative YAML (deck dump)
  2. Translate to Gateway API resources (HTTPRoute, SecurityPolicy, etc.)
  3. Store in Git for GitOps with ArgoCD/Flux
# Export Kong config
deck dump --output-file kong-config.yaml

# Use translation scripts or manual conversion
# Store in Git repository
git add manifests/envoy-gateway/
git commit -m "Migrate Kong routes to Envoy Gateway"
git push

Challenge 4: Multi-Workspace Kong (Enterprise)

Problem: Kong workspaces provide multi-tenancy; Envoy Gateway uses Kubernetes namespaces.

Solution:

  1. Map Kong workspaces → Kubernetes namespaces
  2. Use Gateway API ReferenceGrant for cross-namespace routing
  3. Implement RBAC for namespace isolation
# ReferenceGrant for cross-namespace backend access
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-production-to-shared-services
  namespace: shared-services
spec:
  from:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespace: production
  to:
  - group: ""
    kind: Service

Challenge 5: Kong Admin API Usage

Problem: Automation scripts using Kong Admin API need replacement.

Solution:

  1. Use kubectl for Gateway API resources (declarative YAML)
  2. Implement GitOps (ArgoCD, Flux) for automated deployments
  3. Use Kubernetes API directly for programmatic access

For organizations needing CI/CD consulting to automate Gateway API deployments, our team specializes in GitOps workflows for Kubernetes infrastructure.


Production Migration Checklist

Use this checklist to ensure a complete, safe migration:

Pre-Migration

  • Inventory complete: All Kong routes, plugins, consumers documented
  • Gateway API CRDs installed (v1.2.1+)
  • Envoy Gateway installed and verified
  • TLS certificates migrated to Kubernetes Secrets
  • Monitoring configured: Prometheus, Grafana dashboards
  • Distributed tracing enabled: Jaeger/Zipkin
  • Backup created: Kong config, database (if applicable)
  • Test environment validated: Successful migration in staging
  • Rollback plan documented and tested
  • Stakeholders notified: Teams aware of migration schedule

During Migration

  • HTTPRoutes created for all Kong routes
  • SecurityPolicies applied: CORS, authentication, authorization
  • BackendTrafficPolicies configured: Rate limiting, retries, circuit breakers
  • DNS configured for gradual traffic shift
  • Monitoring dashboards active: Kong vs. Envoy comparison
  • Alert rules updated: Envoy-specific alerts configured
  • Load testing completed: Performance validated at each traffic percentage
  • Functional testing passed: All critical user journeys validated
  • Chaos testing performed: Pod failures, network partitions tested
  • Runbook updated: Troubleshooting steps for Envoy Gateway

Post-Migration

  • 100% traffic on Envoy: Kong fully deprecated
  • Performance validated: Latency, throughput meet SLAs
  • Error rates normal: < baseline for 1 week
  • Resource usage optimized: HPA configured, limits tuned
  • Documentation updated: Architecture diagrams, runbooks
  • Team training completed: Operations team comfortable with Envoy
  • Kong decommissioned: Resources deleted (after 2-week stabilization)
  • Cost analysis: Resource usage, licensing costs compared
  • Lessons learned: Post-mortem completed, improvements documented
  • Celebration: Team recognized for successful migration! 🎉

Migration Timeline Example

Small Deployment (< 50 routes)

  • Week 1: Assessment, planning, Envoy Gateway installation
  • Week 2: Route translation, testing in staging
  • Week 3: Production migration (gradual traffic shift)
  • Week 4: Monitoring, optimization, Kong decommissioning

Total: 4 weeks

Medium Deployment (50-200 routes)

  • Weeks 1-2: Assessment, inventory, planning
  • Weeks 3-4: Envoy Gateway installation, route translation
  • Weeks 5-7: Staging validation, production migration
  • Week 8: Monitoring, optimization, Kong decommissioning

Total: 8 weeks

Large Deployment (200+ routes, complex plugins)

  • Weeks 1-3: Comprehensive assessment, custom plugin analysis
  • Weeks 4-6: Envoy Gateway setup, route translation, custom filter development
  • Weeks 7-10: Staging validation, gradual production migration (10% increments)
  • Weeks 11-12: Monitoring, optimization, Kong decommissioning

Total: 12 weeks


Need Expert Help with Your Kong to Envoy Migration?

Migrating from Kong OSS to Envoy Gateway is a critical project that requires deep expertise in Kubernetes networking, Gateway API, and production migration strategies. Mistakes can lead to downtime, security vulnerabilities, or performance degradation.

Tasrie IT is 1 of only 2 official Envoy Gateway enterprise support partners worldwide, recognized by the Envoy Gateway project. Our team has successfully migrated hundreds of production API gateways with zero downtime.

Our Migration Services Include:

Pre-migration assessment - Comprehensive inventory, complexity analysis, timeline estimation ✅ Custom plugin translation - Lua → Wasm filters, external processing services ✅ Zero-downtime migration execution - Gradual traffic shift with 24/7 monitoring ✅ Performance optimization - Load testing, resource tuning, autoscaling configuration ✅ 24/7 post-migration support - Incident response, troubleshooting, optimization ✅ Team training - Hands-on workshops for operations and development teams

Whether you’re managing a simple Kong deployment or a complex multi-cluster, multi-tenant architecture, we can help ensure a smooth, successful migration to Envoy Gateway.

Additional Services

Schedule a free 30-minute consultation to discuss your Kong to Envoy migration strategy, or contact our team for a detailed migration assessment.

Don’t let Kong’s business model change disrupt your operations. Migrate to Envoy Gateway with confidence.

Related Articles

Continue exploring these related topics

Chat with real humans