Skip to content
Published on

The Death and Resurrection of Kubernetes Networking: 5 Changes You Must Know Before March 2026

Authors
  • Name
    Twitter

1. Introduction: Your Cluster Is in Danger

In March 2026, one of the most widely used infrastructure components in the Kubernetes ecosystem officially reaches the end of its life. This is the EOL (End of Life) of the Ingress NGINX Controller (kubernetes/ingress-nginx).

This is not a simple version upgrade or minor change. Approximately 41-50% of internet-connected Kubernetes clusters use Ingress NGINX, and it ships as the default ingress controller on major platforms including RKE2, IBM Cloud, and Alibaba ACK. The fact that this controller will no longer receive security patches, bug fixes, or any releases means that hundreds of thousands of production clusters will be left unprotected.

"In March 2026, Kubernetes will retire Ingress NGINX, a piece of critical infrastructure for about half of cloud native environments... Half of you will be affected. You have two months left to prepare... We cannot overstate the severity of this situation or the importance of beginning migration..."

-- Kat Cosgrove, CNCF Ambassador & DevRel Engineer

This article analyzes the essence of this transition from 5 key perspectives:

  1. The Countdown of a Time Bomb -- The official retirement of Ingress NGINX and its aftermath
  2. Escaping the Annotation Swamp -- Structural flaws and Gateway API's solution
  3. Separation of Roles -- Peaceful coexistence of infrastructure administrators and developers
  4. Breaking Vendor Lock-in -- Achieving portability
  5. The Performance Leap -- Full-scale adoption of HTTP/3 and QUIC
  ┌─────────────────────────────────────────────────────────────────┐
2026 Kubernetes Networking Transition Roadmap  ├──────────┬──────────┬──────────┬──────────┬──────────┬──────────┤
2025.032025.112026.032026.062026.112027+  │          │          │          │          │          │          │
IngressOfficial │ ■ EOL ■  │ GatewayAKS/GKEIngressNightmare│ RetireSecurityAPI v1.5ExtendedAPICVEAnnouncePatches   (Est.)SupportResidual│
  │          │          │ End      │          │ EndsLowGW APIGW API   │          │          │          │          │
  │ v1.2     │ v1.4 GA  │          │          │          │          │
  └──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘
         ▲                    ▲                    ▲
         │                    │                    │
    CVE-2025-1974        Community Support    Cloud Vendor
    CVSS 9.8             Fully Ends          Extended Support Ends

2. [Takeaway 1] The Countdown of a Time Bomb: The Official Retirement of Ingress NGINX

2.1 What Is Being Retired: Precise Scope Definition

To prevent confusion, let's clarify something. What is being retired is the kubernetes/ingress-nginx controller project. The GA (General Availability) Ingress API itself (networking.k8s.io/v1) is still supported in Kubernetes. However, since the most popular implementation that actually runs the Ingress API is disappearing, the practical impact is enormous.

  ┌─────────────────────────────────────────────────────────┐
Retirement Scope Clarification  │                                                         │
  │  ✗ Retiring:   kubernetes/ingress-nginx controller      │
                 (Community-maintained project)  │                                                         │
  │  ✓ Continuing: Ingress API (networking.k8s.io/v1)F5 NGINX Ingress Controller (Commercial)Other third-party Ingress implementations  │
  │                                                         │
  │  ★ New Standard: Gateway API (gateway.networking.k8s.io)  └─────────────────────────────────────────────────────────┘

2.2 Why Now: Accumulation of Structural Problems

The retirement of the Ingress NGINX project is not a sudden decision. It is the result of structural problems that have accumulated over years reaching a critical point:

1) Maintainer Exhaustion

The project has long relied on just one or two volunteers. Having critical infrastructure that affects half of internet-connected clusters depend on individuals' spare time is not a sustainable model.

"For a long time, we've considered big companies or end user companies that rely on open source not contributing back to be a moral issue. But now, I think it's very easy to make the argument that not contributing back to open source is, in fact, a security issue. You have to start considering open source contributions as part of your security plan."

-- Kat Cosgrove

2) Unmanageable Technical Debt

Features once praised for their flexibility, particularly the ability to inject arbitrary NGINX configuration through snippets annotations, are now recognized as unmanageable security vulnerabilities. This issue will be discussed in more detail later.

3) IngressNightmare: The Impact of CVE-2025-1974

CVE-2025-1974, discovered in March 2025, dramatically exposed the structural vulnerability of Ingress NGINX.

2.3 IngressNightmare: The Worst Kubernetes Vulnerability Ever

CVE-2025-1974 is not a single vulnerability but an attack chain composed of 5 chained vulnerabilities (CVE-2025-1097, CVE-2025-1098, CVE-2025-24513, CVE-2025-24514, CVE-2025-1974).

CVE IDCVSSDescription
CVE-2025-245148.8Configuration injection via auth-url annotation
CVE-2025-10978.8Configuration injection via auth-tls-match-cn annotation
CVE-2025-10988.8Configuration injection via mirror-target/mirror-host annotations
CVE-2025-245134.8Lack of auth-url file path validation
CVE-2025-19749.8Unauthenticated Remote Code Execution (Unauthenticated RCE)

Attack Scenario:

  Attacker (with Pod network access)
  ┌──────────────────────────┐
Admission Webhook       │  ← Accessible without authentication
    (port 8443)  └──────────┬───────────────┘
Send malicious Ingress object
  ┌──────────────────────────┐
NGINX Config Injection  │  ← Inject arbitrary NGINX directives
    (Leveraging CVE-2025-1097/1098/24514)  └──────────┬───────────────┘
Achieve RCE via crafted config
  ┌──────────────────────────┐
Controller Pod Takeover │  ← CVE-2025-1974
    (CVSS 9.8)  └──────────┬───────────────┘
Steal ServiceAccount token
  ┌──────────────────────────┐
Access All Cluster      │  ← Can view Secrets from
Secrets & Cluster       │     all namespaces
Takeover  └──────────────────────────┘

According to Wiz Research, approximately 43% of cloud environments were exposed to this vulnerability, and more than 6,500 clusters, including Fortune 500 companies, had vulnerable Admission Controllers exposed to the public internet.

The key lesson from this incident is clear: the architecture of annotation-based configuration injection itself is a fundamental security threat.

2.4 EOL Timeline and Platform-Specific Impact

TimeframeEventImpact
March 2025IngressNightmare (CVE-2025-1974) disclosedEmergency patches released (v1.12.1, v1.11.5)
November 2025Official Ingress NGINX retirement announcedCommunity migration advisory begins
March 2026Community support fully endsAll security patches, bug fixes, releases cease
November 2026AKS Application Routing extended support endsAzure managed environments also lose support
After November 2026All official/extended support endsFully self-managed responsibility

"Best-effort maintenance will continue until March 2026. Afterward, there will be no further releases, no bugfixes, and no updates to resolve any security vulnerabilities that may be discovered."

-- Tabitha Sable, Kubernetes Security Response Committee

Cloud Vendor Response Status:

Cloud VendorResponse StrategyExtended SupportRecommended Alternative
Azure (AKS)ingress-nginx support within Application Routing Add-onUntil November 2026 (security patches only)Gateway API + NGINX Gateway Fabric
GCP (GKE)GKE Gateway Controller providedRecommends transition to vendor's own implementationGKE Gateway Controller
AWS (EKS)AWS Load Balancer ControllerAlready separated to own implementationAWS Gateway API Controller
Self-HostedDirect migration requiredNone (ends March 2026)NGINX Gateway Fabric, Envoy Gateway, etc.

For organizations running self-hosted environments, the situation is most urgent. No official patches will be provided for any security vulnerabilities discovered after March 2026.


3. [Takeaway 2] Escaping the Annotation Swamp

3.1 Structural Flaws of Annotation-Based Configuration

The most fundamental limitation of the Ingress API is lack of expressiveness. The Ingress resource spec only supports the most basic features: host-based routing and path-based routing. As a result, virtually all advanced features needed in practice rely on annotations -- an unstructured mechanism.

Analyzing the fundamental problems of annotations reveals the following:

1) Absence of Type Safety

Annotations are simple key: value string pairs. Without schema validation, typos, incorrect value formats, and wrong key names are not discovered until deployment time.

# Can you spot the typos?
metadata:
  annotations:
    # Typo: "rewrite-target" → "rewrite-traget"
    nginx.ingress.kubernetes.io/rewrite-traget: /$2
    # Type error: should be a number but string passed
    nginx.ingress.kubernetes.io/proxy-read-timeout: 'sixhundred'
    # Wrong prefix: "nginx.ingress.kubernetes.io" → "nginx.kubernetes.io"
    nginx.kubernetes.io/ssl-redirect: 'true'

All three of the above are applied without any errors during kubectl apply. Problems only manifest as unexpected behavior at runtime, and debugging can take hours.

2) Vendor Lock-in Amplification

Each Ingress Controller uses its own annotation namespace:

# ingress-nginx specific
nginx.ingress.kubernetes.io/canary: 'true'
nginx.ingress.kubernetes.io/canary-weight: '20'

# Traefik specific
traefik.ingress.kubernetes.io/router.middlewares: default-rate-limit@kubernetescrd

# HAProxy specific
haproxy.org/rate-limit-requests: '100'

# AWS ALB specific
alb.ingress.kubernetes.io/target-type: ip

While implementing the same functionality (canary deployments, rate limiting, etc.), completely different annotation syntax is used. When migrating from one controller to another, all annotations must be manually converted.

3) Impossibility of Audit and Governance

Annotations are listed flat in the Ingress resource metadata. Identifying security-sensitive settings in an Ingress object with dozens of annotations is virtually impossible. Restricting specific annotations via RBAC is also impossible -- if you can write annotations, you can write all annotations.

3.2 The snippets Annotation: A Vulnerability by Design

The extreme case of the annotation problem is nginx.ingress.kubernetes.io/configuration-snippet and nginx.ingress.kubernetes.io/server-snippet. These annotations allow direct injection of arbitrary NGINX configuration directives.

# Dangerous: Allows injection of arbitrary NGINX configuration
metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      # Intended normal use: add custom headers
      more_set_headers "X-Custom-Header: value";

      # Malicious use: exfiltrate server information
      # proxy_pass http://internal-service.kube-system.svc.cluster.local;

      # Malicious use: bypass authentication
      # satisfy any;
      # allow all;

This feature was the direct cause of multiple security vulnerabilities including CVE-2023-5043. With only the permission to create Ingress objects, it was effectively possible to manipulate the entire NGINX process configuration. This is because the configuration-snippet annotation is inserted directly into the location block of the NGINX configuration file, and server-snippet into the server block.

3.3 Gateway API's Annotation-less Model

Gateway API solves this problem with structured API types. Instead of relying on annotations, it expresses configuration through typed CRD fields.

Comparison Example: HTTPS Redirect and Path Rewriting

Legacy Ingress + Annotations approach:

# Ingress approach: relies on annotations
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: 'true'
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/proxy-read-timeout: '600'
    nginx.ingress.kubernetes.io/proxy-send-timeout: '600'
    nginx.ingress.kubernetes.io/proxy-body-size: '100m'
    nginx.ingress.kubernetes.io/cors-allow-origin: 'https://example.com'
    nginx.ingress.kubernetes.io/cors-allow-methods: 'GET, POST, PUT'
    nginx.ingress.kubernetes.io/cors-allow-headers: 'Content-Type, Authorization'
    nginx.ingress.kubernetes.io/enable-cors: 'true'
    nginx.ingress.kubernetes.io/limit-rps: '100'
    nginx.ingress.kubernetes.io/canary: 'true'
    nginx.ingress.kubernetes.io/canary-weight: '20'
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - app.example.com
      secretName: app-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /api(/|$)(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: api-service
                port:
                  number: 80

Gateway API approach:

# Gateway API approach: structured spec
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app
spec:
  parentRefs:
    - name: production-gateway
  hostnames:
    - app.example.com
  rules:
    # Rule 1: HTTPS redirect (expressed via spec, not annotations)
    - filters:
        - type: RequestRedirect
          requestRedirect:
            scheme: https
            statusCode: 301
      matches:
        - headers:
            - name: X-Forwarded-Proto
              value: http
    # Rule 2: API routing
    - matches:
        - path:
            type: PathPrefix
            value: /api
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /
      backendRefs:
        - name: api-service
          port: 80
          weight: 80
        - name: api-service-canary
          port: 80
          weight: 20

Key Differences Analysis:

AspectIngress + AnnotationsGateway API
Type SafetyNone (string key-value)Yes (CRD schema validation)
IDE SupportNoneAutocompletion, real-time validation
Deploy-time ValidationNone (runtime errors)Admission Webhook validation
Canary DeploymentAnnotation (vendor-specific)backendRefs.weight (standard)
HTTPS RedirectAnnotation (vendor-specific)RequestRedirect filter (standard)
Path RewritingAnnotation + regexURLRewrite filter (standard)
RBAC ControlCannot control per annotationResource-level RBAC possible
Audit TrailDifficultPossible at CRD level

3.4 Policy Attachment: The True Alternative to Annotations

Gateway API's Policy Attachment model separates cross-cutting concerns that annotations used to handle into independent resources.

# Timeout policy: managed as a separate resource
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: BackendLBPolicy
metadata:
  name: api-timeout-policy
spec:
  targetRefs:
    - group: ''
      kind: Service
      name: api-service
  sessionPersistence:
    sessionName: my-session
    type: Cookie
---
# TLS policy: backend TLS config separated into its own resource
apiVersion: gateway.networking.k8s.io/v1alpha3
kind: BackendTLSPolicy
metadata:
  name: api-backend-tls
spec:
  targetRefs:
    - group: ''
      kind: Service
      name: api-service
  validation:
    caCertificateRefs:
      - name: backend-ca-cert
        group: ''
        kind: ConfigMap
    hostname: api-internal.example.com

The advantages of this model are clear:

  • Separation of Concerns: Routing rules (HTTPRoute) and operational policies (Policy) are managed independently
  • Reusability: A single policy can be attached to multiple services
  • RBAC Application: Separate RBAC rules can be applied to policy resources
  • Audit Ease: Which policies are applied to which targets can be clearly tracked

4. [Takeaway 3] Separation of Roles: Peaceful Coexistence of Infrastructure Administrators and Developers

4.1 Governance Problems with Ingress

One of the fundamental design limitations of the existing Ingress API is the absence of role separation. Infrastructure settings (TLS certificates, listener ports) and application routing rules (path matching, backend services) are mixed within a single Ingress resource.

# Ingress: infrastructure and application settings mixed
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  # Who manages these annotations? Infra team? Dev team?
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: 'true' # Infrastructure concern
    nginx.ingress.kubernetes.io/proxy-body-size: '50m' # Infrastructure concern
    nginx.ingress.kubernetes.io/rewrite-target: /$1 # Application concern
    nginx.ingress.kubernetes.io/canary-weight: '10' # Application concern
spec:
  ingressClassName: nginx # Infrastructure concern
  tls:
    - hosts:
        - app.example.com
      secretName: production-tls-cert # Infrastructure concern (secret management)
  rules:
    - host: app.example.com # Mixed concern
      http:
        paths:
          - path: /api/(.*) # Application concern
            pathType: ImplementationSpecific
            backend:
              service:
                name: api-service # Application concern
                port:
                  number: 80

In this structure, developers must modify the same resource that contains infrastructure settings to change their routing rules. Conversely, infrastructure administrators must access resources containing application routing rules to replace TLS certificates.

4.2 Gateway API's Role-Based Resource Hierarchy

Gateway API solves this problem with a 3-layer resource model:

  ┌─────────────────────────────────────────────────────────────┐
Layer 1: GatewayClass  │  ─────────────────────                                      │
Owner: Infrastructure Provider (Cloud vendor, Platform team)Role: Define data plane implementation                      │
Example: "nginx", "envoy", "gke-l7-global"RBAC: cluster-admin level                                  │
  ├─────────────────────────────────────────────────────────────┤
Layer 2: Gateway  │  ─────────────────                                          │
Owner: Cluster Operator (Platform/Infra Engineer)Role: Listeners, TLS, IP addresses, ports, allowed NSExample: Port 443 HTTPS listener, wildcard certificate      │
RBAC: namespace-admin level (infra namespace)  ├─────────────────────────────────────────────────────────────┤
Layer 3: HTTPRoute / GRPCRoute / TCPRoute  │  ───────────────────────────────────────────                 │
Owner: Application Developer (Service developer)Role: Routing rules, backend service mapping, traffic weight│
Example: /api → api-service, canary 20%RBAC: namespace-editor level (application namespace)  └─────────────────────────────────────────────────────────────┘

Role Responsibility Matrix:

RoleResourceScope of ResponsibilityRBAC Example
Infrastructure ProviderGatewayClassRegister data plane implementation, define parametersClusterRole: gatewayclass-admin
Cluster OperatorGateway, ReferenceGrantListener settings, TLS cert management, NS access controlRole: gateway-admin (infra-ns)
Application DeveloperHTTPRoute, GRPCRouteRouting rules, backend service mapping, traffic distributionRole: route-editor (app-ns)

4.3 Production RBAC Configuration Example

Step 1: Infrastructure Provider -- GatewayClass Definition

# GatewayClass defined by the infrastructure provider
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx-gateway-fabric
spec:
  controllerName: gateway.nginx.org/nginx-gateway-controller
  parametersRef:
    group: gateway.nginx.org
    kind: NginxProxy
    name: production-proxy-config

Step 2: Cluster Operator -- Gateway Configuration

# Gateway managed by the cluster operator
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production-gateway
  namespace: gateway-infra # Infrastructure-only namespace
spec:
  gatewayClassName: nginx-gateway-fabric
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-tls-cert
            kind: Secret
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              gateway-access: 'true' # Only allowed namespaces
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: Same
---
# Cross-namespace reference grant
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-gateway-to-app-secrets
  namespace: app-team-a
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: Gateway
      namespace: gateway-infra
  to:
    - group: ''
      kind: Service

Step 3: Application Developer -- HTTPRoute Definition

# HTTPRoute managed by developers in their namespace
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-routes
  namespace: app-team-a # Application namespace
spec:
  parentRefs:
    - name: production-gateway
      namespace: gateway-infra # Reference Gateway in infra namespace
      sectionName: https
  hostnames:
    - api.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /v1
      backendRefs:
        - name: api-v1
          port: 8080
          weight: 80
        - name: api-v2
          port: 8080
          weight: 20 # Canary deployment: 20% traffic to v2

RBAC Policy Example:

# Developer Role: Can only create/modify HTTPRoutes
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: route-editor
  namespace: app-team-a
rules:
  - apiGroups: ['gateway.networking.k8s.io']
    resources: ['httproutes', 'grpcroutes']
    verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete']
  - apiGroups: ['gateway.networking.k8s.io']
    resources: ['gateways']
    verbs: ['get', 'list'] # Gateway is read-only
---
# Infrastructure operator Role: Can manage Gateway, cannot create Routes
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: gateway-admin
  namespace: gateway-infra
rules:
  - apiGroups: ['gateway.networking.k8s.io']
    resources: ['gateways', 'referencegrants']
    verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete']
  - apiGroups: ['']
    resources: ['secrets']
    verbs: ['get', 'list', 'watch', 'create', 'update']

The practical value this structure provides is as follows:

  • Developer Autonomy: Developers can freely change routing rules in their namespace without approval from the infrastructure team
  • Infrastructure Safety: The risk of developers accidentally modifying infrastructure settings such as TLS certificates, listener ports, or allowed namespaces is fundamentally eliminated
  • Cross-Namespace Security: Through ReferenceGrant, referencing resources from other namespaces must be explicitly allowed, preventing unauthorized access
  • Self-Service Governance: The platform team controls which namespaces can use the Gateway via allowedRoutes, and development teams operate freely within that scope

5. [Takeaway 4] Breaking Vendor Lock-in: Achieving Portability

5.1 The Essence of the Portability Problem

The reason the Ingress API fails to provide vendor portability is simple: the standard spec is too minimal. The Ingress API spec defines only the bare minimum: host matching, path matching, and TLS termination. All advanced features needed in practice (canary deployments, rate limiting, header manipulation, timeouts, retries, etc.) are independently implemented by each vendor through annotations.

As a result, the moment you write an Ingress resource, you are locked into a specific controller. This directly conflicts with Kubernetes' ideal of "Write once, run anywhere."

  ┌─────────────────────────────────────────────────────────────┐
Ingress API Portability Limitations  │                                                             │
Ingress spec (Standard)    Annotations (Non-standard)  │  ┌───────────────────┐   ┌──────────────────────────────┐   │
  │  │ host: app.com     │   │ nginx.ingress.k8s.io/...     │   │
  │  │ path: /api        │   │ traefik.ingress.k8s.io/...   │   │
  │  │ tls: cert         │   │ alb.ingress.k8s.io/...       │   │
  │  │                   │   │ haproxy.org/...               │   │
 (Portable) (Non-portable - Vendor-locked)│   │
  │  └───────────────────┘   └──────────────────────────────┘   │
20%                        80%Only 20% of actual          The remaining 80% depends    │
  │    config is portable          on vendor-specific annotations│
  └─────────────────────────────────────────────────────────────┘

5.2 Gateway API's Portability Strategy

Gateway API achieves both portability and extensibility by layering features into 3 support levels:

Support LevelDescriptionPortabilityConformance Test
CoreEssential features that all implementations must supportFully portableMandatory pass
ExtendedPortable features that not all implementations may supportConditionally portableOptional pass
Implementation-specificVendor-specific extension featuresNot portableNot applicable

Core Features (Fully Portable):

# This HTTPRoute works identically on any Gateway API implementation
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: portable-route
spec:
  parentRefs:
    - name: my-gateway
  hostnames:
    - app.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix # Core: path matching
            value: /api
        - headers: # Core: header matching
            - name: X-Version
              value: v2
      filters:
        - type: RequestHeaderModifier # Core: header manipulation
          requestHeaderModifier:
            add:
              - name: X-Gateway
                value: production
      backendRefs:
        - name: api-service
          port: 8080

Extended Features (Portable but verify implementation support):

# Extended features: supported by most implementations but verify
rules:
  - filters:
      - type: RequestRedirect # Extended: HTTP redirect
        requestRedirect:
          scheme: https
          statusCode: 301
      - type: URLRewrite # Extended: URL rewriting
        urlRewrite:
          path:
            type: ReplacePrefixMatch
            replacePrefixMatch: /v2
    backendRefs:
      - name: api-v1
        port: 8080
        weight: 90 # Extended: traffic weighting (canary)
      - name: api-v2
        port: 8080
        weight: 10

5.3 Conformance Test: The Guarantee of Portability

Gateway API's portability is backed not by mere promises but by a concrete verification mechanism called Conformance Tests.

Each implementation must pass a standardized test suite provided by the Gateway API project. These tests actually create Gateways and Routes, send traffic, and verify that they behave identically to the API specification.

  ┌─────────────────────────────────────────────────────────────┐
Conformance Test Process  │                                                             │
1. Run Gateway API test suite                               │
  │     └─> Deploy standard Gateway/HTTPRoute resources          │
  │                                                             │
2. Send actual traffic and verify behavior                  │
  │     └─> Path matching, header filtering, redirects, etc.     
  │                                                             │
3. Generate results report                                  │
  │     └─> Core 100%, Extended features list                    │
  │                                                             │
4. Official certification (Conformance Profile)  │     └─> Listed in official Gateway API implementations       │
  └─────────────────────────────────────────────────────────────┘

Conformance Status by Major Implementation:

ImplementationCore ConformanceExtended FeaturesNotes
NGINX Gateway FabricPassHTTP routing, TLS, URL rewriting, weight-based distributionNGINX data plane
Envoy GatewayPassAll Extended features supportedEnvoy Proxy data plane
GKE Gateway ControllerPassGCP native integrationGoogle Cloud only
IstioPassService mesh integrationIstio data plane
ContourPassEnvoy-basedVMware supported
TraefikPassMiddleware integrationv3+ support

5.4 Practical Portability Scenario: Multi-Cloud Migration

The portability guaranteed by Conformance Tests delivers real value in multi-cloud operations:

  ┌──────────────────┐     ┌──────────────────┐
AWS EKS        │     │   Azure AKS  │                  │     │                  │
GatewayClass:   │     │  GatewayClass:  │  aws-gateway     │     │  azure-gateway   │
    (change impl)  (change impl)  │                  │     │                  │
Gateway: ───────┼─────┼─ Gateway: ──────┐│
    (minimal edits)  (minimal edits) ││
  │                  │     │                  ││
HTTPRoute: ─────┼─────┼─ HTTPRoute: ────┘│
    (reuse as-is)  (reuse as-is)  └──────────────────┘     └──────────────────┘
           │                        │
           └───────┬────────────────┘
        Same HTTPRoute manifests reused
        by only changing GatewayClass

With the legacy Ingress approach, moving from AWS ALB Ingress Controller to GKE Ingress Controller required rewriting all annotations. With Gateway API, by only changing the GatewayClass, the remaining resources (Gateway, HTTPRoute) can be reused as-is within the scope of Core/Extended features.


6. [Takeaway 5] The Performance Leap: Full-Scale Adoption of HTTP/3 and QUIC

6.1 Why HTTP/3: The Structural Limitations of TCP

HTTP/2 enabled processing multiple streams simultaneously on the same TCP connection through multiplexing. However, it failed to solve the Head-of-Line (HOL) Blocking problem inherent in the TCP protocol itself.

  HTTP/2 over TCP Head-of-Line Blocking:

  TCP Connection
  ┌─────────────────────────────────────────────────┐
Stream 1: [Pkt1][Pkt2][  Lost  ][Pkt4]Stream 2: [PktA][PktB]Wait  [PktD]        │  ← Blocked!
Stream 3: [PktX][PktY]Wait  [PktZ]        │  ← Blocked!
  └─────────────────────────────────────────────────┘
               Pkt3 lost → All streams wait

  HTTP/3 over QUIC Independent Streams:

  QUIC Connection
  ┌─────────────────────────────────────────────────┐
Stream 1: [Pkt1][Pkt2][  Lost  ][Pkt4]        │  ← Only this stream affected
Stream 2: [PktA][PktB][PktC]   [PktD]         │  ← Proceeds normally!
Stream 3: [PktX][PktY][PktZ]                   │  ← Proceeds normally!
  └─────────────────────────────────────────────────┘
               Pkt3 lost → Only Stream 1 affected

HTTP/3 uses the QUIC (Quick UDP Internet Connections) protocol instead of TCP. QUIC is built on top of UDP, and each stream is delivered independently. Packet loss in one stream does not affect other streams.

6.2 Key Performance Benefits of HTTP/3

FeatureHTTP/2 (TCP)HTTP/3 (QUIC)Improvement
Transport LayerTCPUDP + QUICReduced kernel dependency
Connection EstablishmentTCP 3-way handshake + TLS handshake (2-3 RTT)QUIC 0-RTT / 1-RTTUp to 67% latency reduction
HOL BlockingOccurs at TCP levelIsolated to stream levelImproved parallel processing
Connection MigrationReconnection needed on IP/port changeMaintained via Connection IDMobile environment stability
EncryptionTLS optionalTLS 1.3 mandatory (built-in)Default encryption guaranteed
Packet Loss RecoveryAffects entire connectionIndependent per-stream recoveryBetter lossy network performance

6.3 HTTP/3 Support in NGINX Gateway Fabric

NGINX officially supports QUIC and HTTP/3 since v1.25.0, and HTTP/3 can be leveraged in Kubernetes environments through NGINX Gateway Fabric.

NginxProxy Configuration for HTTP/3 Activation:

apiVersion: gateway.nginx.org/v1alpha1
kind: NginxProxy
metadata:
  name: http3-enabled-proxy
spec:
  config:
    http:
      http3: true
      http3MaxConcurrentStreams: 128
      altSvcHeader: true # Automatically add Alt-Svc header

Gateway HTTP/3 Listener Configuration:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: http3-gateway
  namespace: gateway-infra
spec:
  gatewayClassName: nginx-gateway-fabric
  listeners:
    # HTTPS (TCP) + HTTP/3 (UDP) simultaneous listening
    - name: https-tcp
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-tls-cert
    - name: https-udp
      protocol: HTTPS # HTTP/3 declared as HTTPS protocol
      port: 443 # Same port, QUIC handled over UDP
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-tls-cert

Exposing UDP Port in Service:

apiVersion: v1
kind: Service
metadata:
  name: nginx-gateway-fabric
  namespace: gateway-infra
spec:
  type: LoadBalancer
  ports:
    - name: https-tcp
      port: 443
      targetPort: 443
      protocol: TCP
    - name: https-udp
      port: 443
      targetPort: 443
      protocol: UDP # UDP port required for QUIC

6.4 HTTP/3 Adoption Considerations

There are technical requirements and considerations that must be verified when adopting HTTP/3:

1) SSL Library Requirements

QUIC protocol support requires a QUIC-compatible SSL library. Standard OpenSSL does not support the QUIC API (as of OpenSSL 3.x), so one of the following alternatives must be used:

SSL LibraryQUIC SupportNotes
BoringSSLNative supportDeveloped by Google, default in NGINX Gateway Fabric
LibreSSL3.6.0+ supportOpenBSD project
QuicTLSOpenSSL + QUIC patchOpenSSL fork with QUIC API added
OpenSSLNot supported (3.x)Future support planned

NGINX Gateway Fabric is built with BoringSSL by default, so HTTP/3 can be used without any SSL library replacement.

2) Firewall and Network Configuration

  ┌─────────────────────────────────────────────────────────┐
HTTP/3 Network Requirements  │                                                         │
UDP 443 must be added to inbound rules:  │                                                         │
Before (HTTP/2 only):  │  ┌──────────────────────────────────────┐               │
  │  │ TCP 80HTTP                     │               │
  │  │ TCP 443HTTPS (TLS over TCP)     │               │
  │  └──────────────────────────────────────┘               │
  │                                                         │
After adding HTTP/3:  │  ┌──────────────────────────────────────┐               │
  │  │ TCP 80HTTP                     │               │
  │  │ TCP 443HTTPS (TLS over TCP)     │               │
  │  │ UDP 443QUIC (HTTP/3 over UDP)   │  ← Must add   │
  │  └──────────────────────────────────────┘               │
  │                                                         │
Note: Many enterprise firewalls and cloud security     │
  │  groups block UDP 443 by default.                       
  └─────────────────────────────────────────────────────────┘
  • Cloud Security Groups: UDP 443 inbound must be explicitly allowed in AWS Security Groups, Azure NSGs, GCP Firewall Rules
  • CDN/WAF Compatibility: Some CDNs or WAFs may block or improperly handle QUIC traffic
  • Load Balancer Support: Verify that cloud load balancers correctly route UDP traffic. AWS NLB, Azure Load Balancer, and GCP Network Load Balancer support UDP

3) Gradual Transition via Alt-Svc Header

HTTP/3 adoption can proceed gradually. The server includes an Alt-Svc header in HTTP/2 responses to inform clients that HTTP/3 is available:

Alt-Svc: h3=":443"; ma=86400

After receiving this header, the client attempts HTTP/3 on subsequent requests. If it fails, it automatically falls back to HTTP/2. As of 2025, Chrome 87+, Firefox 88+, Safari 14+, and more than 95% of all browsers support HTTP/3.

4) QUIC Connection Migration with eBPF

Linux 5.7+ kernels support QUIC packet routing using eBPF. This enables QUIC's Connection Migration feature, allowing connections to persist even when the client's network changes (e.g., switching from Wi-Fi to LTE).

# Enable eBPF-based QUIC routing in nginx.conf
quic_bpf on;  # Requires Linux 5.7+

7. Practical Migration Guide

7.1 Migration Strategy Overview

Migration from Ingress NGINX to Gateway API should follow a Progressive Migration approach rather than a Big Bang approach.

  ┌──────────────────────────────────────────────────────────────┐
Progressive Migration Strategy  │                                                              │
Phase 1: Inventory and Assessment (1-2 weeks)  │  ├─ Catalog all Ingress resources                            │
  │  ├─ Classify annotations in use                              │
  │  ├─ Identify snippets usage (priority: security risk removal)  │  └─ Map dependencies (cert-manager, external-dns, etc.)  │                                                              │
Phase 2: Build Gateway API Infrastructure (1-2 weeks)  │  ├─ Install Gateway API CRDs  │  ├─ Deploy NGINX Gateway Fabric or alternative controller    │
  │  ├─ Create GatewayClass, Gateway resources                   │
  │  └─ Validate in non-production environment                   │
  │                                                              │
Phase 3: Progressive Routing Transition (2-4 weeks)  │  ├─ Initial conversion with ingress2gateway tool             │
  │  ├─ Manual review & annotation → filter/policy conversion    │
  │  ├─ Sequential per-service transition (non-critical → critical)  │  └─ Parallel operation period (Ingress + Gateway API)  │                                                              │
Phase 4: Full Transition and Cleanup (1-2 weeks)  │  ├─ Confirm all traffic routes through Gateway API  │  ├─ Remove Ingress resources                                 │
  │  ├─ Remove ingress-nginx controller                          │
  │  └─ Reconfigure monitoring and alerts                        │
  └──────────────────────────────────────────────────────────────┘

7.2 Phase 1: Inventory Collection

Query all Ingress resources:

# List all Ingress resources across all namespaces
kubectl get ingress -A -o wide

# Extract all annotations in use
kubectl get ingress -A -o json | \
  jq -r '.items[].metadata.annotations // {} | keys[]' | \
  sort | uniq -c | sort -rn

# Urgent check for snippets annotations (security risk)
kubectl get ingress -A -o json | \
  jq -r '.items[] | select(.metadata.annotations["nginx.ingress.kubernetes.io/configuration-snippet"] != null or .metadata.annotations["nginx.ingress.kubernetes.io/server-snippet"] != null) | .metadata.namespace + "/" + .metadata.name'

# Check IngressClass
kubectl get ingressclass

Annotation Classification Checklist:

ClassificationAnnotation ExamplesGateway API ReplacementUrgency
Security Riskconfiguration-snippet, server-snippetRemove or Custom FilterImmediate
Standard Replaceablessl-redirect, rewrite-targetRequestRedirect, URLRewrite filterHigh
Policy Replaceableproxy-read-timeout, proxy-body-sizePolicy AttachmentMedium
Feature Replaceablecanary, canary-weightbackendRefs.weightMedium
Implementation Dependentupstream-hash-by, affinityCheck implementation-specific CRDsLow

7.3 Phase 2: Using the ingress2gateway Tool

ingress2gateway is an official migration tool provided by Kubernetes SIG-Network.

Installation:

# With Go environment
go install github.com/kubernetes-sigs/ingress2gateway@latest

# Or download binary from GitHub Releases
# https://github.com/kubernetes-sigs/ingress2gateway/releases

Basic Usage:

# Auto-convert Ingress resources from the cluster
ingress2gateway print --all-namespaces

# Convert specific namespace only
ingress2gateway print --namespace production

# File-based conversion
ingress2gateway print --input-file ingress-resources.yaml

# Specify ingress-nginx provider (annotation conversion support)
ingress2gateway print --providers ingress-nginx --all-namespaces

# Save results to file
ingress2gateway print --providers ingress-nginx --all-namespaces > gateway-resources.yaml

Important Note: ingress2gateway is only a starting point and does not perfectly convert all annotations. Implementation-specific features (snippets, custom Lua scripts, etc.) must be manually redesigned. Always review conversion results and thoroughly test in a non-production environment before applying.

7.4 Phase 3: Deploying NGINX Gateway Fabric

Installation via Helm:

# Install Gateway API CRDs
kubectl kustomize \
  "https://github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.2.1" \
  | kubectl apply -f -

# Install NGINX Gateway Fabric
helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
  --create-namespace \
  --namespace nginx-gateway \
  --set service.type=LoadBalancer

Verify GatewayClass:

# Check GatewayClass after installation
kubectl get gatewayclass
# NAME            CONTROLLER                                    ACCEPTED
# nginx           gateway.nginx.org/nginx-gateway-controller     True

Create and Validate Gateway:

# Apply Gateway resource
kubectl apply -f gateway.yaml

# Check Gateway status
kubectl get gateway -n gateway-infra
# NAME                  CLASS   ADDRESS         PROGRAMMED   AGE
# production-gateway    nginx   203.0.113.10    True         5m

# Apply HTTPRoute
kubectl apply -f httproute.yaml

# Check HTTPRoute status
kubectl get httproute -n app-team-a
# NAME          HOSTNAMES           AGE
# api-routes    ["api.example.com"] 2m

# Test with actual traffic
curl -H "Host: api.example.com" https://203.0.113.10/v1/health

7.5 Ingress vs Gateway API Feature Comparison Summary

FeatureIngress APIGateway APINotes
Host-based Routingspec.rules[].hostspec.hostnamesEquivalent
Path-based Routingspec.rules[].http.pathsspec.rules[].matches[].pathGateway API more flexible
TLS Terminationspec.tlsGateway.listeners[].tlsRole separation (managed at Gateway)
HTTPS RedirectAnnotation (vendor-specific)RequestRedirect filter (standard)Gateway API advantage
URL RewritingAnnotation (vendor-specific)URLRewrite filter (standard)Gateway API advantage
Canary DeploymentAnnotation (vendor-specific)backendRefs.weight (standard)Gateway API advantage
Header MatchingNot supported (annotation only)spec.rules[].matches[].headersGateway API advantage
Header ManipulationAnnotation (vendor-specific)RequestHeaderModifier filterGateway API advantage
Traffic MirroringAnnotation (vendor-specific)RequestMirror filter (Extended)Gateway API advantage
TimeoutsAnnotation (vendor-specific)HTTPRoute timeouts (v1.2+)Gateway API advantage
RetriesAnnotation (vendor-specific)HTTPRoute retry (v1.2+)Gateway API advantage
gRPC RoutingNot supported (annotation only)GRPCRoute (GA)Gateway API advantage
TCP/UDP RoutingNot supportedTCPRoute, UDPRoute (Experimental)Gateway API advantage
Role-based SeparationNot supportedGatewayClass/Gateway/Route separationGateway API advantage
Cross-NamespaceNot supportedReferenceGrantGateway API advantage
Vendor PortabilityLow (annotation-dependent)High (Conformance Test)Gateway API advantage
Backend TLSAnnotation (vendor-specific)BackendTLSPolicy (v1.4 GA)Gateway API advantage
WebSocketAnnotation (vendor-specific)Standard support (v1.2+)Gateway API advantage

8. Comprehensive Migration Checklist

Below is a comprehensive checklist for transitioning from Ingress NGINX to Gateway API. Adapt it to your organization's situation.

8.1 Assessment Phase

  • Complete inventory of all Ingress resources and namespace mapping across all clusters
  • Complete audit of all Ingress NGINX annotations in use
  • Confirm configuration-snippet / server-snippet usage and assess security risk
  • Verify ingress-nginx controller version (CVE-2025-1974 patch status)
  • Identify dependencies on integrated systems (cert-manager, external-dns, etc.)
  • Document current traffic patterns and routing rules

8.2 Planning Phase

  • Select target Gateway API implementation (NGINX Gateway Fabric, Envoy Gateway, etc.)
  • Establish GatewayClass/Gateway/Route role separation policy
  • Design namespace strategy (infrastructure vs. application)
  • Design RBAC policy (infrastructure team vs. development team privilege separation)
  • Determine migration order (non-critical services first)
  • Establish rollback plan
  • Decide on HTTP/3 adoption

8.3 Execution Phase

  • Install Gateway API CRDs (gateway.networking.k8s.io)
  • Deploy Gateway API implementation controller
  • Create GatewayClass resource and verify status (ACCEPTED: True)
  • Create Gateway resource and confirm IP address allocation (PROGRAMMED: True)
  • Run initial conversion with ingress2gateway tool
  • Manually review conversion results and supplement missing features
  • Test converted HTTPRoutes in non-production environment
  • Gradually shift traffic using DNS weight-based routing
  • Production environment transition and monitoring

8.4 Validation Phase

  • Confirm normal responses for all routing paths
  • Verify TLS certificate termination and renewal work correctly
  • Confirm canary/weight-based deployment behavior
  • Verify header-based routing behavior
  • Confirm error pages and default backend behavior
  • Verify monitoring and alerting work correctly
  • Perform load testing and compare against performance baseline

8.5 Cleanup Phase

  • Remove legacy Ingress resources
  • Remove ingress-nginx controller Deployment/DaemonSet
  • Clean up ingress-nginx related ConfigMaps, ServiceAccounts, RBAC resources
  • Remove ingress-nginx Service (LoadBalancer) and reclaim IP addresses
  • Clean up Helm releases (if applicable)
  • Remove or replace Ingress-related manifests in CI/CD pipelines with Gateway API
  • Remove ingress-nginx modules from IaC (Terraform, Pulumi, etc.)
  • Team training and operational documentation update

9. Conclusion: It Is Time to Act

The retirement of Ingress NGINX is not simply an event where one controller disappears. It is a turning point for the entire Kubernetes networking paradigm.

Summary: 5 Key Changes and Response Directions

#ChangeKey MessageImmediate Action
1Ingress NGINX EOLNo security patches after March 2026Begin migration planning
2Escape AnnotationsStructural flaws directly lead to vulnerabilitiesRemove snippets usage immediately
3Role SeparationGatewayClass/Gateway/Route 3-layer modelRedesign RBAC policies
4Vendor PortabilityConformance Test-based standardizationRevisit multi-cloud strategy
5HTTP/3 & QUICNext-gen protocol based on UDPReview firewall UDP 443 opening

3 Actions to Execute Right Now:

1. Collect Inventory (Today)

# Execute this right now
kubectl get ingress -A -o json | \
  jq -r '[.items[] | {
    namespace: .metadata.namespace,
    name: .metadata.name,
    annotations: (.metadata.annotations // {} | keys | length),
    has_snippets: ((.metadata.annotations // {}) |
      has("nginx.ingress.kubernetes.io/configuration-snippet") or
      has("nginx.ingress.kubernetes.io/server-snippet"))
  }]'

2. Run ingress2gateway Tool (This Week)

go install github.com/kubernetes-sigs/ingress2gateway@latest
ingress2gateway print --providers ingress-nginx -A > gateway-migration.yaml

3. Build NGINX Gateway Fabric Test Environment (This Month)

# Test on a non-production cluster
kubectl kustomize \
  "https://github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.2.1" \
  | kubectl apply -f -

helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
  --create-namespace --namespace nginx-gateway

The experience and lessons the Kubernetes community has built over a decade are distilled into Gateway API as the new standard. It is time to move from the annotation swamp to type-safe APIs, from mixed single resources to role-based separation, and from vendor lock-in to the freedom of portability.

The March 2026 deadline is not a threat but an opportunity. Through this transition, you can build more secure, more flexible, and more standardized networking infrastructure. Start now.


10. References

Official Documentation and Announcements

NGINX Gateway Fabric

Security and CVE

Migration Guides

Cloud Vendors

HTTP/3 and QUIC