From 4cc2d868f6b6612dfcfc4873c45505b5e0feb0aa Mon Sep 17 00:00:00 2001
From: Sunjay Bhatia
Date: Wed, 11 Oct 2023 19:52:08 +0000
Subject: [PATCH 1/6] Add configurability for HTTP requests per IO cycle
An additional mitigation to CVE-2023-44487 available in Envoy 1.27.1.
This change allows configuring the http.max_requests_per_io_cycle Envoy
runtime setting via Contour configuration to allow administrators of
Contour to prevent abusive connections from starving resources from
others. The default is left as the existing behavior, that is no limit,
so as not to impact existing valid traffic.
See the Envoy release notes for more information:
https://www.envoyproxy.io/docs/envoy/v1.27.1/version_history/v1.27/v1.27.1
Signed-off-by: Sunjay Bhatia
---
apis/projectcontour/v1alpha1/contourconfig.go | 9 +++
.../v1alpha1/zz_generated.deepcopy.go | 5 ++
cmd/contour/serve.go | 4 +-
cmd/contour/servecontext.go | 1 +
cmd/contour/servecontext_test.go | 10 +++
examples/contour/01-crds.yaml | 21 +++++
examples/render/contour-deployment.yaml | 21 +++++
.../render/contour-gateway-provisioner.yaml | 21 +++++
examples/render/contour-gateway.yaml | 21 +++++
examples/render/contour.yaml | 21 +++++
internal/envoy/v3/runtime.go | 12 ++-
internal/envoy/v3/runtime_test.go | 41 +++++++---
internal/xdscache/v3/runtime.go | 36 +++++++--
internal/xdscache/v3/runtime_test.go | 78 ++++++++++++++-----
internal/xdscache/v3/server_test.go | 2 +-
pkg/config/parameters.go | 10 +++
pkg/config/parameters_test.go | 15 ++++
.../docs/main/config/api-reference.html | 16 ++++
18 files changed, 304 insertions(+), 40 deletions(-)
diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go
index 5699d5e1f30..562b4007efb 100644
--- a/apis/projectcontour/v1alpha1/contourconfig.go
+++ b/apis/projectcontour/v1alpha1/contourconfig.go
@@ -391,6 +391,15 @@ type EnvoyListenerConfig struct {
// Single set of options are applied to all listeners.
// +optional
SocketOptions *SocketOptions `json:"socketOptions,omitempty"`
+
+ // Defines the limit on number of HTTP requests that Envoy will process from a single
+ // connection in a single I/O cycle. Requests over this limit are processed in subsequent
+ // I/O cycles. Can be used as a mitigation for CVE-2023-44487 when abusive traffic is
+ // detected. Configures the http.max_requests_per_io_cycle Envoy runtime setting.
+ //
+ // +kubebuilder:validation:Minimum=1
+ // +optional
+ MaxRequestsPerIOCycle *uint32 `json:"maxRequestsPerIOCycle"`
}
// SocketOptions defines configurable socket options for Envoy listeners.
diff --git a/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go b/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go
index d889c429aa5..c8a9d6776fe 100644
--- a/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go
@@ -582,6 +582,11 @@ func (in *EnvoyListenerConfig) DeepCopyInto(out *EnvoyListenerConfig) {
*out = new(SocketOptions)
**out = **in
}
+ if in.MaxRequestsPerIOCycle != nil {
+ in, out := &in.MaxRequestsPerIOCycle, &out.MaxRequestsPerIOCycle
+ *out = new(uint32)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyListenerConfig.
diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go
index d7bd8387a4a..6a6e4461fc7 100644
--- a/cmd/contour/serve.go
+++ b/cmd/contour/serve.go
@@ -465,7 +465,9 @@ func (s *Server) doServe() error {
&xdscache_v3.RouteCache{},
&xdscache_v3.ClusterCache{},
endpointHandler,
- &xdscache_v3.RuntimeCache{},
+ xdscache_v3.NewRuntimeCache(xdscache_v3.ConfigurableRuntimeSettings{
+ MaxRequestsPerIOCycle: contourConfiguration.Envoy.Listener.MaxRequestsPerIOCycle,
+ }),
}
// snapshotHandler is used to produce new snapshots when the internal state changes for any xDS resource.
diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go
index 629ef75280f..25c1e8ffc5d 100644
--- a/cmd/contour/servecontext.go
+++ b/cmd/contour/servecontext.go
@@ -528,6 +528,7 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_api_v1alpha
ConnectionBalancer: ctx.Config.Listener.ConnectionBalancer,
PerConnectionBufferLimitBytes: ctx.Config.Listener.PerConnectionBufferLimitBytes,
MaxRequestsPerConnection: ctx.Config.Listener.MaxRequestsPerConnection,
+ MaxRequestsPerIOCycle: ctx.Config.Listener.MaxRequestsPerIOCycle,
TLS: &contour_api_v1alpha1.EnvoyTLS{
MinimumProtocolVersion: ctx.Config.TLS.MinimumProtocolVersion,
MaximumProtocolVersion: ctx.Config.TLS.MaximumProtocolVersion,
diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go
index 1e7cc21db2a..183e7c2dd85 100644
--- a/cmd/contour/servecontext_test.go
+++ b/cmd/contour/servecontext_test.go
@@ -874,6 +874,16 @@ func TestConvertServeContext(t *testing.T) {
return cfg
},
},
+ "envoy listener settings": {
+ getServeContext: func(ctx *serveContext) *serveContext {
+ ctx.Config.Listener.MaxRequestsPerIOCycle = ref.To(uint32(10))
+ return ctx
+ },
+ getContourConfiguration: func(cfg contour_api_v1alpha1.ContourConfigurationSpec) contour_api_v1alpha1.ContourConfigurationSpec {
+ cfg.Envoy.Listener.MaxRequestsPerIOCycle = ref.To(uint32(10))
+ return cfg
+ },
+ },
}
for name, tc := range cases {
diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml
index 98b9fe9cebd..13cea6f5ef1 100644
--- a/examples/contour/01-crds.yaml
+++ b/examples/contour/01-crds.yaml
@@ -203,6 +203,16 @@ spec:
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
+ I/O cycle. Requests over this limit are processed in subsequent
+ I/O cycles. Can be used as a mitigation for CVE-2023-44487
+ when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
+ Envoy runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
@@ -3643,6 +3653,17 @@ spec:
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 I/O cycle. Requests over this limit are processed
+ in subsequent I/O cycles. Can be used as a mitigation
+ for CVE-2023-44487 when abusive traffic is detected.
+ Configures the http.max_requests_per_io_cycle Envoy
+ runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml
index 5cb52b443b5..9c10ccb38ed 100644
--- a/examples/render/contour-deployment.yaml
+++ b/examples/render/contour-deployment.yaml
@@ -422,6 +422,16 @@ spec:
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
+ I/O cycle. Requests over this limit are processed in subsequent
+ I/O cycles. Can be used as a mitigation for CVE-2023-44487
+ when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
+ Envoy runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
@@ -3862,6 +3872,17 @@ spec:
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 I/O cycle. Requests over this limit are processed
+ in subsequent I/O cycles. Can be used as a mitigation
+ for CVE-2023-44487 when abusive traffic is detected.
+ Configures the http.max_requests_per_io_cycle Envoy
+ runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml
index b0097c823ca..4025b561475 100644
--- a/examples/render/contour-gateway-provisioner.yaml
+++ b/examples/render/contour-gateway-provisioner.yaml
@@ -214,6 +214,16 @@ spec:
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
+ I/O cycle. Requests over this limit are processed in subsequent
+ I/O cycles. Can be used as a mitigation for CVE-2023-44487
+ when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
+ Envoy runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
@@ -3654,6 +3664,17 @@ spec:
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 I/O cycle. Requests over this limit are processed
+ in subsequent I/O cycles. Can be used as a mitigation
+ for CVE-2023-44487 when abusive traffic is detected.
+ Configures the http.max_requests_per_io_cycle Envoy
+ runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml
index e184b93ca01..38b4a027da2 100644
--- a/examples/render/contour-gateway.yaml
+++ b/examples/render/contour-gateway.yaml
@@ -425,6 +425,16 @@ spec:
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
+ I/O cycle. Requests over this limit are processed in subsequent
+ I/O cycles. Can be used as a mitigation for CVE-2023-44487
+ when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
+ Envoy runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
@@ -3865,6 +3875,17 @@ spec:
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 I/O cycle. Requests over this limit are processed
+ in subsequent I/O cycles. Can be used as a mitigation
+ for CVE-2023-44487 when abusive traffic is detected.
+ Configures the http.max_requests_per_io_cycle Envoy
+ runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml
index 72d6979983d..75bf1ba4aa6 100644
--- a/examples/render/contour.yaml
+++ b/examples/render/contour.yaml
@@ -422,6 +422,16 @@ spec:
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
+ I/O cycle. Requests over this limit are processed in subsequent
+ I/O cycles. Can be used as a mitigation for CVE-2023-44487
+ when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
+ Envoy runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
@@ -3862,6 +3872,17 @@ spec:
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 I/O cycle. Requests over this limit are processed
+ in subsequent I/O cycles. Can be used as a mitigation
+ for CVE-2023-44487 when abusive traffic is detected.
+ Configures the http.max_requests_per_io_cycle Envoy
+ runtime setting.
+ format: int32
+ minimum: 1
+ type: integer
per-connection-buffer-limit-bytes:
description: Defines the soft limit on size of the listener’s
new connection read and write buffers in bytes. If unspecified,
diff --git a/internal/envoy/v3/runtime.go b/internal/envoy/v3/runtime.go
index 8e2a121e06b..135eddab56b 100644
--- a/internal/envoy/v3/runtime.go
+++ b/internal/envoy/v3/runtime.go
@@ -24,11 +24,15 @@ const (
maxRegexProgramSizeWarn = 1000
)
-func RuntimeLayers() []*envoy_service_runtime_v3.Runtime {
+func RuntimeLayers(configurableRuntimeFields map[string]*structpb.Value) []*envoy_service_runtime_v3.Runtime {
+ baseLayer := baseRuntimeLayer()
+ for k, v := range configurableRuntimeFields {
+ baseLayer.Fields[k] = v
+ }
return []*envoy_service_runtime_v3.Runtime{
{
Name: DynamicRuntimeLayerName,
- Layer: baseRuntimeLayer(),
+ Layer: baseLayer,
},
}
}
@@ -36,8 +40,8 @@ func RuntimeLayers() []*envoy_service_runtime_v3.Runtime {
func baseRuntimeLayer() *structpb.Struct {
return &structpb.Struct{
Fields: map[string]*structpb.Value{
- "re2.max_program_size.error_level": {Kind: &structpb.Value_NumberValue{NumberValue: maxRegexProgramSizeError}},
- "re2.max_program_size.warn_level": {Kind: &structpb.Value_NumberValue{NumberValue: maxRegexProgramSizeWarn}},
+ "re2.max_program_size.error_level": structpb.NewNumberValue(maxRegexProgramSizeError),
+ "re2.max_program_size.warn_level": structpb.NewNumberValue(maxRegexProgramSizeWarn),
},
}
}
diff --git a/internal/envoy/v3/runtime_test.go b/internal/envoy/v3/runtime_test.go
index a0ca20d3cf0..9e84d136b65 100644
--- a/internal/envoy/v3/runtime_test.go
+++ b/internal/envoy/v3/runtime_test.go
@@ -22,15 +22,38 @@ import (
)
func TestRuntimeLayers(t *testing.T) {
- require.Equal(t, []*envoy_service_runtime_v3.Runtime{
- {
- Name: "dynamic",
- Layer: &structpb.Struct{
- Fields: map[string]*structpb.Value{
- "re2.max_program_size.error_level": {Kind: &structpb.Value_NumberValue{NumberValue: 1 << 20}},
- "re2.max_program_size.warn_level": {Kind: &structpb.Value_NumberValue{NumberValue: 1000}},
- },
+ testCases := map[string]struct {
+ configurableFields map[string]*structpb.Value
+ }{
+ "nil configurable fields": {},
+ "empty configurable fields": {
+ configurableFields: map[string]*structpb.Value{},
+ },
+ "some configurable fields": {
+ configurableFields: map[string]*structpb.Value{
+ "some.value1": structpb.NewBoolValue(true),
+ "some.value2": structpb.NewNumberValue(1000),
},
},
- }, RuntimeLayers())
+ }
+ for name, tc := range testCases {
+ t.Run(name, func(t *testing.T) {
+ expectedFields := map[string]*structpb.Value{
+ "re2.max_program_size.error_level": structpb.NewNumberValue(1 << 20),
+ "re2.max_program_size.warn_level": structpb.NewNumberValue(1000),
+ }
+ for k, v := range tc.configurableFields {
+ expectedFields[k] = v
+ }
+ layers := RuntimeLayers(tc.configurableFields)
+ require.Equal(t, []*envoy_service_runtime_v3.Runtime{
+ {
+ Name: "dynamic",
+ Layer: &structpb.Struct{
+ Fields: expectedFields,
+ },
+ },
+ }, layers)
+ })
+ }
}
diff --git a/internal/xdscache/v3/runtime.go b/internal/xdscache/v3/runtime.go
index a163350804f..52530e664d9 100644
--- a/internal/xdscache/v3/runtime.go
+++ b/internal/xdscache/v3/runtime.go
@@ -14,36 +14,58 @@
package v3
import (
+ "reflect"
+
resource "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
"github.com/projectcontour/contour/internal/contour"
"github.com/projectcontour/contour/internal/dag"
envoy_v3 "github.com/projectcontour/contour/internal/envoy/v3"
"github.com/projectcontour/contour/internal/protobuf"
"google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/types/known/structpb"
)
+type ConfigurableRuntimeSettings struct {
+ MaxRequestsPerIOCycle *uint32
+}
+
// RuntimeCache manages the contents of the gRPC RTDS cache.
-type RuntimeCache struct {
+type runtimeCache struct {
contour.Cond
+ runtimeKV map[string]*structpb.Value
+}
+
+var supportedRuntimeKeyTypes = map[string]reflect.Kind{
+ "http.max_requests_per_io_cycle": reflect.Int32,
+}
+
+// NewRuntimeCache builds a RuntimeCache with the provided runtime
+// settings that will be set in the runtime layer configured by Contour.
+func NewRuntimeCache(runtimeSettings ConfigurableRuntimeSettings) *runtimeCache {
+ runtimeKV := make(map[string]*structpb.Value)
+ if runtimeSettings.MaxRequestsPerIOCycle != nil && *runtimeSettings.MaxRequestsPerIOCycle > 0 {
+ runtimeKV["http.max_requests_per_io_cycle"] = structpb.NewNumberValue(float64(*runtimeSettings.MaxRequestsPerIOCycle))
+ }
+ return &runtimeCache{runtimeKV: runtimeKV}
}
// Contents returns all Runtime layers.
-func (c *RuntimeCache) Contents() []proto.Message {
- return protobuf.AsMessages(envoy_v3.RuntimeLayers())
+func (c *runtimeCache) Contents() []proto.Message {
+ return protobuf.AsMessages(envoy_v3.RuntimeLayers(c.runtimeKV))
}
// Query returns only the "dynamic" layer if requested, otherwise empty.
-func (c *RuntimeCache) Query(names []string) []proto.Message {
+func (c *runtimeCache) Query(names []string) []proto.Message {
for _, name := range names {
if name == envoy_v3.DynamicRuntimeLayerName {
- return protobuf.AsMessages(envoy_v3.RuntimeLayers())
+ return protobuf.AsMessages(envoy_v3.RuntimeLayers(c.runtimeKV))
}
}
return []proto.Message{}
}
-func (*RuntimeCache) TypeURL() string { return resource.RuntimeType }
+func (*runtimeCache) TypeURL() string { return resource.RuntimeType }
-func (c *RuntimeCache) OnChange(root *dag.DAG) {
+func (c *runtimeCache) OnChange(root *dag.DAG) {
// DAG changes do not affect runtime layers at the moment.
}
diff --git a/internal/xdscache/v3/runtime_test.go b/internal/xdscache/v3/runtime_test.go
index 71793f0c40d..b7aa25815d2 100644
--- a/internal/xdscache/v3/runtime_test.go
+++ b/internal/xdscache/v3/runtime_test.go
@@ -18,16 +18,72 @@ import (
envoy_service_runtime_v3 "github.com/envoyproxy/go-control-plane/envoy/service/runtime/v3"
"github.com/projectcontour/contour/internal/protobuf"
+ "github.com/projectcontour/contour/internal/ref"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
)
func TestRuntimeCacheContents(t *testing.T) {
- rc := &RuntimeCache{}
- protobuf.ExpectEqual(t, runtimeLayers(), rc.Contents())
+ testCases := map[string]struct {
+ runtimeSettings ConfigurableRuntimeSettings
+ additionalFields map[string]*structpb.Value
+ }{
+ "no values set": {
+ runtimeSettings: ConfigurableRuntimeSettings{},
+ },
+ "http max requests per io cycle set": {
+ runtimeSettings: ConfigurableRuntimeSettings{
+ MaxRequestsPerIOCycle: ref.To(uint32(1)),
+ },
+ additionalFields: map[string]*structpb.Value{
+ "http.max_requests_per_io_cycle": structpb.NewNumberValue(1),
+ },
+ },
+ "http max requests per io cycle set invalid": {
+ runtimeSettings: ConfigurableRuntimeSettings{
+ MaxRequestsPerIOCycle: ref.To(uint32(0)),
+ },
+ },
+ "http max requests per io cycle set nil": {
+ runtimeSettings: ConfigurableRuntimeSettings{
+ MaxRequestsPerIOCycle: nil,
+ },
+ },
+ }
+ for name, tc := range testCases {
+ t.Run(name, func(t *testing.T) {
+ rc := NewRuntimeCache(tc.runtimeSettings)
+ fields := map[string]*structpb.Value{
+ "re2.max_program_size.error_level": structpb.NewNumberValue(1 << 20),
+ "re2.max_program_size.warn_level": structpb.NewNumberValue(1000),
+ }
+ for k, v := range tc.additionalFields {
+ fields[k] = v
+ }
+ protobuf.ExpectEqual(t, []proto.Message{
+ &envoy_service_runtime_v3.Runtime{
+ Name: "dynamic",
+ Layer: &structpb.Struct{
+ Fields: fields,
+ },
+ },
+ }, rc.Contents())
+ })
+ }
}
func TestRuntimeCacheQuery(t *testing.T) {
+ baseRuntimeLayers := []proto.Message{
+ &envoy_service_runtime_v3.Runtime{
+ Name: "dynamic",
+ Layer: &structpb.Struct{
+ Fields: map[string]*structpb.Value{
+ "re2.max_program_size.error_level": structpb.NewNumberValue(1 << 20),
+ "re2.max_program_size.warn_level": structpb.NewNumberValue(1000),
+ },
+ },
+ },
+ }
testCases := map[string]struct {
names []string
expected []proto.Message
@@ -38,7 +94,7 @@ func TestRuntimeCacheQuery(t *testing.T) {
},
"names include dynamic": {
names: []string{"foo", "dynamic", "bar"},
- expected: runtimeLayers(),
+ expected: baseRuntimeLayers,
},
"names excludes dynamic": {
names: []string{"foo", "bar", "baz"},
@@ -47,22 +103,8 @@ func TestRuntimeCacheQuery(t *testing.T) {
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
- rc := &RuntimeCache{}
+ rc := NewRuntimeCache(ConfigurableRuntimeSettings{})
protobuf.ExpectEqual(t, tc.expected, rc.Query(tc.names))
})
}
}
-
-func runtimeLayers() []proto.Message {
- return []proto.Message{
- &envoy_service_runtime_v3.Runtime{
- Name: "dynamic",
- Layer: &structpb.Struct{
- Fields: map[string]*structpb.Value{
- "re2.max_program_size.error_level": {Kind: &structpb.Value_NumberValue{NumberValue: 1 << 20}},
- "re2.max_program_size.warn_level": {Kind: &structpb.Value_NumberValue{NumberValue: 1000}},
- },
- },
- },
- }
-}
diff --git a/internal/xdscache/v3/server_test.go b/internal/xdscache/v3/server_test.go
index 0cda062359d..b1716839613 100644
--- a/internal/xdscache/v3/server_test.go
+++ b/internal/xdscache/v3/server_test.go
@@ -208,7 +208,7 @@ func TestGRPC(t *testing.T) {
&RouteCache{},
&ClusterCache{},
et,
- &RuntimeCache{},
+ NewRuntimeCache(ConfigurableRuntimeSettings{}),
}
eh = contour.NewEventHandler(contour.EventHandlerConfig{
diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go
index 462361d226c..65e23b855f7 100644
--- a/pkg/config/parameters.go
+++ b/pkg/config/parameters.go
@@ -484,6 +484,12 @@ type ListenerParameters struct {
// SocketOptions is used to set socket options for listeners.
SocketOptions SocketOptions `yaml:"socket-options"`
+
+ // Defines the limit on number of HTTP requests that Envoy will process from a single
+ // connection in a single I/O cycle. Requests over this limit are processed in subsequent
+ // I/O cycles. Can be used as a mitigation for CVE-2023-44487 when abusive traffic is
+ // detected. Configures the http.max_requests_per_io_cycle Envoy runtime setting.
+ MaxRequestsPerIOCycle *uint32 `yaml:"max-requests-per-io-cycle"`
}
func (p *ListenerParameters) Validate() error {
@@ -503,6 +509,10 @@ func (p *ListenerParameters) Validate() error {
return fmt.Errorf("invalid per connections buffer limit bytes value %q set on listener, minimum value is 1", *p.PerConnectionBufferLimitBytes)
}
+ if p.MaxRequestsPerIOCycle != nil && *p.MaxRequestsPerIOCycle < 1 {
+ return fmt.Errorf("invalid max connections per IO cycle value %q set on listener, minimum value is 1", *p.MaxRequestsPerIOCycle)
+ }
+
return p.SocketOptions.Validate()
}
diff --git a/pkg/config/parameters_test.go b/pkg/config/parameters_test.go
index bcd46957a99..c5d1d987aa9 100644
--- a/pkg/config/parameters_test.go
+++ b/pkg/config/parameters_test.go
@@ -468,6 +468,13 @@ listener:
per-connection-buffer-limit-bytes: 1
`)
+ check(func(t *testing.T, conf *Parameters) {
+ assert.Equal(t, ref.To(uint32(1)), conf.Listener.MaxRequestsPerIOCycle)
+ }, `
+listener:
+ max-requests-per-io-cycle: 1
+`)
+
check(func(t *testing.T, conf *Parameters) {
assert.Equal(t, ref.To(uint32(1)), conf.Cluster.MaxRequestsPerConnection)
}, `
@@ -564,6 +571,14 @@ func TestListenerValidation(t *testing.T) {
PerConnectionBufferLimitBytes: ref.To(uint32(0)),
}
require.Error(t, l.Validate())
+ l = &ListenerParameters{
+ MaxRequestsPerIOCycle: ref.To(uint32(1)),
+ }
+ require.NoError(t, l.Validate())
+ l = &ListenerParameters{
+ MaxRequestsPerIOCycle: ref.To(uint32(0)),
+ }
+ require.Error(t, l.Validate())
l = &ListenerParameters{
SocketOptions: SocketOptions{
TOS: 64,
diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html
index b91773147ef..7780dfdf892 100644
--- a/site/content/docs/main/config/api-reference.html
+++ b/site/content/docs/main/config/api-reference.html
@@ -6784,6 +6784,22 @@ EnvoyListenerConfig
Single set of options are applied to all listeners.
+
+
+maxRequestsPerIOCycle
+
+
+uint32
+
+ |
+
+(Optional)
+ Defines the limit on number of HTTP requests that Envoy will process from a single
+connection in a single I/O cycle. Requests over this limit are processed in subsequent
+I/O cycles. Can be used as a mitigation for CVE-2023-44487 when abusive traffic is
+detected. Configures the http.max_requests_per_io_cycle Envoy runtime setting.
+ |
+
EnvoyLogging
From ac7beababf87b290d997bb62478afe6d4ddab5a4 Mon Sep 17 00:00:00 2001
From: Sunjay Bhatia
Date: Wed, 11 Oct 2023 20:03:43 +0000
Subject: [PATCH 2/6] lint, unused code from previous iteration
Signed-off-by: Sunjay Bhatia
---
internal/xdscache/v3/runtime.go | 6 ------
1 file changed, 6 deletions(-)
diff --git a/internal/xdscache/v3/runtime.go b/internal/xdscache/v3/runtime.go
index 52530e664d9..b4124bfa217 100644
--- a/internal/xdscache/v3/runtime.go
+++ b/internal/xdscache/v3/runtime.go
@@ -14,8 +14,6 @@
package v3
import (
- "reflect"
-
resource "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
"github.com/projectcontour/contour/internal/contour"
"github.com/projectcontour/contour/internal/dag"
@@ -35,10 +33,6 @@ type runtimeCache struct {
runtimeKV map[string]*structpb.Value
}
-var supportedRuntimeKeyTypes = map[string]reflect.Kind{
- "http.max_requests_per_io_cycle": reflect.Int32,
-}
-
// NewRuntimeCache builds a RuntimeCache with the provided runtime
// settings that will be set in the runtime layer configured by Contour.
func NewRuntimeCache(runtimeSettings ConfigurableRuntimeSettings) *runtimeCache {
From f307aa2a72070b1135b703b756bab4eeae2d2519 Mon Sep 17 00:00:00 2001
From: Sunjay Bhatia
Date: Wed, 11 Oct 2023 20:09:04 +0000
Subject: [PATCH 3/6] changelog
Signed-off-by: Sunjay Bhatia
---
changelogs/unreleased/5827-sunjayBhatia-minor.md | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 changelogs/unreleased/5827-sunjayBhatia-minor.md
diff --git a/changelogs/unreleased/5827-sunjayBhatia-minor.md b/changelogs/unreleased/5827-sunjayBhatia-minor.md
new file mode 100644
index 00000000000..7c601bb374e
--- /dev/null
+++ b/changelogs/unreleased/5827-sunjayBhatia-minor.md
@@ -0,0 +1,7 @@
+## Max HTTP requests per IO cycle is configurable as an additional mitigation for CVE-2023-44487
+
+Envoy v1.27.1 mitigates CVE-2023-44487 with some default runtime settings, however the `http.max_requests_per_io_cycle` does not have a default value.
+This change allows configuring this runtime setting via Contour configuration to allow administrators of Contour to prevent abusive connections from starving resources from other valid connections.
+The default is left as the existing behavior (no limit) so as not to impact existing valid traffic.
+
+See the [Envoy release notes](https://www.envoyproxy.io/docs/envoy/v1.27.1/version_history/v1.27/v1.27.1) for more details.
From 5a2eeb19a77358c114ea4005a08055792f810e98 Mon Sep 17 00:00:00 2001
From: Sunjay Bhatia
Date: Wed, 11 Oct 2023 20:10:48 +0000
Subject: [PATCH 4/6] Update field description with the default behavior
Signed-off-by: Sunjay Bhatia
---
apis/projectcontour/v1alpha1/contourconfig.go | 3 ++-
examples/contour/01-crds.yaml | 6 ++++--
examples/render/contour-deployment.yaml | 6 ++++--
examples/render/contour-gateway-provisioner.yaml | 6 ++++--
examples/render/contour-gateway.yaml | 6 ++++--
examples/render/contour.yaml | 6 ++++--
site/content/docs/main/config/api-reference.html | 3 ++-
7 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go
index 562b4007efb..8070cb99c94 100644
--- a/apis/projectcontour/v1alpha1/contourconfig.go
+++ b/apis/projectcontour/v1alpha1/contourconfig.go
@@ -395,7 +395,8 @@ type EnvoyListenerConfig struct {
// Defines the limit on number of HTTP requests that Envoy will process from a single
// connection in a single I/O cycle. Requests over this limit are processed in subsequent
// I/O cycles. Can be used as a mitigation for CVE-2023-44487 when abusive traffic is
- // detected. Configures the http.max_requests_per_io_cycle Envoy runtime setting.
+ // detected. Configures the http.max_requests_per_io_cycle Envoy runtime setting. The default
+ // value when this is not set is no limit.
//
// +kubebuilder:validation:Minimum=1
// +optional
diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml
index 13cea6f5ef1..7fb064b7c5a 100644
--- a/examples/contour/01-crds.yaml
+++ b/examples/contour/01-crds.yaml
@@ -209,7 +209,8 @@ spec:
I/O cycle. Requests over this limit are processed in subsequent
I/O cycles. Can be used as a mitigation for CVE-2023-44487
when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
- Envoy runtime setting.
+ Envoy runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
@@ -3660,7 +3661,8 @@ spec:
in subsequent I/O cycles. Can be used as a mitigation
for CVE-2023-44487 when abusive traffic is detected.
Configures the http.max_requests_per_io_cycle Envoy
- runtime setting.
+ runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml
index 9c10ccb38ed..74d0938f238 100644
--- a/examples/render/contour-deployment.yaml
+++ b/examples/render/contour-deployment.yaml
@@ -428,7 +428,8 @@ spec:
I/O cycle. Requests over this limit are processed in subsequent
I/O cycles. Can be used as a mitigation for CVE-2023-44487
when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
- Envoy runtime setting.
+ Envoy runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
@@ -3879,7 +3880,8 @@ spec:
in subsequent I/O cycles. Can be used as a mitigation
for CVE-2023-44487 when abusive traffic is detected.
Configures the http.max_requests_per_io_cycle Envoy
- runtime setting.
+ runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml
index 4025b561475..0a100be8a90 100644
--- a/examples/render/contour-gateway-provisioner.yaml
+++ b/examples/render/contour-gateway-provisioner.yaml
@@ -220,7 +220,8 @@ spec:
I/O cycle. Requests over this limit are processed in subsequent
I/O cycles. Can be used as a mitigation for CVE-2023-44487
when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
- Envoy runtime setting.
+ Envoy runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
@@ -3671,7 +3672,8 @@ spec:
in subsequent I/O cycles. Can be used as a mitigation
for CVE-2023-44487 when abusive traffic is detected.
Configures the http.max_requests_per_io_cycle Envoy
- runtime setting.
+ runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml
index 38b4a027da2..3c2f4b1a9f5 100644
--- a/examples/render/contour-gateway.yaml
+++ b/examples/render/contour-gateway.yaml
@@ -431,7 +431,8 @@ spec:
I/O cycle. Requests over this limit are processed in subsequent
I/O cycles. Can be used as a mitigation for CVE-2023-44487
when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
- Envoy runtime setting.
+ Envoy runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
@@ -3882,7 +3883,8 @@ spec:
in subsequent I/O cycles. Can be used as a mitigation
for CVE-2023-44487 when abusive traffic is detected.
Configures the http.max_requests_per_io_cycle Envoy
- runtime setting.
+ runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml
index 75bf1ba4aa6..7b7ffa08de3 100644
--- a/examples/render/contour.yaml
+++ b/examples/render/contour.yaml
@@ -428,7 +428,8 @@ spec:
I/O cycle. Requests over this limit are processed in subsequent
I/O cycles. Can be used as a mitigation for CVE-2023-44487
when abusive traffic is detected. Configures the http.max_requests_per_io_cycle
- Envoy runtime setting.
+ Envoy runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
@@ -3879,7 +3880,8 @@ spec:
in subsequent I/O cycles. Can be used as a mitigation
for CVE-2023-44487 when abusive traffic is detected.
Configures the http.max_requests_per_io_cycle Envoy
- runtime setting.
+ runtime setting. The default value when this is not
+ set is no limit.
format: int32
minimum: 1
type: integer
diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html
index 7780dfdf892..672010fc223 100644
--- a/site/content/docs/main/config/api-reference.html
+++ b/site/content/docs/main/config/api-reference.html
@@ -6797,7 +6797,8 @@ EnvoyListenerConfig
Defines the limit on number of HTTP requests that Envoy will process from a single
connection in a single I/O cycle. Requests over this limit are processed in subsequent
I/O cycles. Can be used as a mitigation for CVE-2023-44487 when abusive traffic is
-detected. Configures the http.max_requests_per_io_cycle Envoy runtime setting.
+detected. Configures the http.max_requests_per_io_cycle Envoy runtime setting. The default
+value when this is not set is no limit.
From 1f2f456643fa5449ea8a0532f12fd95882c56e6f Mon Sep 17 00:00:00 2001
From: Sunjay Bhatia
Date: Wed, 11 Oct 2023 20:28:09 +0000
Subject: [PATCH 5/6] changelog updates and save pkg/config changes
Signed-off-by: Sunjay Bhatia
---
changelogs/unreleased/5827-sunjayBhatia-minor.md | 11 ++++++++++-
pkg/config/parameters.go | 3 ++-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/changelogs/unreleased/5827-sunjayBhatia-minor.md b/changelogs/unreleased/5827-sunjayBhatia-minor.md
index 7c601bb374e..93010ffb61a 100644
--- a/changelogs/unreleased/5827-sunjayBhatia-minor.md
+++ b/changelogs/unreleased/5827-sunjayBhatia-minor.md
@@ -1,7 +1,16 @@
-## Max HTTP requests per IO cycle is configurable as an additional mitigation for CVE-2023-44487
+## Max HTTP requests per IO cycle is configurable as an additional mitigation for HTTP/2 CVE-2023-44487
Envoy v1.27.1 mitigates CVE-2023-44487 with some default runtime settings, however the `http.max_requests_per_io_cycle` does not have a default value.
This change allows configuring this runtime setting via Contour configuration to allow administrators of Contour to prevent abusive connections from starving resources from other valid connections.
The default is left as the existing behavior (no limit) so as not to impact existing valid traffic.
+The Contour ConfigMap can be modified similar to the following (and Contour restarted) to set this value:
+
+```
+listener:
+ max-requests-per-io-cycle: 10
+```
+
+(Note this can be used in addition to the existing Listener configuration field `listener.max-requests-per-connection` which is used primarily for HTTP/1.1 connections and is an approximate limit for HTTP/2)
+
See the [Envoy release notes](https://www.envoyproxy.io/docs/envoy/v1.27.1/version_history/v1.27/v1.27.1) for more details.
diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go
index 65e23b855f7..413bae97a11 100644
--- a/pkg/config/parameters.go
+++ b/pkg/config/parameters.go
@@ -488,7 +488,8 @@ type ListenerParameters struct {
// Defines the limit on number of HTTP requests that Envoy will process from a single
// connection in a single I/O cycle. Requests over this limit are processed in subsequent
// I/O cycles. Can be used as a mitigation for CVE-2023-44487 when abusive traffic is
- // detected. Configures the http.max_requests_per_io_cycle Envoy runtime setting.
+ // detected. Configures the http.max_requests_per_io_cycle Envoy runtime setting. The default
+ // value when this is not set is no limit.
MaxRequestsPerIOCycle *uint32 `yaml:"max-requests-per-io-cycle"`
}
From 48b3a76d00e28470371e990d4b4336c87af3965b Mon Sep 17 00:00:00 2001
From: Sunjay Bhatia
Date: Thu, 12 Oct 2023 15:50:44 +0000
Subject: [PATCH 6/6] add to configuration.md
Signed-off-by: Sunjay Bhatia
---
site/content/docs/main/configuration.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/site/content/docs/main/configuration.md b/site/content/docs/main/configuration.md
index 0c42f161188..b8dcfe238df 100644
--- a/site/content/docs/main/configuration.md
+++ b/site/content/docs/main/configuration.md
@@ -195,6 +195,7 @@ The listener configuration block can be used to configure various parameters for
| max-requests-per-connection | int | none | This field specifies the maximum requests for downstream connections. If not specified, there is no limit |
| per-connection-buffer-limit-bytes | int | 1MiB* | This field specifies the soft limit on size of the listener’s new connection read and write buffer. If not specified, Envoy defaults of 1MiB apply |
| socket-options | SocketOptions | | The [Socket Options](#socket-options) for Envoy listeners. |
+| max-requests-per-io-cycle | int | none | Defines the limit on number of HTTP requests that Envoy will process from a single connection in a single I/O cycle. Requests over this limit are processed in subsequent I/O cycles. Can be used as a mitigation for CVE-2023-44487 when abusive traffic is detected. Configures the `http.max_requests_per_io_cycle` Envoy runtime setting. The default value when this is not set is no limit. |
_This is Envoy's default setting value and is not explicitly configured by Contour._