Skip to content

Rate Limiting

Added in version 3.3.0

Nautobot has the ability to rate limit requests received in order to mitigate over usage.

Rate limiting is applied for each user's provisioned token.

Rate limiting is enforced using a complexity cost model.

Nautobot estimates how expensive each request is and charges that estimate for each token's budget.

Rate limiting is disabled by default.

Requirements

Rate limiting budgets are stored in Redis. See Redis for setup instructions.

If Redis cannot be reached, the rate limiting fails open. Meaning, the request is served and the response reports the full budget. The failure is counted in the nautobot_rate_limiting_rest_backend_errors Prometheus metric. See Prometheus Metrics.

Budget and Window

The per-token budget is specified using the NAUTOBOT_RATE_LIMITING_REST_BUDGET setting. [default 1000].

The per-token budget is renewed after its window expires.

The per-token budget window is specified using the NAUTOBOT_RATE_LIMITING_REST_BUDGET_WINDOW_IN_SECONDS setting. [default 60].

The per-token budget window only begins on the first request that is charged.

The per-token budget resets when the budget window expires. Charges made during a per-token budget window do not extend the budget window.

REST Rate Limiting

REST Rate Limiting Modes

Rate limiting can be enabled using the NAUTOBOT_RATE_LIMITING_REST_MODE setting.

Mode Behavior
off [DEFAULT] Requests are not charged or limited. Budget information is not included in response headers
report Each request's cost is calculated and reported in the response headers. No budget is consumed and no request is denied.
enforce Each request's cost is charged against the token's budget. Requests are denied once the budget is exhausted.

Use report first to see what your clients actually cost, then switch to enforce.

Note

In report mode the RateLimit header always reports a full budget. It shows you the per-request cost, but not which requests enforce would have rejected.

REST Complexity Cost Calculation

Each request has a level of complexity associated with it.

Complexity is an estimate of how much work the Nautobot instance will need to perform to satisfy the request.

Complexity costs are determined in one of two forms, read operations and write operations.

Read operations are GET, HEAD, and OPTIONS requests.

Write operations are DELETE, PATCH, POST, PUT requests.

Complexity cost is generated by determining the Nautobot features used for a REST request. This is done using the classify_rest_read_request_features function which returns a RestReadRequestFeatures object. The RestReadRequestFeatures object is used by estimate_rest_read_request_cost to return an integer value representing the request's estimated cost.

The complexity cost process can be overridden using a custom function. See Custom Complexity Cost Function

REST Complexity Cost Settings

Setting Default Description
NAUTOBOT_RATE_LIMITING_REST_MODE off off, report, or enforce.
NAUTOBOT_RATE_LIMITING_REST_BUDGET 1000 Complexity cost points granted for each token's budget window.
NAUTOBOT_RATE_LIMITING_REST_BUDGET_WINDOW_IN_SECONDS 60 Length of the token's budget window in seconds.
NAUTOBOT_RATE_LIMITING_REST_READ_COST 1.0 Base cost of a REST read request.
NAUTOBOT_RATE_LIMITING_REST_WRITE_COST 3.0 Flat cost of a REST write request.
NAUTOBOT_RATE_LIMITING_REST_PAGINATION_COST 3.0 Cost for each page of the request's result set.
NAUTOBOT_RATE_LIMITING_REST_INDEXABLE_LOOKUP_COST 3.0 Cost for each indexable filter.
NAUTOBOT_RATE_LIMITING_REST_UNINDEXABLE_LOOKUP_COST 3.0 Cost for each unindexable filter.
NAUTOBOT_RATE_LIMITING_REST_DEPTH_MULTIPLIER_PER_LEVEL 1.0 Weight of each level of depth.
NAUTOBOT_RATE_LIMITING_REST_COMPUTED_FIELDS_MULTIPLIER 3.0 Multiplier for each computed_field used
NAUTOBOT_RATE_LIMITING_REST_CSV_MULTIPLIER 3.0 Multiplier for format=csv.
NAUTOBOT_RATE_LIMITING_CUSTOM_COMPLEXITY_COST_ESTIMATION_FUNCTION "" Replaces the built-in cost estimate.

See Settings for the full reference on each setting.

REST Response Headers

When a rate limiting mode is set to report or enforce, Nautobot adds headers to REST API responses.

Rate limiting response headers follow the IETF HTTP API RateLimit Headers draft specification.

Header Description
X-Nautobot-Cost The estimated cost of this request.
RateLimit-Policy The budget specification: q is the budget, w is the budget window length.
RateLimit The current budget state: r is the budget remaining, t is the seconds remaining in the budget window.

Example:

RateLimit-Policy: "rest-complexity-cost";q=1000;w=60
RateLimit: "rest-complexity-cost";r=996;t=60
X-Nautobot-Cost: 4

GraphQL Rate Limiting

GraphQL Rate Limiting Modes

Rate limiting can be enabled using the NAUTOBOT_RATE_LIMITING_GRAPHQL_MODE setting.

Mode Behavior
off [DEFAULT] Requests are not charged or limited. Budget information is not included in response headers
report Each request's cost is calculated and reported in the response headers. No budget is consumed and no request is denied.
enforce Each request's cost is charged against the token's budget. Requests are denied once the budget is exhausted.

Use report first to see what your clients actually cost, then switch to enforce.

GraphQL Complexity Cost Calculation

Warning

GraphQL complexity cost rate limiting has not yet been implemented

GraphQL Complexity Cost Settings

Warning

GraphQL complexity cost rate limiting has not yet been implemented

Setting Default Description
NAUTOBOT_RATE_LIMITING_GRAPHQL_MODE off Mode for token-authenticated GraphQL requests.

See Settings for the full reference on each setting.

Denied Requests

When rate limiting is enforced, a request made after the budget is exhausted returns an HTTP 429 Too Many Requests status.

{"detail": "Request was throttled. The estimated complexity cost exceeds the budget."}

The response headers will carry a Retry-After header with the number of seconds remaining in the window.

Custom Complexity Cost Function

NAUTOBOT_RATE_LIMITING_CUSTOM_COMPLEXITY_COST_ESTIMATION_FUNCTION replaces Nautobot's built-in complexity cost estimation with a custom implementation.

Nautobot resolves the path at startup and reports a system check error if it cannot be imported or is not callable.

When set to an empty string (the default) Nautobot uses the built-in estimation implementation.

Set it to a dotted import path to override.

The dotted path must be importable, so the function has to live in an installed Python package, in a Nautobot App, or in nautobot_config.py itself (referenced as nautobot_config.my_function). Nautobot does not add any directory to sys.path, so a loose file beside nautobot_config.py is not importable on its own.

For example my_package.my_module.my_function. Or nautobot_config.estimate_request_cost.

The custom function takes one argument, the HttpRequest being estimated. The custom function returns an integer, the cost of the request. The returned integer is used to charge the token for its request.

This function is applied to REST read and write operations, as well as GraphQL operations.

Custom Complexity Cost Function - Flat Example

# nautobot_config.py

NAUTOBOT_RATE_LIMITING_REST_MODE = "enforce"
NAUTOBOT_RATE_LIMITING_CUSTOM_COMPLEXITY_COST_ESTIMATION_FUNCTION = "nautobot_config.estimate_request_cost"


def estimate_request_cost(request):
    """Charge a flat cost for every API request."""
    return 1

Custom Complexity Cost Function - Using RestReadRequestFeatures Object

# nautobot_config.py

from nautobot.core.rate_limiting.rest_calculator import (
    READ_METHODS,
    classify_rest_read_request_features,
)

NAUTOBOT_RATE_LIMITING_REST_MODE = "enforce"
NAUTOBOT_RATE_LIMITING_CUSTOM_COMPLEXITY_COST_ESTIMATION_FUNCTION = "nautobot_config.estimate_request_cost"


def estimate_request_cost(request):
    if request.method not in READ_METHODS:
        return 10

    rest_read_request_features = classify_rest_read_request_features(request)

    cost = 1
    cost += rest_read_request_features.depth * 2
    cost += rest_read_request_features.indexable_lookups
    cost += rest_read_request_features.unindexable_lookups * 5

    if rest_read_request_features.do_computed_fields_exist():
        cost += 10
    if rest_read_request_features.is_response_format_csv():
        cost *= 3

    return cost

Prometheus Monitoring

When rate limiting is enabled, Prometheus metrics will be generated. See Prometheus Metrics.