envoyproxy / envoyproxy/gateway

`BackendTrafficPolicy`: emit `Retry-After` header on rate-limit 429 responses

Open
#9,078 6 comments 3 reactions 0 assignees View on GitHub
help wanted kind/feature
Dominant language
Go
Stars
3k
Forks
864
Avg merge
2d 2h
Merged PRs (30d)
140

Description

*Description*:

The global rate-limit filter in EG emits the IETF draft-03 triple
(`x-ratelimit-limit`, `x-ratelimit-remaining`, `x-ratelimit-reset`) on both
200 and 429 responses, but does not emit `Retry-After` on the 429.

`Retry-After` on 429 is the convention defined by [RFC 6585 section 4](https://www.rfc-editor.org/rfc/rfc6585#section-4),
with the field itself defined by [RFC 9110 section 10.2.3](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.3)
as `HTTP-date / delay-seconds`. Operators today have to bridge this gap
themselves, typically with a Lua filter via `EnvoyExtensionPolicy` that
copies `x-ratelimit-reset` into `Retry-After` on 429. The information is
already in the filter; only the emission is missing.

Proposal: add a option to `BackendTrafficPolicy.spec.rateLimit` (and the
local rate-limit equivalent) that opts the rule or policy into emitting
`Retry-After: ` on rate-limited 429 responses, sourced from
the same reset value the filter already computes. Sketch:

```yaml
spec:
rateLimit:
type: Global
global:
emitRetryAfter: true # or per-rule, mirroring xRateLimitHeaders
rules: [ ... ]
```

The value would be an integer matching the current `x-ratelimit-reset`
semantics: most-restrictive matched rule's seconds-until-reset, clamped
to ≥1. Emission is conditional on the 429, not on every response, to
match RFC 6585 section 4 semantics.

This works for both the RLS-backed global filter and the local rate-limit
filter; the underlying delay value is already computed in both paths.

*Relevant Links*:

- RFC 9110 section 10.2.3, Retry-After: https://www.rfc-editor.org/rfc/rfc9110#section-10.2.3
- RFC 6585 section 4, 429 with Retry-After: https://www.rfc-editor.org/rfc/rfc6585#section-4
- IETF draft-ietf-httpapi-ratelimit-headers (active WG draft, v11): https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/
- Closely related, **closed without delivering Retry-After**:
envoyproxy/gateway#5693, closed after the scope was narrowed to enabling
the existing `x-ratelimit-*` headers on the local rate-limit filter;
the original `Retry-After` ask was not addressed.
- Adjacent CRD surface already shipped in v1.8: envoyproxy/gateway#8279
(`xRateLimitHeaders` per-rule enum), same place the new option would live.
- Upstream Envoy dormant issues for context:
envoyproxy/envoy#12356 (original draft-03 implementation),
envoyproxy/envoy#3555 (custom response headers from the rate-limit
filter/service).
- Envoy `XRateLimitHeadersRFCVersion` enum (frozen at `DRAFT_VERSION_03`):
https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/common/ratelimit/v3/ratelimit.proto

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.