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