Rate Limiting
Overview
Section titled “Overview”Runway provides rate limiting capabilities through Cloudflare to protect your workloads from abuse and control traffic flow. Rate limits are applied at the Cloudflare edge, before traffic reaches your origin servers.
Prerequisites
Section titled “Prerequisites”Ensure Cloudflare is enabled in your workload configuration:
spec: load_balancing: cloudflare: enabled: true # Must be true for rate limiting to workFeatures
Section titled “Features”User Rate Limiting
Section titled “User Rate Limiting”Limit requests based on configurable characteristics:
- Default: 100 requests per 60 seconds
- Characteristics: The set of parameters that define how Cloudflare tracks the rate for this rule. Each unique combination of these values gets its own separate rate limit counter:
- Colocation ID (
cf.colo.id): Cloudflare data center location where the request was processed - Source IP (
ip.src): The originating IP address of the request - Host name (
http.host): The Host header from the original request - User identification headers: Default is
x-gitlab-global-user-id, but can be customized using thecharacteristics.headersconfiguration
- Colocation ID (
- Configurable per route: Define different limits for each path
Configuration:
Configure rate limiting by updating your workload configuration in provisioner’s config/runtimes/[eks|gke]/workloads.yml as follows:
cloudflare: rate_limits: user: - path: "/api/v1" requests_per_period: 1000 # number of requests allowed per period period: 60 # time window in seconds characteristics: # optional: customize tracking headers: - x-gitlab-global-user-id - x-custom-user-headerUnmatched Request Handling:
By default, requests to paths not covered by your rate limit rules are allowed through. You can change this behavior using allow_only_rate_limited_paths:
cloudflare: rate_limits: user: - path: "/api/v1" requests_per_period: 1000 period: 60 allow_only_rate_limited_paths: true # enable 404 responsesWhen allow_only_rate_limited_paths: true, requests to paths not in your user rate limit configuration will receive a 404 response.
Rate Limiting All Requests:
To rate limit all requests, use path: "/". This will apply rate limiting to every request and will ignore the allow_only_rate_limited_paths setting:
cloudflare: rate_limits: user: - path: "/" requests_per_period: 1000 period: 60Authentication Failure Rate Limiting
Section titled “Authentication Failure Rate Limiting”Protect against brute-force attacks by limiting failed authentication attempts:
- Default: 50 requests per 300 seconds with 300 seconds ban time
- Triggered on: HTTP 401 responses
- Characteristics: The set of parameters that define how Cloudflare tracks the rate for this rule. Each unique combination of these values gets its own separate rate limit counter:
- Colocation ID (
cf.colo.id): Cloudflare data center location where the request was processed - Source IP (
ip.src): The originating IP address of the request - Host name (
http.host): The Host header from the original request - Authorization header: Default is
authorization, but can be customized using thecharacteristics.headersconfiguration
- Colocation ID (
- Applies to: All paths on the zone
Configuration:
cloudflare: rate_limits: auth_failure: requests_per_period: 50 # number of requests allowed per period period: 300 # time window in seconds mitigation_timeout: 300 # ban duration in seconds characteristics: # optional: customize tracking headers: - authorizationCustom Error Handling
Section titled “Custom Error Handling”Serve appropriate error responses for unmatched requests:
- Return 404s for paths that are not rate limited
- Applies when
allow_only_rate_limited_paths: true
Complete Configuration Example
Section titled “Complete Configuration Example”Here’s a complete workload configuration in config/runtimes/[eks|gke]/workloads.yml:
- runway_service_id: my-service project_id: 12345678 cloudflare: enabled: true rate_limits: user: - path: "/api/v1" requests_per_period: 1000 period: 60 characteristics: # optional: customize tracking headers headers: - x-gitlab-global-user-id - x-custom-user-header - path: "/api/v2" requests_per_period: 600 period: 60 auth_failure: requests_per_period: 50 period: 300 mitigation_timeout: 300 characteristics: # optional: customize tracking headers headers: - authorization allow_only_rate_limited_paths: trueThe characteristics.headers configuration allows you to customize which headers are used for rate limit tracking. If not specified, default headers are used (x-gitlab-global-user-id for user rate limits, authorization for auth failure rate limits).
Rate Limit Defaults
Section titled “Rate Limit Defaults”| Type | Period | Requests | Mitigation Timeout | Characteristics |
|---|---|---|---|---|
| User | 60s | 100 | 0s | cf.colo.id, http.host, ip.src, x-gitlab-global-user-id |
| Auth Failure | 300s | 50 | 300s | cf.colo.id, http.host, ip.src, authorization |
Environment-Specific Behavior
Section titled “Environment-Specific Behavior”Rate limit rules are automatically configured to match host names of staging and production environments:
- Production:
<runway-service-id>.svc.gitlab.net - Staging:
staging.<runway-service-id>.svc.gitlab.net
Monitoring and Troubleshooting
Section titled “Monitoring and Troubleshooting”Check Rate Limit Status
Section titled “Check Rate Limit Status”Rate limit violations are logged in Cloudflare analytics. Check:
- Cloudflare dashboard for your zone
- Query Rate limit rule metrics (Mimir - Runway) - Coming Soon!
Common Issues
Section titled “Common Issues”Issue: Legitimate traffic is being rate limited
- Increase
requests_per_periodfor the affected path - Adjust
periodto a longer time window - Review
characteristicsto ensure proper user identification
Issue: Auth failures not being limited
- Verify
auth_failureconfiguration is present - Check that your service returns 401 responses correctly
- Confirm
mitigation_timeoutis set appropriately
Related Resources
Section titled “Related Resources”Support
Section titled “Support”For questions or issues with rate limiting, contact the Runway team in #f_runway