Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/v1alpha1/clienttrafficpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ type HeaderSettings struct {
// +optional
DisableRateLimitHeaders *bool `json:"disableRateLimitHeaders,omitempty"`

// EnableRetryAfterHeader configures Envoy Proxy to emit the "Retry-After" response header
// on rate-limited 429 responses.
// +optional
EnableRetryAfterHeader *bool `json:"enableRetryAfterHeader,omitempty"`
Comment thread
devilleweppenaar marked this conversation as resolved.

// XForwardedClientCert configures how Envoy Proxy handle the x-forwarded-client-cert (XFCC) HTTP header.
//
// x-forwarded-client-cert (XFCC) is an HTTP header used to forward the certificate
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,11 @@ spec:
EnableEnvoyHeaders configures Envoy Proxy to add the "X-Envoy-" headers to requests
and responses.
type: boolean
enableRetryAfterHeader:
description: |-
EnableRetryAfterHeader configures Envoy Proxy to emit the "Retry-After" response header
on rate-limited 429 responses.
type: boolean
host:
description: Host enables managing how the Host/Authority header
set by clients can be normalized.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,11 @@ spec:
EnableEnvoyHeaders configures Envoy Proxy to add the "X-Envoy-" headers to requests
and responses.
type: boolean
enableRetryAfterHeader:
description: |-
EnableRetryAfterHeader configures Envoy Proxy to emit the "Retry-After" response header
on rate-limited 429 responses.
type: boolean
host:
description: Host enables managing how the Host/Authority header
set by clients can be normalized.
Expand Down
2 changes: 1 addition & 1 deletion examples/extension-server/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.27.0
require (
github.com/envoyproxy/gateway v1.3.1
github.com/envoyproxy/go-control-plane v0.14.1-0.20260729145720-a2d8c7492908
github.com/envoyproxy/go-control-plane/envoy v1.39.0
github.com/envoyproxy/go-control-plane/envoy v1.39.1-0.20260816030012-a266ce994369
github.com/urfave/cli/v2 v2.27.7
google.golang.org/grpc v1.83.1
google.golang.org/protobuf v1.36.12
Expand Down
4 changes: 2 additions & 2 deletions examples/extension-server/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.14.1-0.20260729145720-a2d8c7492908 h1:Ymr4e9UMtsAYCBiuHV2JF8BxaMZu49yEFpTXBqgaqUE=
github.com/envoyproxy/go-control-plane v0.14.1-0.20260729145720-a2d8c7492908/go.mod h1:rcDQvjX9fwNQvh7l9pxwfGBufBWU6xQ0zK5mcsH8/Lg=
github.com/envoyproxy/go-control-plane/envoy v1.39.0 h1:1uwRDYPYG8BIBU9Mj1sUAebNmlM6beu/ZKKweSLDxk8=
github.com/envoyproxy/go-control-plane/envoy v1.39.0/go.mod h1:5e4ylfTZO723MEEFsCpSW4ZEBWR8mwkEyXfwJBTCZ9c=
github.com/envoyproxy/go-control-plane/envoy v1.39.1-0.20260816030012-a266ce994369 h1:ZJjjlzVZoUwYJtlGzPjVC+gbG/v16XUJRHE0pQ1FFz4=
github.com/envoyproxy/go-control-plane/envoy v1.39.1-0.20260816030012-a266ce994369/go.mod h1:PYEOlng9XcrulfyWpm49jECTPV0LT4q8cO7fLW/xwgk=
github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=
github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0=
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ require (
github.com/dominikbraun/graph v0.23.0
github.com/envoyproxy/go-control-plane v0.14.1-0.20260729145720-a2d8c7492908
github.com/envoyproxy/go-control-plane/contrib v1.36.1-0.20260729145720-a2d8c7492908
github.com/envoyproxy/go-control-plane/envoy v1.37.1-0.20260729145720-a2d8c7492908
github.com/envoyproxy/go-control-plane/envoy v1.39.1-0.20260816030012-a266ce994369
github.com/envoyproxy/go-control-plane/ratelimit v0.1.1-0.20260729145720-a2d8c7492908
github.com/envoyproxy/ratelimit v1.4.1-0.20260122083618-3fb702589d36
github.com/evanphx/json-patch v5.9.11+incompatible
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ github.com/envoyproxy/go-control-plane v0.14.1-0.20260729145720-a2d8c7492908 h1:
github.com/envoyproxy/go-control-plane v0.14.1-0.20260729145720-a2d8c7492908/go.mod h1:rcDQvjX9fwNQvh7l9pxwfGBufBWU6xQ0zK5mcsH8/Lg=
github.com/envoyproxy/go-control-plane/contrib v1.36.1-0.20260729145720-a2d8c7492908 h1:+7FtQqQ7Yfo5dgsAyTAIe8OhmUtWUw6VjeQ3by2Xdm4=
github.com/envoyproxy/go-control-plane/contrib v1.36.1-0.20260729145720-a2d8c7492908/go.mod h1:pdjA+146jsWRsJ0M1jgfRrvJq1HPWeyvaT/Va+nV2OY=
github.com/envoyproxy/go-control-plane/envoy v1.37.1-0.20260729145720-a2d8c7492908 h1:yp1HVjmLFpwwN3Ik82LUTAZ6giMb6NAuhA3fralKvRQ=
github.com/envoyproxy/go-control-plane/envoy v1.37.1-0.20260729145720-a2d8c7492908/go.mod h1:rYoRI6N8FcjZVmmeKqH8/ykAhfro9Bg8+of2IpBseyQ=
github.com/envoyproxy/go-control-plane/envoy v1.39.1-0.20260816030012-a266ce994369 h1:ZJjjlzVZoUwYJtlGzPjVC+gbG/v16XUJRHE0pQ1FFz4=
github.com/envoyproxy/go-control-plane/envoy v1.39.1-0.20260816030012-a266ce994369/go.mod h1:PYEOlng9XcrulfyWpm49jECTPV0LT4q8cO7fLW/xwgk=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.1-0.20260729145720-a2d8c7492908 h1:dNsOk1pDOqRl4SzUdAWDPXQ05VASaD5CYYaVpfZr7os=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.1-0.20260729145720-a2d8c7492908/go.mod h1:kFrXkz+a+gF/F56IcDXtBE0QfpZfFTyf92okqDzIBu0=
github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=
Expand Down
1 change: 1 addition & 0 deletions internal/gatewayapi/clienttrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,7 @@ func translateListenerHeaderSettings(headerSettings *egv1a1.HeaderSettings, http
httpIR.Headers = &ir.HeaderSettings{
EnableEnvoyHeaders: ptr.Deref(headerSettings.EnableEnvoyHeaders, false),
DisableRateLimitHeaders: ptr.Deref(headerSettings.DisableRateLimitHeaders, false),
EnableRetryAfterHeader: ptr.Deref(headerSettings.EnableRetryAfterHeader, false),
WithUnderscoresAction: ir.WithUnderscoresAction(ptr.Deref(headerSettings.WithUnderscoresAction, egv1a1.WithUnderscoresActionRejectRequest)),
}
if headerSettings.RequestID != nil {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
clientTrafficPolicies:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
namespace: envoy-gateway
name: target-gateway-1
spec:
headers:
enableRetryAfterHeader: true
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http-1
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
- name: http-2
protocol: HTTP
port: 8080
allowedRoutes:
namespaces:
from: Same
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
clientTrafficPolicies:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
name: target-gateway-1
namespace: envoy-gateway
spec:
headers:
enableRetryAfterHeader: true
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
status:
ancestors:
- ancestorRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
namespace: envoy-gateway
conditions:
- lastTransitionTime: null
message: Policy has been accepted.
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: null
message: spec.targetRef is deprecated, use spec.targetRefs instead
reason: DeprecatedField
status: "True"
type: Warning
controllerName: gateway.envoyproxy.io/gatewayclass-controller
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway-1
namespace: envoy-gateway
spec:
gatewayClassName: envoy-gateway-class
listeners:
- allowedRoutes:
namespaces:
from: Same
name: http-1
port: 80
protocol: HTTP
- allowedRoutes:
namespaces:
from: Same
name: http-2
port: 8080
protocol: HTTP
status:
listeners:
- attachedRoutes: 0
conditions:
- lastTransitionTime: null
message: Sending translated listener configuration to the data plane
reason: Programmed
status: "True"
type: Programmed
- lastTransitionTime: null
message: Listener has been successfully translated
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: null
message: Listener references have been resolved
reason: ResolvedRefs
status: "True"
type: ResolvedRefs
name: http-1
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
- group: gateway.networking.k8s.io
kind: GRPCRoute
- attachedRoutes: 0
conditions:
- lastTransitionTime: null
message: Sending translated listener configuration to the data plane
reason: Programmed
status: "True"
type: Programmed
- lastTransitionTime: null
message: Listener has been successfully translated
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: null
message: Listener references have been resolved
reason: ResolvedRefs
status: "True"
type: ResolvedRefs
name: http-2
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
- group: gateway.networking.k8s.io
kind: GRPCRoute
infraIR:
envoy-gateway/gateway-1:
proxy:
listeners:
- name: envoy-gateway/gateway-1/http-1
ports:
- containerPort: 10080
name: http-80
protocol: HTTP
servicePort: 80
- name: envoy-gateway/gateway-1/http-2
ports:
- containerPort: 8080
name: http-8080
protocol: HTTP
servicePort: 8080
metadata:
labels:
gateway.envoyproxy.io/owning-gateway-name: gateway-1
gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
ownerReference:
kind: GatewayClass
name: envoy-gateway-class
name: envoy-gateway/gateway-1
namespace: envoy-gateway-system
xdsIR:
envoy-gateway/gateway-1:
accessLog:
json:
- path: /dev/stdout
globalResources:
proxyServiceCluster:
metadata:
kind: Service
name: envoy-envoy-gateway-gateway-1-196ae069
namespace: envoy-gateway-system
sectionName: "8080"
name: envoy-gateway/gateway-1
settings:
- addressType: IP
endpoints:
- host: 7.6.5.4
port: 8080
zone: zone1
metadata:
kind: Service
name: envoy-envoy-gateway-gateway-1-196ae069
namespace: envoy-gateway-system
sectionName: "8080"
name: envoy-gateway/gateway-1
protocol: TCP
http:
- address: 0.0.0.0
externalPort: 80
headers:
enableRetryAfterHeader: true
withUnderscoresAction: RejectRequest
hostnames:
- '*'
metadata:
kind: Gateway
name: gateway-1
namespace: envoy-gateway
sectionName: http-1
name: envoy-gateway/gateway-1/http-1
path:
escapedSlashesAction: UnescapeAndRedirect
mergeSlashes: true
port: 10080
- address: 0.0.0.0
externalPort: 8080
headers:
enableRetryAfterHeader: true
withUnderscoresAction: RejectRequest
hostnames:
- '*'
metadata:
kind: Gateway
name: gateway-1
namespace: envoy-gateway
sectionName: http-2
name: envoy-gateway/gateway-1/http-2
path:
escapedSlashesAction: UnescapeAndRedirect
mergeSlashes: true
port: 8080
readyListener:
address: 0.0.0.0
ipFamily: IPv4
path: /ready
port: 19003
5 changes: 5 additions & 0 deletions internal/ir/xds.go
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,11 @@ type HeaderSettings struct {
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ratelimit/v3/rate_limit.proto#extensions-filters-http-ratelimit-v3-ratelimit
DisableRateLimitHeaders bool `json:"disableRateLimitHeaders,omitempty" yaml:"disableRateLimitHeaders,omitempty"`

// EnableRetryAfterHeader controls if a "Retry-After" header is added to rate-limited 429 responses.
// The default is to omit this header.
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ratelimit/v3/rate_limit.proto#extensions-filters-http-ratelimit-v3-ratelimit
EnableRetryAfterHeader bool `json:"enableRetryAfterHeader,omitempty" yaml:"enableRetryAfterHeader,omitempty"`

// Configure Envoy proxy how to handle the x-forwarded-client-cert (XFCC) HTTP header.
// refer to https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#envoy-v3-api-enum-extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-forwardclientcertdetails
XForwardedClientCert *XForwardedClientCert `json:"xForwardedClientCert,omitempty" yaml:"xForwardedClientCert,omitempty"`
Expand Down
3 changes: 3 additions & 0 deletions internal/xds/extensions/extensions.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ import (
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/early_data/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/common/dependency/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/common/fault/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/common/jwks/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/common/matcher/action/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/common/set_filter_state/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/a2a/v3"
Expand All @@ -130,6 +131,7 @@ import (
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/bandwidth_limit/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/bandwidth_share/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/basic_auth/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/body_size_limit/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/buffer/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/cache/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/cache_v2/v3"
Expand Down Expand Up @@ -281,6 +283,7 @@ import (
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/http/stateful_session/envelope/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/http/stateful_session/header/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/internal_redirect/allow_listed_routes/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/internal_redirect/filter_state/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/internal_redirect/previous_routes/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/internal_redirect/safe_cross_scheme/v3"
_ "github.com/envoyproxy/go-control-plane/envoy/extensions/key_value/file_based/v3"
Expand Down
3 changes: 3 additions & 0 deletions internal/xds/translator/local_ratelimit.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ func (*localRateLimit) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, h
if httpListener.Headers != nil && httpListener.Headers.DisableRateLimitHeaders {
localRl.EnableXRatelimitHeaders = rlv3.XRateLimitHeadersRFCVersion_OFF
}
if httpListener.Headers != nil && httpListener.Headers.EnableRetryAfterHeader {
localRl.EnableRetryAfterHeader = true
}

localRlAny, err := anypb.New(localRl)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions internal/xds/translator/ratelimit.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ func createRateLimitFilter(t *Translator, irListener *ir.HTTPListener, domain, f
rateLimitFilterProto.EnableXRatelimitHeaders = ratelimitfilterv3.RateLimit_DRAFT_VERSION_03
}

// Emit the Retry-After header on rate-limited 429 responses.
if irListener.Headers != nil && irListener.Headers.EnableRetryAfterHeader {
rateLimitFilterProto.EnableRetryAfterHeader = true
}

// Set the failure mode to deny if the global rate limit is configured to fail closed
if t.GlobalRateLimit.FailClosed {
rateLimitFilterProto.FailureModeDeny = t.GlobalRateLimit.FailClosed
Expand Down
Loading
Loading