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).
- RateLimitsthat set limits based on the labels in the request
Labels
Edge Stack supports three types of labels:
- generic_keywhich is a simple string
- remote_addresswhich 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 ambassadorModule are "global" and applied to every single request that goes through Ambassador; these labels are typically managed by operations
- Labels applied at the Mappingare 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 ambassadorlabel domain.
- Each label must have a name, e.g., one_request_label
- The string_request_labelsimply adds the stringcatalogto every incoming request to the given mapping. The string is referenced with the keygeneric_key.
- The header_request_labeladds 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., thehostheader needs to be specified as the:authorityheader).
- Multiple labels can be part of a single named label, e.g., multi_request_labelspecifies two different headers to be added
- When an HTTP header is not present, the entire named label is omitted. The omit_if_not_present: trueis an explicit notation to remind end-users of this limitation.falseis not a supported value.
Ambassador Edge Stack supports several special labels:
- remote_addressautomatically populates the remote IP address using the trusted IP address from- X-Forwarded-For
- request_headers: HEADERwill extract the value from a given HTTP header
- destination_clusterpopulates the name of the Envoy cluster. Typically, there is a 1:1 correspondence between a- servicein a- Mappingto a- destination_cluster. You can get the name of the cluster from the diagnostics service.
- source_clusterpopulates 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 RateLimits 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.