Skip to content

Build1 publisher3 min readPublished

Porting OAuth2 Proxy to Gateway API moves the login redirect into a Traefik-specific CRD

A guide rebuilding browser OIDC login off ingress-nginx keeps its Gateway and HTTPRoute objects intact and hands the 401-to-302 step to two Traefik middlewares. Swap the controller and that half gets rewritten.

The Engineer · Build desk

Illustration accompanying Porting OAuth2 Proxy to Gateway API moves the login redirect into a Traefik-specific CRD

What happened

  • A guide that previously put internal Kubernetes services behind OAuth2 Proxy with ingress-nginx annotations rebuilds the same authentication flow on Gateway API with Traefik, OAuth2 Proxy and Pocket ID.
  • Traefik runs with two providers enabled at once: the Gateway API provider for the standard routing objects, and the Kubernetes CRD provider for the authentication middleware.
  • Three HTTPS hostnames sit under one parent domain, one each for the Pocket ID issuer, the OAuth2 Proxy endpoints and the protected demo service.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Portability stops at the auth filter. A later move to Envoy Gateway, Kong or Cilium transfers the Gateway and HTTPRoute objects untouched and re-opens the login layer for rework.
  • decision Choosing a Gateway implementation is also choosing the login adapter, and the vendor CRD provider that Gateway API was meant to displace has to stay switched on to serve it.
  • exposure The cookie domain is a security boundary here. Set it at a wide parent and every unrelated application under that parent receives the shared session cookie.
  • cost OAuth2 Proxy becomes a sizing and availability item for the gateway path, because every protected request pays a ForwardAuth call to it and each cold login pays four requests.

The redirect is the piece that has to be rebuilt. ForwardAuth calls `/oauth2/auth`, and that endpoint only checks a session: it answers 202 when the cookie is valid and 401 when it is not [4]. Traefik's `Errors` middleware catches the 401 and sends the browser to `/oauth2/sign_in?rd=...` [5]. The guide's author wrote: "That separate redirect step is the most important difference from the old ingress-nginx annotations." [6]

Two Traefik providers are on at once. The Helm install sets `providers.kubernetesGateway.enabled=true` for the standard objects [7], and the Kubernetes CRD provider stays enabled because the authentication middleware is a Traefik CRD [8]. Gateway API's standard channel, installed here from the v1.6.1 manifest [9], ships the stable `GatewayClass`, `Gateway` and `HTTPRoute` APIs [10]. Browser OIDC login and an external-auth filter are not among them [3].

Gateway is routing configuration; Traefik is the process that accepts the traffic, and the `Gateway` resource does not create the external listener by itself [11]. The address comes from Traefik's Service: type `LoadBalancer` on a managed cluster, MetalLB or an existing external load balancer on bare metal [12]. DNS for `*.k8s.example.com` points at whatever endpoint terminates that HTTPS traffic, and the guide checks the Service has an address before the record is added [13].

Count the exchanges in the published sequence diagram and OAuth2 Proxy handles four requests before the `whoami` backend sees anything: the first `/oauth2/auth` returning 401, the sign-in start, the callback carrying the authorization code, and the second `/oauth2/auth` returning 202 with identity headers [20]. Pocket ID authenticates the user with a passkey in between [19]. Once the session cookie exists, each request costs one ForwardAuth call [20]. That call is on the path of every protected request.

The flow was verified on a local K3s cluster, using standard kubectl and Helm commands the author says are not tied to that environment [16]. The parts that differ elsewhere are traffic entry and certificates: the guide assumes cert-manager and a `ClusterIssuer` named `letsencrypt-prod` already exist, and both the login callback and the session cookie need HTTPS [17]. Cookie scope is the other setting to get right locally. Three hostnames under one parent domain let OAuth2 Proxy share a narrowly scoped session cookie such as `.k8s.example.com`, and the guide tells you not to widen that domain when unrelated applications sit under it [14][15].

In my view this is the right trade where Traefik is already the gateway: the routing objects become portable and two middlewares are the bill. Teams on Envoy Gateway, Kong or Cilium keep the same `Gateway` and `HTTPRoute` and change the authentication adapter [18]. The guide does not measure what that change costs on any of those three.

What to watch

  • Whether Envoy Gateway, Kong or Cilium publish an equivalent OIDC login flow that leaves the HTTPRoute objects untouched.
  • Whether a later Gateway API release standardises an external-auth filter; the standard channel installed here ships only GatewayClass, Gateway and HTTPRoute.
  • Whether the flow gets verified beyond a local K3s cluster, on a managed cluster where a LoadBalancer Service is the traffic entry.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories