Skip to content

Add redirect loop protection to HTTPRequestRedirect #1185

@rainest

Description

@rainest

What would you like to be added:
I want the HTTPRequestRedirect to include language indicating how implementations handle redirects that result in loops, where the request URL received is equal to the request URL returned by the filter.

I propose that the spec be amended to include something like

If the result of applying an HTTPRequestRedirect would be a response whose Location header value matches the original request URL, implementations MUST NOT return the redirect request, and MUST instead proxy the request upstream.

Is this behavior desirable, and can implementations honor it easily?

Why this is needed:
https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.HTTPRequestRedirectFilter defines an HTTPRoute Filter for issuing HTTP redirects in response that match a set of criteria. My strictest interpretation of the spec is that implementations must honor these absolutely: there are no matching criteria other than the HTTPRoute itself, and if a request matches that HTTPRoute, the implementation must issue the redirect.

Because the redirect filter applies to any matching request, you can easily configure HTTPRoutes that will result in a redirect loop: clients will send a request with some URL, receive a redirect response directing them to the same URL, send a new request to that URL, and receive another redirect to the same URL ad infinitum. For example, this HTTPRoute performs an HTTP->HTTPS redirect for any request to the redirect.example domain:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
  name: http-filter-redirect
spec:
  hostnames:
    - redirect.example
  rules:
    - filters:
      - type: RequestRedirect
        requestRedirect:
          scheme: https
          statusCode: 301

With the naive implementation above, attaching this HTTPRoute to a Gateway with both HTTP and HTTPS Listeners would result in a loop: http://example.redirect/ will be redirected to https://example.redirect and https://example.redirect will also be redirected, back to itself, indefinitely.

AFAIK to avoid this you'd need to create separate HTTPRoutes, one with the redirect and one without, and either bind them to separate Gateways or use a combination of allowedRoutes configuration and namespaced backendRefs to bind them to only one Listener on a single Gateway. I may have overlooked something here, but I don't see another way to ensure they don't collide. I am not aware of any reason users would want to configure a redirect loop, since HTTP-compliant clients will never receive a useful response from a looping URL, so I believe the strict interpretation of the current spec only needlessly complicates configuration.

While HTTP->HTTPS redirects are probably the most common case where sensible configuration will result in a loop, this problem is generic to any redirect configuration: a regex path match that redirects /foo/* to /foo/example will also loop indefinitely, since /foo/example matches the expression. The proposed change avoids loops regardless of the redirect type.

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/featureCategorizes issue or PR as related to a new feature.lifecycle/rottenDenotes an issue or PR that has aged beyond stale and will be auto-closed.priority/backlogHigher priority than priority/awaiting-more-evidence.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions