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 <[email protected]>
  • Loading branch information
sunjayBhatia committed Oct 13, 2023
1 parent cda0703 commit 304d5be
Show file tree
Hide file tree
Showing 20 changed files with 405 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 @@ -400,7 +400,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"`
}

// SocketOptions defines configurable socket options for Envoy listeners.
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 @@ -430,6 +430,7 @@ func (s *Server) doServe() error {
XffNumTrustedHops: *contourConfiguration.Envoy.Network.XffNumTrustedHops,
ConnectionBalancer: contourConfiguration.Envoy.Listener.ConnectionBalancer,
MaxRequestsPerConnection: contourConfiguration.Envoy.Listener.MaxRequestsPerConnection,
HTTP2MaxConcurrentStreams: contourConfiguration.Envoy.Listener.HTTP2MaxConcurrentStreams,
PerConnectionBufferLimitBytes: contourConfiguration.Envoy.Listener.PerConnectionBufferLimitBytes,
SocketOptions: contourConfiguration.Envoy.Listener.SocketOptions,
}
Expand Down
1 change: 1 addition & 0 deletions cmd/contour/servecontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_api_v1alpha
PerConnectionBufferLimitBytes: ctx.Config.Listener.PerConnectionBufferLimitBytes,
MaxRequestsPerConnection: ctx.Config.Listener.MaxRequestsPerConnection,
MaxRequestsPerIOCycle: ctx.Config.Listener.MaxRequestsPerIOCycle,
HTTP2MaxConcurrentStreams: ctx.Config.Listener.HTTP2MaxConcurrentStreams,
TLS: &contour_api_v1alpha1.EnvoyTLS{
MinimumProtocolVersion: ctx.Config.TLS.MinimumProtocolVersion,
MaximumProtocolVersion: ctx.Config.TLS.MaximumProtocolVersion,
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 @@ -877,10 +877,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 @@ -196,6 +196,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream connections.
If not specified, there is no limit. see https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-msg-config-core-v3-httpprotocoloptions
Expand Down Expand Up @@ -3637,6 +3649,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream
connections. If not specified, there is no limit. see
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 @@ -415,6 +415,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream connections.
If not specified, there is no limit. see https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-msg-config-core-v3-httpprotocoloptions
Expand Down Expand Up @@ -3856,6 +3868,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream
connections. If not specified, there is no limit. see
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 @@ -210,6 +210,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream connections.
If not specified, there is no limit. see https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-msg-config-core-v3-httpprotocoloptions
Expand Down Expand Up @@ -3651,6 +3663,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream
connections. If not specified, there is no limit. see
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 @@ -421,6 +421,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream connections.
If not specified, there is no limit. see https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-msg-config-core-v3-httpprotocoloptions
Expand Down Expand Up @@ -3862,6 +3874,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream
connections. If not specified, there is no limit. see
Expand Down
24 changes: 24 additions & 0 deletions examples/render/contour.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream connections.
If not specified, there is no limit. see https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-msg-config-core-v3-httpprotocoloptions
Expand Down Expand Up @@ -3856,6 +3868,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
maxRequestsPerConnection:
description: Defines the maximum requests for downstream
connections. If not specified, there is no limit. see
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 @@ -57,6 +57,7 @@ func TestOverlayOnDefaults(t *testing.T) {
DisableAllowChunkedLength: ref.To(true),
DisableMergeSlashes: ref.To(true),
MaxRequestsPerConnection: ref.To(uint32(1)),
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 @@ -172,6 +172,7 @@ type httpConnectionManagerBuilder struct {
numTrustedHops uint32
tracingConfig *http.HttpConnectionManager_Tracing
maxRequestsPerConnection *uint32
http2MaxConcurrentStreams *uint32
enableWebsockets bool
}

Expand Down Expand Up @@ -284,6 +285,11 @@ func (b *httpConnectionManagerBuilder) MaxRequestsPerConnection(maxRequestsPerCo
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 @@ -538,6 +544,12 @@ func (b *httpConnectionManagerBuilder) Get() *envoy_listener_v3.Filter {
cm.CommonHttpProtocolOptions.MaxRequestsPerConnection = wrapperspb.UInt32(*b.maxRequestsPerConnection)
}

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

if b.enableWebsockets {
cm.UpgradeConfigs = append(cm.UpgradeConfigs,
&http.HttpConnectionManager_UpgradeConfig{
Expand Down
Loading

0 comments on commit 304d5be

Please sign in to comment.