Skip to content
Merged
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
9 changes: 5 additions & 4 deletions cmd/contour/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,10 +350,11 @@ func doServe(log logrus.FieldLogger, ctx *serveContext) error {
}

listenerConfig.RateLimitConfig = &xdscache_v3.RateLimitConfig{
ExtensionService: namespacedName,
Domain: ctx.Config.RateLimitService.Domain,
Timeout: responseTimeout,
FailOpen: ctx.Config.RateLimitService.FailOpen,
ExtensionService: namespacedName,
Domain: ctx.Config.RateLimitService.Domain,
Timeout: responseTimeout,
FailOpen: ctx.Config.RateLimitService.FailOpen,
EnableXRateLimitHeaders: ctx.Config.RateLimitService.EnableXRateLimitHeaders,
}
}

Expand Down
6 changes: 6 additions & 0 deletions examples/contour/01-contour-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ data:
# service fails to respond with a valid rate limit decision within
# the timeout defined on the extension service.
# failOpen: false
# Defines whether to include the X-RateLimit headers X-RateLimit-Limit,
# X-RateLimit-Remaining, and X-RateLimit-Reset (as defined by the IETF
# Internet-Draft linked below), on responses to clients when the Rate
# Limit Service is consulted for a request.
# ref. https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html
# enableXRateLimitHeaders: false
#
# Global Policy settings.
# policy:
Expand Down
6 changes: 6 additions & 0 deletions examples/render/contour.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ data:
# service fails to respond with a valid rate limit decision within
# the timeout defined on the extension service.
# failOpen: false
# Defines whether to include the X-RateLimit headers X-RateLimit-Limit,
# X-RateLimit-Remaining, and X-RateLimit-Reset (as defined by the IETF
# Internet-Draft linked below), on responses to clients when the Rate
# Limit Service is consulted for a request.
# ref. https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html
# enableXRateLimitHeaders: false
#
# Global Policy settings.
# policy:
Expand Down
17 changes: 13 additions & 4 deletions internal/envoy/v3/ratelimit.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,11 @@ func GlobalRateLimits(descriptors []*dag.RateLimitDescriptor) []*envoy_route_v3.
// GlobalRateLimitConfig stores configuration for
// an HTTP global rate limiting filter.
type GlobalRateLimitConfig struct {
ExtensionService types.NamespacedName
FailOpen bool
Timeout timeout.Setting
Domain string
ExtensionService types.NamespacedName
FailOpen bool
Timeout timeout.Setting
Domain string
EnableXRateLimitHeaders bool
}

// GlobalRateLimitFilter returns a configured HTTP global rate limit filter,
Expand All @@ -141,7 +142,15 @@ func GlobalRateLimitFilter(config *GlobalRateLimitConfig) *http.HttpFilter {
},
TransportApiVersion: envoy_core_v3.ApiVersion_V3,
},
EnableXRatelimitHeaders: enableXRateLimitHeaders(config.EnableXRateLimitHeaders),
}),
},
}
}

func enableXRateLimitHeaders(enable bool) ratelimit_filter_v3.RateLimit_XRateLimitHeadersRFCVersion {
if enable {
return ratelimit_filter_v3.RateLimit_DRAFT_VERSION_03
}
return ratelimit_filter_v3.RateLimit_OFF
}
118 changes: 94 additions & 24 deletions internal/envoy/v3/ratelimit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,35 +180,105 @@ func TestGlobalRateLimits(t *testing.T) {
}

func TestGlobalRateLimitFilter(t *testing.T) {
assert.Nil(t, GlobalRateLimitFilter(nil))

want := &http.HttpFilter{
Name: wellknown.HTTPRateLimit,
ConfigType: &http.HttpFilter_TypedConfig{
TypedConfig: protobuf.MustMarshalAny(&ratelimit_filter_v3.RateLimit{
Domain: "domain",
Timeout: protobuf.Duration(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",
tests := map[string]struct {
cfg *GlobalRateLimitConfig
want *http.HttpFilter
}{
"nil config produces nil filter": {
cfg: nil,
want: nil,
},
"all fields configured correctly with FailOpen=false": {
cfg: &GlobalRateLimitConfig{
ExtensionService: k8s.NamespacedNameFrom("projectcontour/ratelimit"),
Timeout: timeout.DurationSetting(7 * time.Second),
Domain: "domain",
FailOpen: false,
},
want: &http.HttpFilter{
Name: wellknown.HTTPRateLimit,
ConfigType: &http.HttpFilter_TypedConfig{
TypedConfig: protobuf.MustMarshalAny(&ratelimit_filter_v3.RateLimit{
Domain: "domain",
Timeout: protobuf.Duration(7 * time.Second),
FailureModeDeny: true,
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",
},
},
},
TransportApiVersion: envoy_core_v3.ApiVersion_V3,
},
},
TransportApiVersion: envoy_core_v3.ApiVersion_V3,
}),
},
},
},
"all fields configured correctly with FailOpen=true": {
cfg: &GlobalRateLimitConfig{
ExtensionService: k8s.NamespacedNameFrom("projectcontour/ratelimit"),
Timeout: timeout.DurationSetting(7 * time.Second),
Domain: "domain",
FailOpen: true,
},
want: &http.HttpFilter{
Name: wellknown.HTTPRateLimit,
ConfigType: &http.HttpFilter_TypedConfig{
TypedConfig: protobuf.MustMarshalAny(&ratelimit_filter_v3.RateLimit{
Domain: "domain",
Timeout: protobuf.Duration(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",
},
},
},
TransportApiVersion: envoy_core_v3.ApiVersion_V3,
},
}),
},
}),
},
},
"EnableXRateLimitHeaders=true is configured correctly": {
cfg: &GlobalRateLimitConfig{
ExtensionService: k8s.NamespacedNameFrom("projectcontour/ratelimit"),
Timeout: timeout.DurationSetting(7 * time.Second),
Domain: "domain",
FailOpen: true,
EnableXRateLimitHeaders: true,
},
want: &http.HttpFilter{
Name: wellknown.HTTPRateLimit,
ConfigType: &http.HttpFilter_TypedConfig{
TypedConfig: protobuf.MustMarshalAny(&ratelimit_filter_v3.RateLimit{
Domain: "domain",
Timeout: protobuf.Duration(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",
},
},
},
TransportApiVersion: envoy_core_v3.ApiVersion_V3,
},
EnableXRatelimitHeaders: ratelimit_filter_v3.RateLimit_DRAFT_VERSION_03,
}),
},
},
},
}

cfg := &GlobalRateLimitConfig{
ExtensionService: k8s.NamespacedNameFrom("projectcontour/ratelimit"),
FailOpen: true,
Timeout: timeout.DurationSetting(time.Second),
Domain: "domain",
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
assert.Equal(t, tc.want, GlobalRateLimitFilter(tc.cfg))
})
}

assert.Equal(t, want, GlobalRateLimitFilter(cfg))
}
18 changes: 10 additions & 8 deletions internal/xdscache/v3/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,11 @@ type ListenerConfig struct {
}

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

// httpAddress returns the port for the HTTP (non TLS)
Expand Down Expand Up @@ -406,10 +407,11 @@ func envoyGlobalRateLimitConfig(config *RateLimitConfig) *envoy_v3.GlobalRateLim
}

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

Expand Down
Loading