envoyproxy / envoy

Cloud-native high-performance edge/middle/service proxy
https://www.envoyproxy.io
Apache License 2.0
24.99k stars 4.81k forks source link

LocalRateLimiter with dynamic descriptor values #19895

Open kiran-bjn opened 2 years ago

kiran-bjn commented 2 years ago

I have setup a localRateLimiter Filter on the route level . I am trying to configure the rateLimiter such that the limits are applied based on the remote-address or an Auth token passed in the request header. Eg: For a particular API path /foo, Allow 5 reqs per min per token or remoteAddress. Although I could configure this with the GlobalRateLimiter, despite digging through the documentation multiple times, I am not able to find a relevant configuration to achieve this with the localRateLimiter.

LocalRateLimitConfig

         route:
            rate_limits:
              - actions:
                  - request_headers:
                      descriptor_key: AuthToken
                      header_name: Authorization
              - actions:
                  - header_value_match:
                      descriptor_value: quote-path-auth
                      expect_match: false
                      headers:
                        - name: Authorization
          typed_per_filter_config:
            envoy.filters.http.local_ratelimit:
              '@type': type.googleapis.com/udpa.type.v1.TypedStruct
              type_url: >-
                type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
              value:
                descriptors:
                  - entries:
                      - key: AuthToken
                   //   - value: x-auth-xxx
                   //     -rate_limit:
                   //            requests_per_unit: 10
                   //            unit: minute  
                    token_bucket:
                      fill_interval: 20s
                      max_tokens: 2
                      tokens_per_fill: 2
                  - entries:
                      - key: header_match
                        value: quote-path-auth
                    token_bucket:
                      fill_interval: 20s
                      max_tokens:5
                      tokens_per_fill: 5
                filter_enabled:
                  default_value:
                    denominator: HUNDRED
                    numerator: 100
                  runtime_key: local_rate_limit_enabled
                filter_enforced:
                  default_value:
                    denominator: HUNDRED
                    numerator: 100
                  runtime_key: local_rate_limit_enforced
                local_rate_limit_per_downstream_connection: false
                response_headers_to_add:
                  - append: false
                    header:
                      key: x-local-rate-limit
                      value: 'true'
                stat_prefix: http_local_rate_limiter
                token_bucket:
                  fill_interval: 20s
                  max_tokens: 1000
                  tokens_per_fill: 1000

Using the following struct provided for the globalRateLimiter Config throws an invalid descriptor error.

Does Envoy not support dynamic values for LocalRateLimiter descriptors .. ??

Documentation Reference : https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/local_rate_limit_filter#using-rate-limit-descriptors-for-local-rate-limiting

htuch commented 2 years ago

@junr03 @mattklein123

kiran-bjn commented 2 years ago

Hi @junr03 @mattklein123 , can U answer this please.

mattklein123 commented 2 years ago

This is basically the same issue as https://github.com/envoyproxy/envoy/issues/19685. I think we should probably also support the substitution formatter for dynamic descriptor values. cc @kyessenov

kyessenov commented 2 years ago

I think you can use the expression rate limit action extension for dynamic values. We can add substitution formatter, too, as another extension.

We should document this better. I could only find some test case here https://github.com/istio/proxy/blob/master/test/envoye2e/ratelimit/ratelimit_test.go#L41.

sseetharaman6 commented 2 years ago

I have a similar issue - I want to be able to set a default rate limit for each client and configure special rate limits for some clients. I am trying to using local rate limit + descriptors as in this example.
I am able to populate the relevant client info in the request header using lua filter , however the descriptor entries are throwing me off. Is there a way to specify that each unique client gets x tokens with local rate limit, without statically configuring it for each client? I am not sure how to go about setting the value in the descriptor entry for this scenario. For special clients, I can explicitly set the value to match the client info.

kyessenov commented 2 years ago

No, there is no way to add dynamic buckets with local rate limiter AFAICT. You might need some global rate limit with quotas for that.

ns-asriram commented 2 years ago

I seem to be having a similar issue as @sseetharaman6 here. Only that I am trying to define local rate limit to throttle requests based on PATH.

Note: I was able to get this working using the global rate limits.

The URIs are in the form /{id}/send where I am looking to assign 'x' tokens for each such "id" PATH. Since the number of ids is huge and not static, it is not feasible to define descriptor entries for each PATH.

I have raised #38008 highlighting the configurations that I have tried.

I see that the feature referenced in this issue (#19685 ) is specific to the Network Rate Limiter, I was wondering if someone can provide me with cues to realise my use-case.

sreekanth-bg commented 2 years ago

@ns-asriram how were you able to achieve this using global rate limits? ie rate limiting based on the {id} which is in the URL?