envoyproxy / ratelimit

Go/gRPC service designed to enable generic rate limit scenarios from different types of applications.
Apache License 2.0
2.25k stars 440 forks source link

Rate limiting for different IPs in different endpoints not working #653

Closed bignyap closed 1 month ago

bignyap commented 1 month ago

Title: Rate limiting for different IPs in different endpoints

I can not make envoy to use the ratelimiter as intended with the following setup for ratelimit, envoy and compose. Is there anything I am missing? The goal is to allow a certain ip on /api endpoint to have unlimited access and for other endpoints, we can have the same rule for all ips.

config.yaml for envoyproxy/ratelimit:

domain: edge_proxy_per_ip
descriptors:
  # Descriptor for the specific IP address with unlimited access to the /api endpoint
  - key: remote_address
    value: <some-ip-address>
    descriptors:
      - key: api_path
        value: "/api"
        rate_limit:
          unlimied: true

  - key: remote_address
    descriptors:
    - key: api_path
      value: "/api"
      rate_limit:
        unit: minute
        requests_per_unit: 100

    - key: default_path
      value: "/"
      rate_limit:
        unit: minute
        requests_per_unit: 500

envoy.yaml

static_resources:

  listeners:
  - name: http
    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.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: "/"
                redirect:
                  https_redirect: true

  - name: internal
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 8443

    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_internal

          use_remote_address: true
          skip_xff_append: false

          access_log:
          - name: envoy.access_loggers.stdout
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog

          http_filters:
            - 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:
                  path_separated_prefix: "/auth"
                route:
                  append_x_forwarded_host: true
                  cluster: service_idp
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          common_tls_context:
            tls_certificates:
            - certificate_chain:
                filename: /tls.crt
              private_key:
                filename: /tls.key

  - name: public
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 443

    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_public

          use_remote_address: true
          skip_xff_append: false

          access_log:
          - name: envoy.access_loggers.stdout
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog

          http_filters:

            - name: envoy.filters.http.ratelimit
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
                domain: edge_proxy_per_ip
                request_type: external
                stage: 0
                rate_limited_as_resource_exhausted: true
                failure_mode_deny: false
                enable_x_ratelimit_headers: DRAFT_VERSION_03
                rate_limit_service:
                  grpc_service:
                    envoy_grpc:
                      cluster_name: ratelimit
                  transport_api_version: V3

            - 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:
                  path_separated_prefix: "/api"
                route:
                  cluster: service_wwe
                  rate_limits:
                  - actions:
                    - request_headers:
                        header_name: x-forwarded-for
                        descriptor_key: remote_address

              - match:
                  prefix: "/"
                route:
                  cluster: service_fe
                  rate_limits:
                  - actions:
                    - request_headers:
                        header_name: x-forwarded-for
                        descriptor_key: remote_address

      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          common_tls_context:
            tls_certificates:
            - certificate_chain:
                filename: /tls.crt
              private_key:
                filename: /tls.key

  clusters:
  - name: service_wwe
    type: LOGICAL_DNS
    load_assignment:
      cluster_name: service_wwe
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: wwe
                port_value: 8080

  - name: service_ratelimit
    type: LOGICAL_DNS
    load_assignment:
      cluster_name: service_ratelimit
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: ratelimit
                port_value: 8081

compose file for ratelimit service

ratelimit:
    image: envoyproxy/ratelimit:master
    command: /bin/ratelimit
    environment:
      USE_STATSD: 'false'
      REDIS_HEALTH_CHECK_ACTIVE_CONNECTION: 'true'
      HEALTHY_WITH_AT_LEAST_ONE_CONFIG_LOADED: 'true'
      LOG_LEVEL: 'debug'
      REDIS_SOCKET_TYPE: 'tcp'
      REDIS_URL: 'redis:6379'
      RUNTIME_ROOT: '/data'
      RUNTIME_SUBDIRECTORY: 'ratelimit'
      RUNTIME_APPDIRECTORY: 'config'
      RUNTIME_WATCH_ROOT: 'false'
      CONFIG_TYPE: '${CONFIG_TYPE:-FILE}'
    ports:
      - 8080:8080
      - 8081:8081
      - 6070:6070
    volumes:
      - ./ratelimiter:/data/ratelimit/config
    depends_on:
      redis:
        condition: service_healthy

[optional Relevant Links:]

Any extra documentation required to understand the issue.

bignyap commented 1 month ago

I was able to resolve this. Redefined the route rate_limiter by going through envoy's official documentation and also the config.yaml file for envoyproxy/ratelimit. Working now.