Skip to content

Commit

Permalink
HTTP/2 max concurrent streams can be configured (projectcontour#5850)
Browse files Browse the repository at this point in the history
Adds a global Listener configuration field for admins to be able to
protect their installations of Contour/Envoy with a limit. Default is no
limit to ensure existing behavior is not impacted for valid traffic.
This field can be used for tuning resource usage or mitigated DOS
attacks like in CVE-2023-44487.

Also fixes omitempty tags on MaxRequestsPerIOCycle field.

Fixes: projectcontour#5846

Signed-off-by: Sunjay Bhatia <sunjayb@vmware.com>
  • Loading branch information
sunjayBhatia committed Oct 13, 2023
1 parent 9d99d15 commit c78c69b
Show file tree
Hide file tree
Showing 20 changed files with 411 additions and 2 deletions.
13 changes: 12 additions & 1 deletion apis/projectcontour/v1alpha1/contourconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,18 @@ type EnvoyListenerConfig struct {
//
// +kubebuilder:validation:Minimum=1
// +optional
MaxRequestsPerIOCycle *uint32 `json:"maxRequestsPerIOCycle"`
MaxRequestsPerIOCycle *uint32 `json:"maxRequestsPerIOCycle,omitempty"`

// Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS Envoy will advertise in the
// SETTINGS frame in HTTP/2 connections and the limit for concurrent streams allowed
// for a peer on a single HTTP/2 connection. It is recommended to not set this lower
// than 100 but this field can be used to bound resource usage by HTTP/2 connections
// and mitigate attacks like CVE-2023-44487. The default value when this is not set is
// unlimited.
//
// +kubebuilder:validation:Minimum=1
// +optional
HTTP2MaxConcurrentStreams *uint32 `json:"httpMaxConcurrentStreams,omitempty"`
}

// EnvoyTLS describes tls parameters for Envoy listneners.
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.

11 changes: 11 additions & 0 deletions changelogs/unreleased/5850-sunjayBhatia-minor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## HTTP/2 max concurrent streams is configurable

This field can be used to limit the number of concurrent streams Envoy will allow on a single connection from a downstream peer.
It can be used to tune resource usage and as a mitigation for DOS attacks arising from vulnerabilities like CVE-2023-44487.

The Contour ConfigMap can be modified similar to the following (and Contour restarted) to set this value:

```
listener:
http2-max-concurrent-streams: 50
```
1 change: 1 addition & 0 deletions cmd/contour/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ func (s *Server) doServe() error {
ServerHeaderTransformation: contourConfiguration.Envoy.Listener.ServerHeaderTransformation,
XffNumTrustedHops: *contourConfiguration.Envoy.Network.XffNumTrustedHops,
ConnectionBalancer: contourConfiguration.Envoy.Listener.ConnectionBalancer,
HTTP2MaxConcurrentStreams: contourConfiguration.Envoy.Listener.HTTP2MaxConcurrentStreams,
}

if listenerConfig.RateLimitConfig, err = s.setupRateLimitService(contourConfiguration); err != nil {
Expand Down
1 change: 1 addition & 0 deletions cmd/contour/servecontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_api_v1alpha
ServerHeaderTransformation: serverHeaderTransformation,
ConnectionBalancer: ctx.Config.Listener.ConnectionBalancer,
MaxRequestsPerIOCycle: ctx.Config.Listener.MaxRequestsPerIOCycle,
HTTP2MaxConcurrentStreams: ctx.Config.Listener.HTTP2MaxConcurrentStreams,
TLS: &contour_api_v1alpha1.EnvoyTLS{
MinimumProtocolVersion: ctx.Config.TLS.MinimumProtocolVersion,
CipherSuites: cipherSuites,
Expand Down
2 changes: 2 additions & 0 deletions cmd/contour/servecontext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,10 +702,12 @@ func TestConvertServeContext(t *testing.T) {
"envoy listener settings": {
getServeContext: func(ctx *serveContext) *serveContext {
ctx.Config.Listener.MaxRequestsPerIOCycle = ref.To(uint32(10))
ctx.Config.Listener.HTTP2MaxConcurrentStreams = ref.To(uint32(30))
return ctx
},
getContourConfiguration: func(cfg contour_api_v1alpha1.ContourConfigurationSpec) contour_api_v1alpha1.ContourConfigurationSpec {
cfg.Envoy.Listener.MaxRequestsPerIOCycle = ref.To(uint32(10))
cfg.Envoy.Listener.HTTP2MaxConcurrentStreams = ref.To(uint32(30))
return cfg
},
},
Expand Down
24 changes: 24 additions & 0 deletions examples/contour/01-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ spec:
slashes from request URL paths. \n Contour's default is
false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2 connections
and the limit for concurrent streams allowed for a peer
on a single HTTP/2 connection. It is recommended to not
set this lower than 100 but this field can be used to bound
resource usage by HTTP/2 connections and mitigate attacks
like CVE-2023-44487. The default value when this is not
set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in a single
Expand Down Expand Up @@ -3208,6 +3220,18 @@ spec:
duplicate slashes from request URL paths. \n Contour's
default is false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2
connections and the limit for concurrent streams allowed
for a peer on a single HTTP/2 connection. It is recommended
to not set this lower than 100 but this field can be
used to bound resource usage by HTTP/2 connections and
mitigate attacks like CVE-2023-44487. The default value
when this is not set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in
Expand Down
24 changes: 24 additions & 0 deletions examples/render/contour-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,18 @@ spec:
slashes from request URL paths. \n Contour's default is
false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2 connections
and the limit for concurrent streams allowed for a peer
on a single HTTP/2 connection. It is recommended to not
set this lower than 100 but this field can be used to bound
resource usage by HTTP/2 connections and mitigate attacks
like CVE-2023-44487. The default value when this is not
set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in a single
Expand Down Expand Up @@ -3421,6 +3433,18 @@ spec:
duplicate slashes from request URL paths. \n Contour's
default is false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2
connections and the limit for concurrent streams allowed
for a peer on a single HTTP/2 connection. It is recommended
to not set this lower than 100 but this field can be
used to bound resource usage by HTTP/2 connections and
mitigate attacks like CVE-2023-44487. The default value
when this is not set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in
Expand Down
24 changes: 24 additions & 0 deletions examples/render/contour-gateway-provisioner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,18 @@ spec:
slashes from request URL paths. \n Contour's default is
false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2 connections
and the limit for concurrent streams allowed for a peer
on a single HTTP/2 connection. It is recommended to not
set this lower than 100 but this field can be used to bound
resource usage by HTTP/2 connections and mitigate attacks
like CVE-2023-44487. The default value when this is not
set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in a single
Expand Down Expand Up @@ -3222,6 +3234,18 @@ spec:
duplicate slashes from request URL paths. \n Contour's
default is false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2
connections and the limit for concurrent streams allowed
for a peer on a single HTTP/2 connection. It is recommended
to not set this lower than 100 but this field can be
used to bound resource usage by HTTP/2 connections and
mitigate attacks like CVE-2023-44487. The default value
when this is not set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in
Expand Down
24 changes: 24 additions & 0 deletions examples/render/contour-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,18 @@ spec:
slashes from request URL paths. \n Contour's default is
false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2 connections
and the limit for concurrent streams allowed for a peer
on a single HTTP/2 connection. It is recommended to not
set this lower than 100 but this field can be used to bound
resource usage by HTTP/2 connections and mitigate attacks
like CVE-2023-44487. The default value when this is not
set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in a single
Expand Down Expand Up @@ -3427,6 +3439,18 @@ spec:
duplicate slashes from request URL paths. \n Contour's
default is false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2
connections and the limit for concurrent streams allowed
for a peer on a single HTTP/2 connection. It is recommended
to not set this lower than 100 but this field can be
used to bound resource usage by HTTP/2 connections and
mitigate attacks like CVE-2023-44487. The default value
when this is not set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in
Expand Down
24 changes: 24 additions & 0 deletions examples/render/contour.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,18 @@ spec:
slashes from request URL paths. \n Contour's default is
false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2 connections
and the limit for concurrent streams allowed for a peer
on a single HTTP/2 connection. It is recommended to not
set this lower than 100 but this field can be used to bound
resource usage by HTTP/2 connections and mitigate attacks
like CVE-2023-44487. The default value when this is not
set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in a single
Expand Down Expand Up @@ -3421,6 +3433,18 @@ spec:
duplicate slashes from request URL paths. \n Contour's
default is false."
type: boolean
httpMaxConcurrentStreams:
description: Defines the value for SETTINGS_MAX_CONCURRENT_STREAMS
Envoy will advertise in the SETTINGS frame in HTTP/2
connections and the limit for concurrent streams allowed
for a peer on a single HTTP/2 connection. It is recommended
to not set this lower than 100 but this field can be
used to bound resource usage by HTTP/2 connections and
mitigate attacks like CVE-2023-44487. The default value
when this is not set is unlimited.
format: int32
minimum: 1
type: integer
maxRequestsPerIOCycle:
description: Defines the limit on number of HTTP requests
that Envoy will process from a single connection in
Expand Down
1 change: 1 addition & 0 deletions internal/contourconfig/contourconfiguration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func TestOverlayOnDefaults(t *testing.T) {
UseProxyProto: ref.To(true),
DisableAllowChunkedLength: ref.To(true),
DisableMergeSlashes: ref.To(true),
HTTP2MaxConcurrentStreams: ref.To(uint32(10)),
ServerHeaderTransformation: contour_api_v1alpha1.PassThroughServerHeader,
ConnectionBalancer: "yesplease",
TLS: &contour_api_v1alpha1.EnvoyTLS{
Expand Down
12 changes: 12 additions & 0 deletions internal/envoy/v3/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ type httpConnectionManagerBuilder struct {
serverHeaderTransformation http.HttpConnectionManager_ServerHeaderTransformation
forwardClientCertificate *dag.ClientCertificateDetails
numTrustedHops uint32
http2MaxConcurrentStreams *uint32
}

// RouteConfigName sets the name of the RDS element that contains
Expand Down Expand Up @@ -265,6 +266,11 @@ func (b *httpConnectionManagerBuilder) NumTrustedHops(num uint32) *httpConnectio
return b
}

func (b *httpConnectionManagerBuilder) HTTP2MaxConcurrentStreams(http2MaxConcurrentStreams *uint32) *httpConnectionManagerBuilder {
b.http2MaxConcurrentStreams = http2MaxConcurrentStreams
return b
}

func (b *httpConnectionManagerBuilder) DefaultFilters() *httpConnectionManagerBuilder {

// Add a default set of ordered http filters.
Expand Down Expand Up @@ -507,6 +513,12 @@ func (b *httpConnectionManagerBuilder) Get() *envoy_listener_v3.Filter {
}
}

if b.http2MaxConcurrentStreams != nil {
cm.Http2ProtocolOptions = &envoy_core_v3.Http2ProtocolOptions{
MaxConcurrentStreams: wrapperspb.UInt32(*b.http2MaxConcurrentStreams),
}
}

return &envoy_listener_v3.Filter{
Name: wellknown.HTTPConnectionManager,
ConfigType: &envoy_listener_v3.Filter_TypedConfig{
Expand Down
Loading

0 comments on commit c78c69b

Please sign in to comment.