github.com/projectcontour/contour@v1.28.2/site/content/docs/v1.17.0/config/rate-limiting.md (about)

     1  # Rate Limiting
     2  
     3  - [Overview](#overview)
     4  - [Local Rate Limiting](#local-rate-limiting)
     5  - [Global Rate Limiting](#global-rate-limiting)
     6  
     7  ## Overview
     8  
     9  Rate limiting is a means of protecting backend services against unwanted traffic.
    10  This can be useful for a variety of different scenarios:
    11  
    12  - Protecting against denial-of-service (DoS) attacks by malicious actors
    13  - Protecting against DoS incidents due to bugs in client applications/services
    14  - Enforcing usage quotas for different classes of clients, e.g. free vs. paid tiers
    15  - Controlling resource consumption/cost
    16  
    17  Envoy supports two forms of HTTP rate limiting: **local** and **global**.
    18  
    19  In local rate limiting, rate limits are enforced by each Envoy instance, without any communication with other Envoys or any external service.
    20  
    21  In global rate limiting, an external rate limit service (RLS) is queried by each Envoy via gRPC for rate limit decisions.
    22  
    23  Contour supports both forms of Envoy's rate limiting.
    24  
    25  ## Local Rate Limiting
    26  
    27  The `HTTPProxy` API supports defining local rate limit policies that can be applied to either individual routes or entire virtual hosts.
    28  Local rate limit policies define a maximum number of requests per unit of time that an Envoy should proxy to the upstream service.
    29  Requests beyond the defined limit will receive a `429 (Too Many Requests)` response by default.
    30  Local rate limit policies program Envoy's [HTTP local rate limit filter][1].
    31  
    32  It's important to note that local rate limit policies apply *per Envoy pod*.
    33  For example, a local rate limit policy of 100 requests per second for a given route will result in *each Envoy pod* allowing up to 100 requests per second for that route.
    34  
    35  ### Defining a local rate limit
    36  
    37  Local rate limit policies can be defined for either routes or virtual hosts. A local rate limit policy requires a `requests` and a `units` field, defining the *number of requests per unit of time* that are allowed. `Requests` must be a positive integer, and `units` can be `second`, `minute`, or `hour`. Optionally, a `burst` parameter can also be provided, defining the number of requests above the baseline rate that are allowed in a short period of time. This would allow occasional larger bursts of traffic not to be rate limited.
    38  
    39  Local rate limiting for the virtual host:
    40  ```yaml
    41  apiVersion: projectcontour.io/v1
    42  kind: HTTPProxy
    43  metadata:
    44    namespace: default
    45    name: ratelimited-vhost
    46  spec:
    47    virtualhost:
    48      fqdn: local.projectcontour.io
    49      rateLimitPolicy:
    50        local:
    51          requests: 100
    52          unit: hour
    53          burst: 20
    54    routes:
    55    - conditions:
    56      - prefix: /s1
    57      services:
    58      - name: s1
    59        port: 80
    60    - conditions:
    61      - prefix: /s2
    62      services:
    63      - name: s2
    64        port: 80
    65  ```
    66  
    67  Local rate limiting for the route:
    68  ```yaml
    69  apiVersion: projectcontour.io/v1
    70  kind: HTTPProxy
    71  metadata:
    72    namespace: default
    73    name: ratelimited-route
    74  spec:
    75    virtualhost:
    76      fqdn: local.projectcontour.io
    77    routes:
    78    - conditions:
    79      - prefix: /s1
    80      services:
    81      - name: s1
    82        port: 80
    83      rateLimitPolicy:
    84        local:
    85          requests: 20
    86          unit: minute
    87    - conditions:
    88      - prefix: /s2
    89      services:
    90      - name: s2
    91        port: 80
    92  ```
    93  
    94  ### Customizing the response
    95  
    96  #### Response code
    97  
    98  By default, Envoy returns a `429 (Too Many Requests)` when a request is rate limited.
    99  A non-default response code can optionally be configured as part of the local rate limit policy, in the `responseStatusCode` field.
   100  The value must be in the 400-599 range.
   101  
   102  ```yaml
   103  apiVersion: projectcontour.io/v1
   104  kind: HTTPProxy
   105  metadata:
   106    namespace: default
   107    name: custom-ratelimit-response
   108  spec:
   109    virtualhost:
   110      fqdn: local.projectcontour.io
   111    routes:
   112    - conditions:
   113      - prefix: /s1
   114      services:
   115      - name: s1
   116        port: 80
   117      rateLimitPolicy:
   118        local:
   119          requests: 20
   120          unit: minute
   121          responseStatusCode: 503 # Service Unavailable 
   122  ```
   123  
   124  #### Headers
   125  
   126  Headers can optionally be added to rate limited responses, by configuring the `responseHeadersToAdd` field.
   127  
   128  ```yaml
   129  apiVersion: projectcontour.io/v1
   130  kind: HTTPProxy
   131  metadata:
   132    namespace: default
   133    name: custom-ratelimit-response
   134  spec:
   135    virtualhost:
   136      fqdn: local.projectcontour.io
   137    routes:
   138    - conditions:
   139      - prefix: /s1
   140      services:
   141      - name: s1
   142        port: 80
   143      rateLimitPolicy:
   144        local:
   145          requests: 20
   146          unit: minute
   147          responseHeadersToAdd:
   148          - name: x-contour-ratelimited
   149            value: "true"
   150  ```
   151  
   152  ## Global Rate Limiting
   153  
   154  The `HTTPProxy` API also supports defining global rate limit policies on routes and virtual hosts.
   155  
   156  In order to use global rate limiting, you must first select and deploy an external rate limit service (RLS).
   157  There is an [Envoy rate limit service implementation][2], but any service that implements the [RateLimitService gRPC interface][3] is supported.
   158  
   159  ### Configuring an external RLS with Contour
   160  
   161  Once you have deployed your RLS, you must configure it with Contour.
   162  
   163  Define an extension service for it (substituting values as appropriate):
   164  ```yaml
   165  apiVersion: projectcontour.io/v1alpha1
   166  kind: ExtensionService
   167  metadata:
   168    namespace: projectcontour
   169    name: ratelimit
   170  spec:
   171    protocol: h2
   172    services:
   173      - name: ratelimit
   174        port: 8081
   175  ```
   176  
   177  Now add a reference to it in the Contour config file:
   178  ```yaml
   179  rateLimitService:
   180    # The namespace/name of the extension service.
   181    extensionService: projectcontour/ratelimit
   182    # The domain value to pass to the RLS for all rate limit
   183    # requests. Acts as a container for a set of rate limit
   184    # definitions within the RLS.
   185    domain: contour
   186    # Whether to allow requests to proceed when the rate limit
   187    # service fails to respond with a valid rate limit decision
   188    # within the timeout defined on the extension service.
   189    failOpen: true
   190  ```
   191  
   192  ### Defining a global rate limit policy
   193  
   194  Global rate limit policies can be defined for either routes or virtual hosts. Unlike local rate limit policies, global rate limit policies do not directly define a rate limit. Instead, they define a set of request descriptors that will be generated and sent to the external RLS for each request. The external RLS then makes the rate limit decision based on the descriptors and returns a response to Envoy.
   195  
   196  A global rate limit policy for the virtual host:
   197  ```yaml
   198  apiVersion: projectcontour.io/v1
   199  kind: HTTPProxy
   200  metadata:
   201    namespace: default
   202    name: ratelimited-vhost
   203  spec:
   204    virtualhost:
   205      fqdn: local.projectcontour.io
   206      rateLimitPolicy:
   207        global:
   208          descriptors:
   209            # the first descriptor has a single key-value pair:
   210            # [ remote_address=<client IP> ].
   211            - entries:
   212                - remoteAddress: {}
   213            # the second descriptor has two key-value pairs:
   214            # [ remote_address=<client IP>, vhost=local.projectcontour.io ].
   215            - entries:
   216                - remoteAddress: {}
   217                - genericKey:
   218                    key: vhost
   219                    value: local.projectcontour.io
   220    routes:
   221    - conditions:
   222      - prefix: /s1
   223      services:
   224      - name: s1
   225        port: 80
   226    - conditions:
   227      - prefix: /s2
   228      services:
   229      - name: s2
   230        port: 80
   231  ```
   232  
   233  A global rate limit policy for the route:
   234  ```yaml
   235  apiVersion: projectcontour.io/v1
   236  kind: HTTPProxy
   237  metadata:
   238    namespace: default
   239    name: ratelimited-route
   240  spec:
   241    virtualhost:
   242      fqdn: local.projectcontour.io
   243    routes:
   244    - conditions:
   245      - prefix: /s1
   246      services:
   247      - name: s1
   248        port: 80
   249      rateLimitPolicy:
   250        global:
   251          descriptors:
   252            # the first descriptor has a single key-value pair:
   253            # [ remote_address=<client IP> ].
   254            - entries:
   255                - remoteAddress: {}
   256            # the second descriptor has two key-value pairs:
   257            # [ remote_address=<client IP>, prefix=/s1 ].
   258            - entries:
   259                - remoteAddress: {}
   260                - genericKey:
   261                    key: prefix
   262                    value: /s1
   263    - conditions:
   264      - prefix: /s2
   265      services:
   266      - name: s2
   267        port: 80
   268  ```
   269  
   270  #### Descriptors & descriptor entries
   271  
   272  A descriptor is a list of key-value pairs, i.e. entries, that are generated for a request. The entries can be generated based on different criteria. If any entry in a descriptor cannot generate a key-value pair for a given request, then the entire descriptor is not generated (see the [Envoy documentation][8] for more information). When a global rate limit policy defines multiple descriptors, then *all* descriptors that can be generated will be generated and sent to the rate limit service for consideration.
   273  
   274  Below are the supported types of descriptor entries.
   275  
   276  ##### GenericKey
   277  
   278  A `GenericKey` descriptor entry defines a static key-value pair. For example:
   279  
   280  ```yaml
   281  rateLimitPolicy:
   282    global:
   283      descriptors:
   284        - entries:
   285            - genericKey:
   286                key: virtual-host-name
   287                value: foo.bar.com
   288  ```
   289  
   290  Produces a descriptor entry of `virtual-host-name=foo.bar.com`.
   291  
   292  The `key` field is optional and defaults to a value of `generic_key` if not specified.
   293  
   294  See the [Envoy documentation][4] for more information and examples.
   295  
   296  ##### RemoteAddress
   297  
   298  A `RemoteAddress` descriptor entry has a key of `remote_address` and a value of the client IP address (using the trusted address from `x-forwarded-for`). For example:
   299  
   300  ```yaml
   301  rateLimitPolicy:
   302    global:
   303      descriptors:
   304        - entries:
   305            - remoteAddress: {}
   306  ```
   307  
   308  Produces a descriptor entry of `remote_address=<client IP>`.
   309  
   310  See the [Envoy documentation][5] for more information and examples.
   311  
   312  ##### RequestHeader
   313  
   314  A `RequestHeader` descriptor entry has a static key and a value equal to the value of a specified header on the client request. If the header is not present, the descriptor entry is not generated. For example:
   315  
   316  ```yaml
   317  rateLimitPolicy:
   318    global:
   319      descriptors:
   320        - entries:
   321            - requestHeader:
   322                headerName: My-Header
   323                descriptorKey: my-header-value
   324  ```
   325  
   326  Produces a descriptor entry of `my-header-value=<value of My-Header>`, for a client request that has the `My-Header` header.
   327  
   328  See the [Envoy documentation][6] for more information and examples.
   329  
   330  ##### RequestHeaderValueMatch
   331  
   332  A `RequestHeaderValueMatch` descriptor entry has a key of `header_match` and a static value. The entry is only generated if the client request's headers match a specified set of criteria. For example:
   333  
   334  ```yaml
   335  rateLimitPolicy:
   336    global:
   337      descriptors:
   338        - entries:
   339            - requestHeaderValueMatch:
   340                headers:
   341                  - name: My-Header
   342                    notpresent: true
   343                  - name: My-Other-Header
   344                    contains: contour
   345                expectMatch: true
   346                value: foo
   347  ```
   348  
   349  Produces a descriptor entry of `header_match=foo`, for a client request that does not have the `My-Header` header, and does have the `My-Other-Header` header, with a value containing the substring "contour".
   350  
   351  Contour supports `present`, `notpresent`, `contains`, `notcontains`, `exact`, and `notexact` header match operators.
   352  
   353  The `expectMatch` field defaults to true if not specified. If true, the client request's headers must positively match the specified criteria in order for the descriptor entry to be generated. If false, the client request's header must *not* match the specified criteria in order for the descriptor entry to be generated.
   354  
   355  See the [Envoy documentation][7] for more information and examples.
   356  
   357  
   358  
   359  [1]: https://www.envoyproxy.io/docs/envoy/v1.17.0/configuration/http/http_filters/local_rate_limit_filter#config-http-filters-local-rate-limit
   360  [2]: https://github.com/envoyproxy/ratelimit
   361  [3]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/ratelimit/v3/rls.proto
   362  [4]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-msg-config-route-v3-ratelimit-action-generickey
   363  [5]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#config-route-v3-ratelimit-action-remoteaddress
   364  [6]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#config-route-v3-ratelimit-action-requestheaders
   365  [7]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#config-route-v3-ratelimit-action-headervaluematch
   366  [8]: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/rate_limit_filter#composing-actions