Rate Limiting in Ambassador Edge Stack
The Basic Configuration Objects
Rate limits in Ambassador Edge Stack are composed of two parts:
- Labels applied to requests (a label is basic metadata that is used by the rate limiting service).
RateLimits
that set limits based on the labels in the request
Labels
Edge Stack supports three types of labels:
generic_key
which is a simple stringremote_address
which is the value of the client IP address, assuming the load balancer configuration is set correctly- a custom type that can forward the value of a header to Ambassador for rate limiting
Global vs service-level rate limits
Edge Stack supports both global and service-level rate limits via two different labeling mechanisms.
- Labels applied in the
ambassador
Module are "global" and applied to every single request that goes through Ambassador; these labels are typically managed by operations - Labels applied at the
Mapping
are at the service-level and applied only to the requests that use thatMapping
An example service-level rate limit
The following Mapping
resource will add the {"generic_key": "default_generic_key_label"}
to every request to the foo-app
service:
---apiVersion: getambassador.io/v2kind: Mappingmetadata:name: foo-appspec:prefix: /foo/service: foolabels:ambassador:- label_group:- foo-app_generic_key_label
You can then create a default rate limit on every request that matches this label:
---apiVersion: getambassador.io/v2kind: RateLimitmetadata:name: default-rate-limitspec:domain: ambassadorlimits:- pattern: [{generic_key: "default_generic_key_label"}]rate: 10unit: minute
Tip: For testing purposes, it is helpful to configure per-minute rate limits before switching the rate limits to per second or per hour.
Request Labels
Mappings can have multiple labels
which annotate a given request.
---apiVersion: getambassador.io/v2kind: Mappingmetadata:name: catalogspec:prefix: /catalog/service: cataloglabels:ambassador:- string_request_label: # a specific request label group- catalog # annotate the request with the string `catalog`- header_request_label:- headerkey: # The name of the labelheader: ":method" # annotate the request with the specific HTTP method usedomit_if_not_present: true # if the header is not present, omit the label- multi_request_label_group:- authorityheader:header: ":authority"omit_if_not_present: true- xuserheader:header: "x-user"omit_if_not_present: true
Let's digest the above example:
- Request labels must be part of the
ambassador
label domain. - Each label must have a name, e.g.,
one_request_label
- The
string_request_label
simply adds the stringcatalog
to every incoming request to the given mapping. The string is referenced with the keygeneric_key
. - The
header_request_label
adds a specific HTTP header value to the request, in this case, the method. Note that HTTP/2 request headers must be used here (e.g., thehost
header needs to be specified as the:authority
header). - Multiple labels can be part of a single named label, e.g.,
multi_request_label
specifies two different headers to be added - When an HTTP header is not present, the entire named label is omitted. The
omit_if_not_present: true
is an explicit notation to remind end-users of this limitation.false
is not a supported value.
Ambassador Edge Stack supports several special labels:
remote_address
automatically populates the remote IP address using the trusted IP address fromX-Forwarded-For
request_headers: HEADER
will extract the value from a given HTTP headerdestination_cluster
populates the name of the Envoy cluster. Typically, there is a 1:1 correspondence between aservice
in aMapping
to adestination_cluster
. You can get the name of the cluster from the diagnostics service.source_cluster
populates the name of the originating cluster (e.g., the Envoy listener).
Note: In Envoy, labels are referred to as descriptors.
Grouping
Labels can be grouped. This allows for a single request to count against multiple different RateLimit
resources. For example, imagine the following scenario:
- Users should be limited on the total number of requests that can be sent to a set of endpoints
- On a specific service, stricter limits are desirable
The following Mapping
resources could be configured:
---apiVersion: getambassador.io/v2kind: Mappingmetadata:name: foo-appspec:prefix: /foo/service: foolabels:ambassador:- foo-app_label_group:- foo-app- total_requests_group:- remote_address---apiVersion: getambassador.io/v2kind: Mappingmetadata:name: bar-appspec:prefix: /bar/service: barlabels:ambassador:- bar-app_label_group:- bar-app- total_requests_group:- remote_address
Now requests to the foo-app
and the bar-app
would be labeled with {{"generic_key": "foo-app"},{"remote_address", 10.10.11.12}} and {{"generic_key": "bar-app"},{"remote_address", 10.10.11.12}}, respectively. Rate limits on these two services could be created as such:
---apiVersion: getambassador.io/v2kind: RateLimitmetadata:name: foo-rate-limitspec:domain: ambassadorlimits:- pattern: [{generic_key: "foo-app"}]rate: 10unit: second---apiVersion: getambassador.io/v2kind: RateLimitmetadata:name: bar-rate-limitspec:domain: ambassadorlimits:- pattern: [{generic_key: "bar-app"}]rate: 20unit: second---apiVersion: getambassador.io/v2kind: RateLimitmetadata:name: user-rate-limitspec:domain: ambassadorlimits:- pattern: [{remote_address: "*"}]rate: 100unit: minute
Global labels and groups
Global labels are prepended to every single label group. In the above example, if the following global label was added in the ambassador
Module:
—--apiVersion: getambassador.io/v2kind: Modulemetadata:name: ambassadorspec:config:default_label_domain: ambassadordefault_labels:ambassador:defaults:- default
The labels metadata would change from: {{"generic_key": "foo-app"},{"remote_address", 10.10.11.12}}
and
{{"generic_key": "bar-app"},{"remote_address", 10.10.11.12}}
to:
{{"generic_key": "default", "generic_key": "foo-app"},{"generic_key": "default", "remote_address", 10.10.11.12}}
and
{{"generic_key": "default", "generic_key": "bar-app"},{"generic_key": "default", "remote_address", 10.10.11.12}}
and thus our RateLimit
s would need to change to appropriately handle the new labels.
Questions?
We’re here to help. If you have questions, join our Slack or contact us.