coupergateway / couper

Couper is a lightweight API gateway designed to support developers in building and operating API-driven Web projects
https://couper.io
MIT License
84 stars 15 forks source link

rate limiter as access control #809

Open johakoch opened 6 months ago

johakoch commented 6 months ago

We could implement a rate limiter as an access control, e.g.:

server {
  api {
    access_control = ["global_rl", "at", "jwt_rl"]
    ...
  }
}

definitions {
  rate_limiter "global_rl" {
    period_window = "sliding" # or "fixed" or ?
    period = "1s"
    per_period = 1000
  }

  jwt "at" {
    ...
  }

  rate_limiter "jwt_rl" {
    period = "1s"
    per_period = 1
    key = request.context.at.sub
  }
}

It could be handy to add more request. sub-properties, e.g. from go Request.RemoteAddr if available.

filex commented 6 months ago

I like the idea. How would you define the order? We could inspect expressions (especially those using request.context), like we do to order request sequences. Or would you use the order of references in the access_control list?

johakoch commented 6 months ago

Or would you use the order of references in the access_control list?

I guess that's the order in which access controls are (already) applied.

malud commented 6 months ago

I would apply the ordered list - no magic reordering.

Should we reply with some additional headers like https://github.com/sashabaranov/go-openai/blob/master/ratelimit.go#L10 ? This could also be interesting for our BE limiters.

johakoch commented 6 months ago

Should we reply with some additional headers like https://github.com/sashabaranov/go-openai/blob/master/ratelimit.go#L10 ? This could also be interesting for our BE limiters.

See also

filex commented 6 months ago

Let's start with a simple implementation that just uses status 429 to communicate current overuse.

filex commented 6 months ago

The key in the proposal is the "key" feature :).

Without it, rate limiting is almost useless. We could even make it a mandatory field.

Is it worth to provide a non-dynamic alternative to the key (which has to be evaluated in cty land) to be more efficient or make typical use-cases simpler? Example:

by_header = "API-Key"
by_client_ip = true

Anyways, we can start with the dynamic key and introduce those optimized shortcuts later once typical use is clear.