Search code examples
envoyproxy

How can I set an envoy local rate limit, on all the paths starting with a given path?


How can I set an envoy local rate limit, on all the paths starting with a given path?

eg: I want to enforce the same rate limit on the URLs starting with : /swagger-ui/...

I've tried a couple of things, including passing a regex in the path: ^/swagger-ui/.*$ but nothing seems to work.

Thanks

My envoy yaml file looks like this:

static_resources:
  listeners:
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 80
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          codec_type: AUTO
          stat_prefix: ingress_http
          http_filters:
          - name: envoy.filters.http.local_ratelimit
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
              stat_prefix: http_local_rate_limiter
              local_rate_limit_per_downstream_connection: false
              filter_enabled:
                runtime_key: test_enabled
                default_value:
                  numerator: 100
                  denominator: HUNDRED
              filter_enforced:
                runtime_key: test_enforced
                default_value:
                  numerator: 100
                  denominator: HUNDRED
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains: ["*"]
              routes:
              - match: { prefix: "/"}
                route: 
                  cluster: middleware
                  timeout: { seconds: 120 }
                  rate_limits:
                  - actions: # any actions in here
                    - request_headers:
                        header_name: ":path"
                        descriptor_key: path
                typed_per_filter_config:
                  envoy.filters.http.local_ratelimit:
                    "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
                    stat_prefix: test
                    token_bucket:
                      max_tokens: 300
                      tokens_per_fill: 1
                      fill_interval: 600s
                    filter_enabled:
                      runtime_key: test_enabled
                      default_value:
                        numerator: 100
                        denominator: HUNDRED
                    filter_enforced:
                      runtime_key: test_enforced
                      default_value:
                        numerator: 100
                        denominator: HUNDRED
                    descriptors:
                    - entries:
                      - key: path
                        value: /swagger-ui/
                      token_bucket:
                        max_tokens: 15
                        tokens_per_fill: 1
                        fill_interval: 600s
                    - entries:
                      - key: path
                        value: /user/create
                      token_bucket:
                        max_tokens: 3
                        tokens_per_fill: 1
                        fill_interval: 600s

  clusters:
  - name: middleware
    connect_timeout: 1s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: middleware
      endpoints:
        - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: middleware
                    port_value: 8080
admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8001 

Solution

  • You need to define two routes (in route_config.virtual_hosts[0].routes):

    • one for /swagger-ui/* (prefix: /swagger-ui/)
    • one for all your other paths-prefix: /)

    Then, configure the local rate limit to only apply to the first route (paths starting with /swagger-ui/).

    Here is a working configuration:

    static_resources:
      listeners:
      - address:
          socket_address:
            address: 0.0.0.0
            port_value: 80
        filter_chains:
        - filters:
          - name: envoy.filters.network.http_connection_manager
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
              stat_prefix: ingress_http
              http_filters:
              - name: envoy.filters.http.local_ratelimit
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
                  stat_prefix: http_local_rate_limiter
              - name: envoy.filters.http.router
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
              route_config:
                name: local_route
                virtual_hosts:
                - name: local_service
                  domains: ["*"]
                  routes:
                  - match: { prefix: "/swagger-ui/" }
                    route: { cluster: middleware }
                    typed_per_filter_config:
                      envoy.filters.http.local_ratelimit:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
                        stat_prefix: http_local_rate_limiter
                        token_bucket:
                          max_tokens: 10
                          tokens_per_fill: 1
                          fill_interval: 10s
                        filter_enabled:
                          runtime_key: local_rate_limit_enabled
                          default_value:
                            numerator: 100
                            denominator: HUNDRED
                        filter_enforced:
                          runtime_key: local_rate_limit_enforced
                          default_value:
                            numerator: 100
                            denominator: HUNDRED
                        response_headers_to_add:
                          - append: false
                            header:
                              key: x-local-rate-limit
                              value: 'true'
                  - match: { prefix: "/" }
                    route: { cluster: middleware }
      clusters:
      - name: middleware
        connect_timeout: 1s
        type: STRICT_DNS
        dns_lookup_family: V4_ONLY
        lb_policy: ROUND_ROBIN
        load_assignment:
          cluster_name: middleware
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: middleware
                    port_value: 8080
    

    You can configure the rate limit values according to your needs.

    The config above is inspired from the official documentation: https://github.com/envoyproxy/envoy/blob/9347baf/docs/root/configuration/http/http_filters/_include/local-rate-limit-route-specific-configuration.yaml.