kubernetes-sigs / gateway-api

Repository for the next iteration of composite service (e.g. Ingress) and load balancing APIs.
https://gateway-api.sigs.k8s.io
Apache License 2.0
1.86k stars 482 forks source link

Support DirectResponse HTTPRouteFilter #2826

Open arkodg opened 9 months ago

arkodg commented 9 months ago

What would you like to be added:

A new HTTPRouteFilter that allows users to directly respond to requests with a specific body and status w/o sending it to a backend.

Existing implementations that have this feature Istio - https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPDirectResponse Contour https://projectcontour.io/docs/1.28/config/api/#projectcontour.io/v1.HTTPDirectResponsePolicy

Why this is needed:

howardjohn commented 9 months ago

Obviously Istio has this as you noted, so I am in favor of this, but just want to note its a tricky tradeoff of how big we allow. Good for simple "return 404" but anything more complex becomes a bit dicey

youngnick commented 9 months ago

Yes, I think that anything we add will need to have a strict limit about size. And an explanation that no, we really won't increase the limit.

lianglli commented 8 months ago

Why this is needed:

For example, some hosts want to disable crawl any of the website's pages. If the request path is "/robots.txt", the gateway will return 200 OK with body "User-agent: * Disallow: /".

Based on the following HTTPRoute, the host "http.route.robots.com" with path "/robots.txt" will be disallowed always.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-route-cookie
spec:
  hostnames:
  - http.route.robots.com
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: http-gateway
  rules:
  - backendRefs:
    - kind: Service 
       name: http-route-production
       port: 7001
    matches:
    - path:
         type: PathPrefix
         value: /
  - directResponse:
    - status: 200
       body: 
         string: "User-agent: *\nDisallow: /"
    matches:
    - path:
         type: Exact
         value: /robots.txt
lianglli commented 8 months ago

Why this is needed:

Moreover, if there is a L7 attack, the directResponse will return 404 based on a new HTTPRoute asap.

Then, the upstream service will be able to process the normal requests without any changes.

E.g., upstream service "http-route-production" try to add a HTTPRoute for protecting it against L7 attack ("http.route.com/acs") specifically:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-route-cookie
spec:
  hostnames:
  - http.route.com
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: http-gateway
  rules:
  - backendRefs:
    - kind: Service 
       name: http-route-production
       port: 7001
    matches:
    - path:
         type: PathPrefix
         value: /
  - directResponse:
    - status: 404
    matches:
    - path:
         type: Exact
         value: /acs
lianglli commented 8 months ago

Yes, I think that anything we add will need to have a strict limit about size. And an explanation that no, we really won't increase the limit.

Yes, it is. The directResponse should be a response with small body or no body.

E.g.,

// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=128
Value string `json:"value"`
NissesSenap commented 7 months ago

I also have a use-case for this. I have an application with x number of paths, and I want all of them to be exposed to the internet except 1.

Today I can write a httpRoute with rules.matches.pathto whitelist all paths I want to be available, but this becomes very boring if I have an app with a long list of paths. So instead of doing whitelist/allowlist, I would like to be able to do blacklist/blocklist.

For example:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: echo
spec:
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: http-gateway
  rules:
    - directResponse:
      - status: 404
      matches:
      - path:
           type: Exact
           value: /secretPath
    - backendRefs:
        - name: echo
          kind: Service
          port: 1027
lianglli commented 7 months ago

I also have a use-case for this. I have an application with x number of paths, and I want all of them to be exposed to the internet except 1.

Today I can write a httpRoute with rules.matches.pathto whitelist all paths I want to be available, but this becomes very boring if I have an app with a long list of paths. So instead of doing whitelist/allowlist, I would like to be able to do blacklist/blocklist.

For example:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: echo
spec:
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: http-gateway
  rules:
    - directResponse:
      - status: 404
      matches:
      - path:
           type: Exact
           value: /secretPath
    - backendRefs:
        - name: echo
          kind: Service
          port: 1027

The directResponse of HTTPRouteFilter is able to fit your requirement.

I'm working on a GEP for directResponse that focuses on background and past implementations first.

lianglli commented 7 months ago

/assign @lianglli

k8s-triage-robot commented 4 months ago

The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:

You can:

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle stale

jbohanon commented 4 months ago

/remove-lifecycle stale

jbohanon commented 4 months ago

@lianglli were you able to make any progress on a GEP for this feature?

lianglli commented 3 months ago

@lianglli were you able to make any progress on a GEP for this feature?

Yes, I will create a GEP firstly.

youngnick commented 3 months ago

As for other Provisional GEPs, the critical parts are What this is, Why we need it, and Who it's for, along with what is currently supported in various data planes and/or implementations. Would love to see a Provisional GEP PR like that.

lianglli commented 3 months ago

Yes, get it.

gganley commented 2 months ago

Per suggestion by Mike Morris in the Istio slack I'd like to add my use case

Right now we're moving from VMs fronted by HAProxy to K8s using K8s G8way + Istio (plus other stuff). One of the hang ups I've encountered in trying to recreate our existing behavior is the lack errorfile directive in haproxy or return in nginx. This allows an inline of an error code and a body. To recreate this in the existing k8s gateway api I need to create a null-backend service whose only job is to act as the backend to return 403 "<html><body><h1>\n403 Forbidden</h1>Request forbidden by administrative rules.\n</body></html>\n"

frontend fe_https
    default_backend null
    # lots of acls either http-request deny or allowing to specific backends
    acl deny path_beg /edge/api/internal
    acl api_backend path_beg /edge/api
    http-request deny if deny
    use_backend api if api_backend

backend api
    server edge-api ...

backend null
    errorfile 403 /usr/local/etc/haproxy/403.http
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: translation
spec:
  parentRefs:
  - name: external
  rules:
  - matches: # deny
    - path:
        type: PathPrefix
        value: /edge/api/internal
    filters:
    - type: DirectResponse
      directResponse:
        statusCode: 403
        body:
          string: "Finger wag"
  - matches: # api
    - path:
        type: PathPrefix
        value: /edge/api
    backendRefs:
    - name: edge-api
      port: 8080
  - filters: # default_backend
    - type: DirectResponse
      directResponse:
        statusCode: 403
        body:
          string: "Finger wag"
bravenut commented 2 months ago

@gganley we have a very similar use case and I would also appreciate the direct response filter within HTTPRoute a lot. Instead of using a custom service that returns arbitrary responses, we're applying an Envoy filter custom resource to the gateway, where you can simply patch the route configuration to use the direct response, works like a charm, but it would be nice to accomplish this without additional overhead and just configure it in the HTTPRoute.

AhmadMS1988 commented 1 month ago

Such feature can be helpful for two use cases:

  1. API sunsetting without modifying applications
  2. The need of returning dummy fixed response for network or ingress health checking from external. Thank you
arkodg commented 1 week ago

Envoy Gateway just added this as a filter in v1.2, here's an example