Half of Kubernetes picked an ingress that just died


Half of cloud native environments front their clusters with the same piece of software. Not the OS. Not the CNI. ingress-nginx, the community NGINX ingress controller, which internal Datadog research puts at roughly 50 percent of cloud native environments.

On March 24, 2026, at KubeCon EU in Amsterdam, Kubernetes archived it. Read-only. No more releases, no bug fixes, no security patches. Steering committee member Kat Cosgrove said it straight: “It is closed. Now it is dead.”

That means half the ecosystem’s clusters are now fronted by software with no upstream and no patch pipeline, sitting on a public IP address. That is not an abstract supply-chain concern. It is your load balancer. Here is what happened, what breaks, and where I think everyone lands over the next year.

First, what died

Precision matters here, because three things get confused constantly.

The community ingress-nginx controller is dead. That is the kubernetes/ingress-nginx project, the one behind the ingress-nginx Helm chart, the one the Kubernetes project itself built as its reference ingress controller.

The Ingress API is not dead. networking.k8s.io/v1 is GA, stable in every current Kubernetes release, and not scheduled for removal. It is frozen, so new features go elsewhere, but it works and it keeps getting whatever security fixes Kubernetes itself ships. As the CNCF migration guide puts it, “A common misconception is that Kubernetes Ingress itself is being retired. In reality, the Ingress API remains supported and widely used.”

F5’s commercial NGINX Ingress Controller was never part of this. Different repo, different maintainers, still maintained. The CNCF end-user post carries an editor’s note about this specifically because people keep mixing them up.

My take: Ingress is not going anywhere fast. Millions of clusters will run it on maintained controllers, Traefik, HAProxy, Contour, the cloud-managed ones, for years. Feature-frozen and boring is a legitimate place to be. If someone tells you Ingress is deprecated, they have confused an API with a controller.

How the most-used ingress controller ran out of people

The retirement announcement spells out the numbers. For years, ingress-nginx was maintained by “one or two people doing development work, on their own time, after work hours and on weekends.” The maintainers tried to hand it off twice. First a public call at KubeCon 2024, then a plan to build a successor called InGate. Neither produced enough contributors. InGate never matured and gets retired alongside the controller.

The project also carried a design that made the job brutal. Ingress annotations get interpolated straight into NGINX configuration, which turned every config-injection bug into a potential remote code execution. In March 2025, Wiz Research disclosed IngressNightmare, a chain of five vulnerabilities led by CVE-2025-1974, CVSS 9.8, unauthenticated RCE through the admission webhook. They estimated 43 percent of cloud environments were vulnerable, with more than 6,500 clusters exposing the vulnerable webhook to the internet.

One or two volunteers cannot be the security response for that, for half the industry, in their spare time. The steering committee said in January 2026 that they could not “overstate the severity of the situation.” By March they had stopped looking for maintainers and started archiving.

The timer you didn’t set

Here is the underrated part. Most people running ingress-nginx on a managed provider will never click “upgrade cluster” in their lives. It does not matter, because their provider will.

GKE upgrades control planes automatically, full stop, and you can only delay it with maintenance windows. The Rapid channel has been moving clusters past 1.35 since June 2026. Regular starts in October 2026, Stable follows in December, and by April 2027 every GKE cluster is past 1.35, the last version ingress-nginx ever supported. AKS ships 1.37 in October 2026, which pushes 1.35 out of the supported window 30 days later, and AKS Automatic clusters get no vote in the matter. EKS is the patient one: the default upgrade policy is EXTENDED, so you pay $0.60 an hour to stay put until March 2028, when Amazon upgrades your control plane without notifying you.

If you are on a managed provider, your clusters may already be running an unsupported controller version, moved there without a ticket from you. Worth checking.

What breaks

Almost nothing breaks right away, but everything breaks eventually.

The controller is just a Deployment. When the control plane upgrades, the nginx pods do not care. The Ingress API still validates your routes, traffic keeps flowing, and Kubernetes’ own retirement post says “existing deployments of Ingress NGINX will continue to function.” No ingress-nginx release has ever been tested against 1.36, and none ever will be. That’s less scary than it sounds. The Ingress API is stable, the controller leans on long-stable APIs, and most clusters should keep serving without drama. For now.

What breaks is the security model, and it is already broken. On July 15, 2026, F5 disclosed CVE-2026-42533, an unauthenticated heap overflow in NGINX’s script engine, 9.2 Critical on CVSS v4.0. Upstream NGINX fixed it the same day, in 1.30.4 and 1.31.3. The ingress-nginx controller embeds an affected NGINX build, sits at the TLS-terminating edge of your cluster, and will never ship a release that absorbs the fix. The reliable exploit outcome is a worker crash, which for an ingress controller is a full front-door outage. The worst case is code execution. A sibling in the same batch, CVE-2026-42945, “NGINX Rift”, is another 9.2 Critical in the rewrite module, same story.

The reporter has a working proof of concept and is withholding it. No confirmed exploitation in the wild yet, and nothing in CISA’s known-exploited catalog. Cosgrove, at the archive, said she would “be incredibly shocked if there wasn’t already somebody sitting on a nasty remote code execution vulnerability.” Five months later, that quote looks less like a joke and more like a schedule.

The pre-retirement CVEs are still out there too, in clusters that never applied the March fixes. Three separate CVSS 8.8 config injection bugs shipped in five weeks before the archive, each one an incomplete fix for the last. And the snippet annotations, server-snippet and friends, still let anyone with Ingress RBAC inject arbitrary NGINX directives, by design, on any version. That is not a bug you patch. That is the architecture.

There is also a compliance clock. The EU Cyber Resilience Act starts its reporting obligations on September 11, 2026. “The upstream project no longer exists” is not an answer a Critical accepts.

Where the crowd is going

Two lanes are emerging.

Lane one is Gateway API, the successor the Kubernetes project built. Routes written against it port between implementations, the feature set went GA across the board in v1.5 and v1.6, and there is now a converter, ingress2gateway, that translates Ingress manifests plus 30-odd ingress-nginx annotations and tells you which ones it could not.

Lane two is a lateral move to another Ingress controller. Traefik is the most cited, it serves Ingress and Gateway API at once, and CERN recommends it as the pragmatic fallback for deployments blocked on third-party Helm charts.

My prediction: the next 6 to 12 months produce a large, mostly involuntary migration to gateways. Three pressures line up. Providers are auto-upgrading clusters past the last supported controller version right now. The CVEs at the edge have no fix path. And Gateway API is finally mature enough that the “we’re not ready” excuse is gone. Before the retirement, KubeCon NA 2024 data put production Gateway API adoption under 15 percent. Under 15 percent means most of the migration still hasn’t happened. That is why the next year gets busy.

Why managed gateways fit

If you are on GKE, EKS, or AKS, I think the managed gateway offerings are the best destination, for three reasons.

Direct to pod

The thing nobody mentions about ingress-nginx is that every request gets proxied twice. The default path is load balancer, node, nginx pod, your pod. Two L7 proxy hops, either of which can cross the network an extra time, and your app never asked for either.

Managed gateway data planes skip that. GKE’s Gateway and Ingress both use container-native load balancing through NEGs, sending traffic “directly to the IP addresses of individual Pods (rather than nodes).” The AWS Load Balancer Controller’s Gateway mode puts pod IPs straight into ALB target groups, verified down to the target matching the pod. Azure’s Application Gateway for Containers proxies “directly to pods,” including through CNI Overlay.

Is the saving big? Per request, no. Benchmarks put an L7 proxy hop at roughly half a millisecond at p50, 2.3ms at p99, 7ms at p99.9. The tails hurt more than the median, as usual. At throughput it stops being latency and becomes capacity: an Envoy-class proxy burns about 1.5 to 1.8 CPU cores per 10,000 requests per second, and a research paper on proxy overhead found protocol parsing alone is 63 to 77 percent of the cost. That is your app’s CPU budget spent re-reading HTTP headers.

Gateway API itself does not remove the hop; the managed data plane does. Self-managed Envoy Gateway or Istio gateways run their own proxy pods behind a load balancer service, which is the identical architecture nginx ingress had. The hop only disappears when the load balancer is the data plane. With the managed gateways, that is the default.

Many hostnames, one load balancer

A chunk of why people loved nginx ingress is economic. One LoadBalancer service, one cloud LB bill, and every team pins hostnames and routes to it. The shared front door.

Gateway API keeps that and formalizes it. One Gateway resource declares the listeners, port 80, port 443, your TLS certs, and HTTPRoutes from any namespace attach to it. The platform team owns the door, app teams own their routes, and the bill stays at one LB.

Not lock-in, config style

The managed gateways are cloud infrastructure, which sounds like lock-in. It mostly is not. The routes you write are standard CRDs. Amazon’s own sample project says it: “The Gateway and HTTPRoute resources use the same CRDs regardless of which controller you are using. The only difference between the two is the gatewayClassName field.” Swapping ALB for VPC Lattice is a one-line change.

Core routes port cleanly; vendor extensions do not. GKE’s multi-cluster GatewayClasses are GCP-only, AWS’s listener rule CRDs are AWS-only, and conformance varies by implementation. So it is a config style thing, not a marriage. You commit to a shape, not a vendor.

If it were my cluster

Find it, version it, then decide deliberately:

kubectl get pods --all-namespaces --selector app.kubernetes.io/name=ingress-nginx

If the controller is below v1.15.1, upgrade first. That is the last release that closes every known pre-archive CVE, and the images and charts are still downloadable. If you are on v1.15.1 already, you are current, and current here means as good as it will ever get.

Then make the migration someone’s job with a real deadline. Treat it like an important security fix, because it is one. It cannot be done instantly, and the annotation audit alone surprises people, so budget a quarter, not a sprint. On a managed provider, pick the managed gateway and change the gatewayClassName. Self-managed or multi-cloud, Traefik if you need Ingress compatibility while third-party charts catch up, Envoy Gateway or Istio if you are ready for routes. Mine already did this lap: the homelab cluster started on ingress-nginx, and I moved it to Traefik on the Gateway API when the retirement was announced, which I wrote up in the Titan post. Lock down who can create Ingress objects while you work, because every known injection bug starts there.

Roughly half of cloud native environments still run this controller. If yours is one of them, the clock is your provider’s next automatic upgrade, so pick a gateway before it lands.