Skip to content

Commit

Permalink
expose configuration for envoy's RateLimitedAsResourceExhausted (proj…
Browse files Browse the repository at this point in the history
…ectcontour#4971)

The Rate Limit filter in Envoy translates a 429 HTTP response code
to UNAVAILABLE as specified in the gRPC mapping document, but Google recommends
translating it to RESOURCE_EXHAUSTED
(see https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md)

This commit introduces a new setting to allow contour to forward the same parameter
introduced in envoyproxy/envoy#4879

The default value is disabled to retain the original behaviour of returning UNAVAILABLE,
as changing it would be a breaking change.

Closes projectcontour#4901.

Signed-off-by: Víctor Roldán Betancort <vroldanbet@authzed.com>
Signed-off-by: yy <yang.yang@daocloud.io>
  • Loading branch information
vroldanbet authored and yangyy93 committed Feb 16, 2023
1 parent 0446326 commit e4cefa1
Show file tree
Hide file tree
Showing 19 changed files with 212 additions and 68 deletions.
6 changes: 6 additions & 0 deletions apis/projectcontour/v1alpha1/contourconfig.go
Expand Up @@ -621,6 +621,12 @@ type RateLimitServiceConfig struct {
// ref. https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html
// +optional
EnableXRateLimitHeaders *bool `json:"enableXRateLimitHeaders,omitempty"`

// EnableResourceExhaustedCode enables translating error code 429 to
// grpc code RESOURCE_EXHAUSTED. When disabled it's translated to UNAVAILABLE
//
// +optional
EnableResourceExhaustedCode *bool `json:"enableResourceExhaustedCode,omitempty"`
}

// TracingConfig defines properties for exporting trace data to OpenTelemetry.
Expand Down
5 changes: 5 additions & 0 deletions apis/projectcontour/v1alpha1/zz_generated.deepcopy.go

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

1 change: 1 addition & 0 deletions changelogs/unreleased/4971-vroldanbet-small.md
@@ -0,0 +1 @@
expose configuration for envoy's RateLimitedAsResourceExhausted
13 changes: 7 additions & 6 deletions cmd/contour/serve.go
Expand Up @@ -668,12 +668,13 @@ func (s *Server) setupRateLimitService(contourConfiguration contour_api_v1alpha1
}

return &xdscache_v3.RateLimitConfig{
ExtensionService: key,
SNI: sni,
Domain: contourConfiguration.RateLimitService.Domain,
Timeout: responseTimeout,
FailOpen: ref.Val(contourConfiguration.RateLimitService.FailOpen, false),
EnableXRateLimitHeaders: ref.Val(contourConfiguration.RateLimitService.EnableXRateLimitHeaders, false),
ExtensionService: key,
SNI: sni,
Domain: contourConfiguration.RateLimitService.Domain,
Timeout: responseTimeout,
FailOpen: ref.Val(contourConfiguration.RateLimitService.FailOpen, false),
EnableXRateLimitHeaders: ref.Val(contourConfiguration.RateLimitService.EnableXRateLimitHeaders, false),
EnableResourceExhaustedCode: ref.Val(contourConfiguration.RateLimitService.EnableResourceExhaustedCode, false),
}, nil
}

Expand Down
7 changes: 4 additions & 3 deletions cmd/contour/servecontext.go
Expand Up @@ -395,9 +395,10 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_api_v1alpha
Name: nsedName.Name,
Namespace: nsedName.Namespace,
},
Domain: ctx.Config.RateLimitService.Domain,
FailOpen: ref.To(ctx.Config.RateLimitService.FailOpen),
EnableXRateLimitHeaders: ref.To(ctx.Config.RateLimitService.EnableXRateLimitHeaders),
Domain: ctx.Config.RateLimitService.Domain,
FailOpen: ref.To(ctx.Config.RateLimitService.FailOpen),
EnableXRateLimitHeaders: ref.To(ctx.Config.RateLimitService.EnableXRateLimitHeaders),
EnableResourceExhaustedCode: ref.To(ctx.Config.RateLimitService.EnableResourceExhaustedCode),
}
}

Expand Down
16 changes: 9 additions & 7 deletions cmd/contour/servecontext_test.go
Expand Up @@ -623,10 +623,11 @@ func TestConvertServeContext(t *testing.T) {
"ratelimit": {
getServeContext: func(ctx *serveContext) *serveContext {
ctx.Config.RateLimitService = config.RateLimitService{
ExtensionService: "ratens/ratelimitext",
Domain: "contour",
FailOpen: true,
EnableXRateLimitHeaders: true,
ExtensionService: "ratens/ratelimitext",
Domain: "contour",
FailOpen: true,
EnableXRateLimitHeaders: true,
EnableResourceExhaustedCode: true,
}
return ctx
},
Expand All @@ -636,9 +637,10 @@ func TestConvertServeContext(t *testing.T) {
Name: "ratelimitext",
Namespace: "ratens",
},
Domain: "contour",
FailOpen: ref.To(true),
EnableXRateLimitHeaders: ref.To(true),
Domain: "contour",
FailOpen: ref.To(true),
EnableXRateLimitHeaders: ref.To(true),
EnableResourceExhaustedCode: ref.To(true),
}
return cfg
},
Expand Down
3 changes: 3 additions & 0 deletions examples/contour/01-contour-config.yaml
Expand Up @@ -145,6 +145,9 @@ data:
# Limit Service is consulted for a request.
# ref. https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html
# enableXRateLimitHeaders: false
# Defines whether to translate status code 429 to grpc code RESOURCE_EXHAUSTED
# instead of the default UNAVAILABLE
# enableResourceExhaustedCode: false
#
# Global Policy settings.
# policy:
Expand Down
10 changes: 10 additions & 0 deletions examples/contour/01-crds.yaml
Expand Up @@ -521,6 +521,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating error
code 429 to grpc code RESOURCE_EXHAUSTED. When disabled it's
translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down Expand Up @@ -3521,6 +3526,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating
error code 429 to grpc code RESOURCE_EXHAUSTED. When disabled
it's translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down
13 changes: 13 additions & 0 deletions examples/render/contour-deployment.yaml
Expand Up @@ -178,6 +178,9 @@ data:
# Limit Service is consulted for a request.
# ref. https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html
# enableXRateLimitHeaders: false
# Defines whether to translate status code 429 to grpc code RESOURCE_EXHAUSTED
# instead of the default UNAVAILABLE
# enableResourceExhaustedCode: false
#
# Global Policy settings.
# policy:
Expand Down Expand Up @@ -731,6 +734,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating error
code 429 to grpc code RESOURCE_EXHAUSTED. When disabled it's
translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down Expand Up @@ -3731,6 +3739,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating
error code 429 to grpc code RESOURCE_EXHAUSTED. When disabled
it's translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down
10 changes: 10 additions & 0 deletions examples/render/contour-gateway-provisioner.yaml
Expand Up @@ -535,6 +535,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating error
code 429 to grpc code RESOURCE_EXHAUSTED. When disabled it's
translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down Expand Up @@ -3535,6 +3540,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating
error code 429 to grpc code RESOURCE_EXHAUSTED. When disabled
it's translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down
13 changes: 13 additions & 0 deletions examples/render/contour-gateway.yaml
Expand Up @@ -184,6 +184,9 @@ data:
# Limit Service is consulted for a request.
# ref. https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html
# enableXRateLimitHeaders: false
# Defines whether to translate status code 429 to grpc code RESOURCE_EXHAUSTED
# instead of the default UNAVAILABLE
# enableResourceExhaustedCode: false
#
# Global Policy settings.
# policy:
Expand Down Expand Up @@ -737,6 +740,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating error
code 429 to grpc code RESOURCE_EXHAUSTED. When disabled it's
translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down Expand Up @@ -3737,6 +3745,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating
error code 429 to grpc code RESOURCE_EXHAUSTED. When disabled
it's translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down
13 changes: 13 additions & 0 deletions examples/render/contour.yaml
Expand Up @@ -178,6 +178,9 @@ data:
# Limit Service is consulted for a request.
# ref. https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html
# enableXRateLimitHeaders: false
# Defines whether to translate status code 429 to grpc code RESOURCE_EXHAUSTED
# instead of the default UNAVAILABLE
# enableResourceExhaustedCode: false
#
# Global Policy settings.
# policy:
Expand Down Expand Up @@ -731,6 +734,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating error
code 429 to grpc code RESOURCE_EXHAUSTED. When disabled it's
translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down Expand Up @@ -3731,6 +3739,11 @@ spec:
domain:
description: Domain is passed to the Rate Limit Service.
type: string
enableResourceExhaustedCode:
description: EnableResourceExhaustedCode enables translating
error code 429 to grpc code RESOURCE_EXHAUSTED. When disabled
it's translated to UNAVAILABLE
type: boolean
enableXRateLimitHeaders:
description: "EnableXRateLimitHeaders defines whether to include
the X-RateLimit headers X-RateLimit-Limit, X-RateLimit-Remaining,
Expand Down
16 changes: 9 additions & 7 deletions internal/envoy/v3/ratelimit.go
Expand Up @@ -123,12 +123,13 @@ func GlobalRateLimits(descriptors []*dag.RateLimitDescriptor) []*envoy_route_v3.
// GlobalRateLimitConfig stores configuration for
// an HTTP global rate limiting filter.
type GlobalRateLimitConfig struct {
ExtensionService types.NamespacedName
SNI string
FailOpen bool
Timeout timeout.Setting
Domain string
EnableXRateLimitHeaders bool
ExtensionService types.NamespacedName
SNI string
FailOpen bool
Timeout timeout.Setting
Domain string
EnableXRateLimitHeaders bool
EnableResourceExhaustedCode bool
}

// GlobalRateLimitFilter returns a configured HTTP global rate limit filter,
Expand All @@ -149,7 +150,8 @@ func GlobalRateLimitFilter(config *GlobalRateLimitConfig) *http.HttpFilter {
GrpcService: GrpcService(dag.ExtensionClusterName(config.ExtensionService), config.SNI, timeout.DefaultSetting()),
TransportApiVersion: envoy_core_v3.ApiVersion_V3,
},
EnableXRatelimitHeaders: enableXRateLimitHeaders(config.EnableXRateLimitHeaders),
EnableXRatelimitHeaders: enableXRateLimitHeaders(config.EnableXRateLimitHeaders),
RateLimitedAsResourceExhausted: config.EnableResourceExhaustedCode,
}),
},
}
Expand Down
31 changes: 31 additions & 0 deletions internal/envoy/v3/ratelimit_test.go
Expand Up @@ -372,6 +372,37 @@ func TestGlobalRateLimitFilter(t *testing.T) {
},
},
},
"EnableResourceExhaustedCode=true is configured correctly": {
cfg: &GlobalRateLimitConfig{
ExtensionService: k8s.NamespacedNameFrom("projectcontour/ratelimit"),
Timeout: timeout.DurationSetting(7 * time.Second),
Domain: "domain",
FailOpen: true,
EnableResourceExhaustedCode: true,
},
want: &http.HttpFilter{
Name: wellknown.HTTPRateLimit,
ConfigType: &http.HttpFilter_TypedConfig{
TypedConfig: protobuf.MustMarshalAny(&ratelimit_filter_v3.RateLimit{
Domain: "domain",
Timeout: durationpb.New(7 * time.Second),
FailureModeDeny: false,
RateLimitService: &ratelimit_config_v3.RateLimitServiceConfig{
GrpcService: &envoy_core_v3.GrpcService{
TargetSpecifier: &envoy_core_v3.GrpcService_EnvoyGrpc_{
EnvoyGrpc: &envoy_core_v3.GrpcService_EnvoyGrpc{
ClusterName: "extension/projectcontour/ratelimit",
Authority: "extension.projectcontour.ratelimit",
},
},
},
TransportApiVersion: envoy_core_v3.ApiVersion_V3,
},
RateLimitedAsResourceExhausted: true,
}),
},
},
},
}

for name, tc := range tests {
Expand Down
26 changes: 14 additions & 12 deletions internal/xdscache/v3/listener.go
Expand Up @@ -144,12 +144,13 @@ type ListenerConfig struct {
}

type RateLimitConfig struct {
ExtensionService types.NamespacedName
SNI string
Domain string
Timeout timeout.Setting
FailOpen bool
EnableXRateLimitHeaders bool
ExtensionService types.NamespacedName
SNI string
Domain string
Timeout timeout.Setting
FailOpen bool
EnableXRateLimitHeaders bool
EnableResourceExhaustedCode bool
}

// DefaultListeners returns the configured Listeners or a single
Expand Down Expand Up @@ -569,12 +570,13 @@ func envoyGlobalRateLimitConfig(config *RateLimitConfig) *envoy_v3.GlobalRateLim
}

return &envoy_v3.GlobalRateLimitConfig{
ExtensionService: config.ExtensionService,
SNI: config.SNI,
FailOpen: config.FailOpen,
Timeout: config.Timeout,
Domain: config.Domain,
EnableXRateLimitHeaders: config.EnableXRateLimitHeaders,
ExtensionService: config.ExtensionService,
SNI: config.SNI,
FailOpen: config.FailOpen,
Timeout: config.Timeout,
Domain: config.Domain,
EnableXRateLimitHeaders: config.EnableXRateLimitHeaders,
EnableResourceExhaustedCode: config.EnableResourceExhaustedCode,
}
}

Expand Down

0 comments on commit e4cefa1

Please sign in to comment.