Gateway API Multi-Tenancy Is Awkward, and We're Migrating Anyway

If you’ve been running multi-tenant Kubernetes clusters with cert-manager and Let’s Encrypt, you’ve probably felt the friction when evaluating Gateway API. I certainly did. What looked like a straightforward migration path turned into a deep dive into API design trade-offs, experimental features, and some hard decisions about timing.

Here’s what we learned and why we’re migrating anyway.

Why This Matters Now

In November 2025, the Kubernetes project announced that ingress-nginx will reach end of life in March 2026. If you’re one of the many teams running ingress-nginx, you’re now on a timeline to migrate to something else.

The Ingress API itself isn’t going anywhere. You can switch to another Ingress controller like Traefik or HAProxy and keep your existing Ingress resources. But if you’re migrating controllers anyway, it’s worth asking: should you move to Gateway API instead?

Gateway API is the successor to Ingress. It’s more expressive, has better separation of concerns, and is where the ecosystem is heading. The catch is that the migration isn’t always straightforward, especially for multi-tenant setups with cert-manager. More on that in a moment.

Our Setup

We run Azure Kubernetes Service clusters hosting applications for multiple customers, each on their own domains. Small teams manage their entire clusters and all the apps inside. One shared ingress controller per cluster, with Ingress resources and TLS annotations per app, and cert-manager handling certificate provisioning automatically via Let’s Encrypt. It works. Nobody needs to think about certificates.

Our current Azure Application Gateway Ingress Controller (AGIC) setup has some pain points though. Changes don’t propagate cleanly during rolling updates, causing brief downtimes that shouldn’t exist. Or the fact that AGIC only supports 100 backend services. So for some clusters, we have deployed multiple Application Gateways, causing extra management overhead and costs.

We want to migrate to Azure Application Gateway for Containers (AGC), which promises to solve these issues. We currently rely on AGIC’s support for end-to-end TLS and Web Application Firewall, and we need to keep those capabilities. AGC supports both Ingress API and Gateway API, but here’s the catch: if you need E2E TLS and WAF on AGC, Gateway API is the only supported path.

So Gateway API it is. Except…

The Multi-Tenancy Problem

Gateway API splits what was a single Ingress resource into multiple resources with different ownership models. The idea is sound: infrastructure concerns (Gateways with ports, addresses, TLS termination) are separated from routing concerns (HTTPRoutes). Clear separation of concerns.

The problem is where TLS certificates land in this model. Certificates are configured on the Gateway resource, not on HTTPRoutes. For multi-tenant clusters, this means:

  • Every app’s TLS configuration lives in a single, central Gateway resource
  • Adding a new domain means editing that shared Gateway, not just deploying app-specific resources
  • Configuration for dozens of unrelated apps gets mixed together in one place

Even for small teams like ours that manage everything, this creates unnecessary coupling. With Ingress, each app’s configuration was self-contained. With Gateway API, we’re back to maintaining a growing list of listeners in a central resource that touches every app.

A Reddit thread captured this frustration well. It seems like this isn’t a niche concern, it’s a common pain point for anyone running multi-tenant clusters.

Why It’s Designed This Way

To be fair to the Gateway API designers, this wasn’t an oversight. Nick Young, one of the maintainers, explained the historical context: when Gateway API was designed, certificates were expensive assets bought from traditional CAs, costing thousands of dollars each. Centralizing them under infrastructure control made sense.

Let’s Encrypt changed that. Certificates became cheap and automatable. cert-manager made it trivial for application teams to manage their own TLS. But Gateway API’s design predates this shift in how we think about certificate ownership.

The other design goal was security. With Ingress, nothing prevented one team from accidentally (or maliciously) creating an Ingress with another team’s hostname, potentially intercepting their traffic. Gateway API’s centralized listener model provides stronger isolation. That’s a real benefit, even if it comes with workflow friction.

The Missing Piece: ListenerSet

The Gateway API community recognized this gap. Enter ListenerSet (currently XListenerSet while experimental), a new resource that lets you define listeners with TLS configuration separately from the Gateway, then attach them.

The model becomes:

ResourceScopeConcerns
GatewayCluster-wideInfrastructure, ports, policies
ListenerSetPer-appHostnames, TLS certificates
HTTPRoutePer-appRouting rules

This is exactly what multi-tenant setups need. The Gateway defines the infrastructure boundary, while ListenerSets and HTTPRoutes stay with their respective apps. cert-manager can annotate ListenerSets for automatic certificate provisioning. Configuration stays where it belongs.

Except it’s experimental. And cert-manager doesn’t support it yet.

The cert-manager Timeline

The cert-manager team is actively working on XListenerSet support. Their planned timeline:

  • January 2026: Alpha builds with XListenerSet support
  • February 2026: cert-manager 1.20 with experimental XListenerSet support
  • Later in 2026: Stable ListenerSet support once Gateway API graduates the feature

This means if you’re migrating today, you’re looking at several months before the elegant solution is available. And if you’re on ingress-nginx, that timeline collides awkwardly with the March 2026 EOL.

Our Options

We had three realistic paths:

Option 1: Wait it out

Stay on Azure Application Gateway with Ingress API until ListenerSet and cert-manager support are both stable. Accept the current limitations (rolling update hiccups) and migrate once the ecosystem is ready.

Pros: Cleanest migration path, no intermediate states

Cons: We keep dealing with App Gateway’s limitations for 6+ months

Option 2: Migrate now, accept the friction

Move to AGC with Gateway API today. Define all HTTPS listeners centrally in the Gateway resource. Accept that this spreads concerns across namespaces and configs, and plan to refactor to ListenerSet later.

Pros: Immediate benefits from AGC, E2E TLS and WAF support now

Cons: Awkward configuration model, technical debt to clean up later

Option 3: Build our own abstraction

Create a custom operator or use something like Crossplane to let teams define their TLS requirements in a friendly CRD, while we generate the underlying Gateway configuration.

Pros: Better developer experience now

Cons: More infrastructure to maintain, another migration when ListenerSet lands

What We Chose

We’re going with Option 2: migrate now and refactor later.

The deciding factors:

  1. We don’t want to build custom tooling. Building and maintaining custom operators isn’t where we want to spend our limited cycles. We’d rather deal with some configuration sprawl than add another system to maintain.

  2. The AGC benefits are real. Fixing our rolling update issues and keeping E2E TLS with WAF is worth some short-term awkwardness.

  3. ListenerSet is real and gaining traction. XListenerSet shipped as experimental in Gateway API v1.3.0 (June 2025), with implementations already available (kgateway) and cert-manager adding support in early 2026. While there’s no published timeline for graduation to Standard, the feature addresses a widely recognized pain point and has active maintainer support.

  4. The migration from centralized listeners to ListenerSet should be straightforward. We’ll essentially be moving configuration from one resource to another, not rearchitecting anything fundamental.

What This Looks Like in Practice

Today, our Gateway resource has to enumerate every listener:

 1apiVersion: gateway.networking.k8s.io/v1
 2kind: Gateway
 3metadata:
 4  name: main-gateway
 5  annotations:
 6    cert-manager.io/cluster-issuer: letsencrypt-prod
 7spec:
 8  gatewayClassName: azure-alb
 9  listeners:
10    - name: https-customer-a
11      hostname: app.customer-a.com
12      port: 443
13      protocol: HTTPS
14      tls:
15        mode: Terminate
16        certificateRefs:
17          - name: customer-a-tls
18    - name: https-customer-b
19      hostname: app.customer-b.com
20      port: 443
21      protocol: HTTPS
22      tls:
23        mode: Terminate
24        certificateRefs:
25          - name: customer-b-tls
26    # ... this list grows with every customer

When ListenerSet lands, each app’s config stays with the app:

 1apiVersion: gateway.networking.x-k8s.io/v1alpha1
 2kind: XListenerSet
 3metadata:
 4  name: customer-a-listeners
 5  namespace: customer-a
 6  annotations:
 7    cert-manager.io/cluster-issuer: letsencrypt-prod
 8spec:
 9  parentRef:
10    name: main-gateway
11    namespace: gateway-system
12  listeners:
13    - name: https
14      hostname: app.customer-a.com
15      port: 443
16      protocol: HTTPS
17      tls:
18        mode: Terminate
19        certificateRefs:
20          - name: customer-a-tls

The Gateway becomes minimal, just defining the infrastructure boundary:

 1apiVersion: gateway.networking.k8s.io/v1
 2kind: Gateway
 3metadata:
 4  name: main-gateway
 5spec:
 6  gatewayClassName: azure-alb
 7  allowedListeners:
 8    namespaces:
 9      from: Selector
10      selector:
11        matchLabels:
12          gateway-access: "true"
13  listeners: []  # Empty! All listeners come from ListenerSets

That’s the end state we’re working toward.

Recommendations

If you’re facing a similar decision:

If you’re on ingress-nginx: You have until March 2026 to migrate somewhere. The cert-manager team’s advice is pragmatic: consider switching to another Ingress controller like Traefik first, rather than jumping straight to Gateway API. Once cert-manager has stable ListenerSet support, you can plan a cleaner migration to Gateway API. Two smaller migrations might be less painful than one messy one.

If you can wait: The ecosystem should be in much better shape by mid-2026. cert-manager 1.20 with XListenerSet support, more implementations supporting ListenerSet, better documentation. If your current setup is tolerable, waiting is the lower-risk path.

If you need to migrate now: Accept that you’ll have a two-phase migration. Document your listener configurations well, so the refactor to ListenerSet is mechanical rather than archaeological. Consider using Kustomize or Helm to template your Gateway listeners if the list gets unwieldy.

If you’re starting fresh: Honestly, evaluate whether you actually need the Gateway API features today. If Ingress with your current controller works, there’s no shame in sticking with it. Gateway API is the future, but the present is a bit rough for multi-tenant cert-manager users.

The Bigger Picture

This situation is a good reminder that API design involves trade-offs. Gateway API’s separation of concerns is genuinely better for security and clarity than Ingress’s everything-in-one-resource model. The multi-tenancy friction is a growing pain, not a fundamental flaw.

The community is working on it. ListenerSet is progressing. cert-manager is adapting. In a year, this blog post will hopefully feel like a historical curiosity rather than current guidance.

Until then, we’re migrating with our eyes open, accepting some short-term awkwardness for long-term benefits. Sometimes that’s the right call.


If you’re navigating this migration and have questions, feel free to reach out. And if you’ve found clever workarounds I haven’t mentioned, I’d love to hear about them.