From 64202725cf6313f17bc8aabbe05d4a3e8a5d3175 Mon Sep 17 00:00:00 2001 From: David Sale Date: Tue, 26 Nov 2024 08:36:07 +0000 Subject: [PATCH] Add strip trailing host dot option from Envoy Fixes #6334 Signed-off-by: David Sale --- apis/projectcontour/v1alpha1/contourconfig.go | 13 +++++ cmd/contour/serve.go | 1 + cmd/contour/servecontext.go | 5 +- cmd/contour/servecontext_test.go | 5 +- examples/contour/01-crds.yaml | 22 ++++++++ examples/render/contour-deployment.yaml | 22 ++++++++ .../render/contour-gateway-provisioner.yaml | 22 ++++++++ examples/render/contour-gateway.yaml | 22 ++++++++ examples/render/contour.yaml | 22 ++++++++ .../contourconfig/contourconfiguration.go | 5 +- .../contourconfiguration_test.go | 5 +- internal/envoy/v3/listener.go | 11 +++- internal/envoy/v3/listener_test.go | 50 +++++++++++++++++ internal/featuretests/v3/listeners_test.go | 54 +++++++++++++++++++ internal/xdscache/v3/listener.go | 7 +++ internal/xdscache/v3/listener_test.go | 42 +++++++++++++++ pkg/config/parameters.go | 15 +++++- pkg/config/parameters_test.go | 9 ++++ .../docs/main/config/api-reference.html | 20 +++++++ 19 files changed, 340 insertions(+), 12 deletions(-) diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go index 0af7a50e08a..9593dda219c 100644 --- a/apis/projectcontour/v1alpha1/contourconfig.go +++ b/apis/projectcontour/v1alpha1/contourconfig.go @@ -757,6 +757,19 @@ type NetworkParameters struct { // Contour's default is 9001. // +optional EnvoyAdminPort *int `json:"adminPort,omitempty"` + + // EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + // before any processing of request by HTTP filters or routing. This + // affects the upstream host header. Without setting this option to true, incoming + // requests with host example.com. will not match against route with domains + // match set to example.com. + // + // See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + // for more information. + // + // Contour's default is false. + // +optional + EnvoyStripTrailingHostDot *bool `json:"stripTrailingHostDot,omitempty"` } // RateLimitServiceConfig defines properties of a global Rate Limit Service. diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index 1c48f9fce88..acb4fc5524e 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -464,6 +464,7 @@ func (s *Server) doServe() error { MergeSlashes: !*contourConfiguration.Envoy.Listener.DisableMergeSlashes, ServerHeaderTransformation: contourConfiguration.Envoy.Listener.ServerHeaderTransformation, XffNumTrustedHops: *contourConfiguration.Envoy.Network.XffNumTrustedHops, + StripTrailingHostDot: *contourConfiguration.Envoy.Network.EnvoyStripTrailingHostDot, ConnectionBalancer: contourConfiguration.Envoy.Listener.ConnectionBalancer, MaxRequestsPerConnection: contourConfiguration.Envoy.Listener.MaxRequestsPerConnection, HTTP2MaxConcurrentStreams: contourConfiguration.Envoy.Listener.HTTP2MaxConcurrentStreams, diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go index 51a6c3a726a..4457a4e64cb 100644 --- a/cmd/contour/servecontext.go +++ b/cmd/contour/servecontext.go @@ -580,8 +580,9 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_v1alpha1.Co }, }, Network: &contour_v1alpha1.NetworkParameters{ - XffNumTrustedHops: &ctx.Config.Network.XffNumTrustedHops, - EnvoyAdminPort: &ctx.Config.Network.EnvoyAdminPort, + XffNumTrustedHops: &ctx.Config.Network.XffNumTrustedHops, + EnvoyAdminPort: &ctx.Config.Network.EnvoyAdminPort, + EnvoyStripTrailingHostDot: &ctx.Config.Network.EnvoyStripTrailingHostDot, }, }, Gateway: gatewayConfig, diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go index 5187bcc090d..cea25b2c723 100644 --- a/cmd/contour/servecontext_test.go +++ b/cmd/contour/servecontext_test.go @@ -484,8 +484,9 @@ func TestConvertServeContext(t *testing.T) { }, }, Network: &contour_v1alpha1.NetworkParameters{ - EnvoyAdminPort: ptr.To(9001), - XffNumTrustedHops: ptr.To(uint32(0)), + EnvoyAdminPort: ptr.To(9001), + XffNumTrustedHops: ptr.To(uint32(0)), + EnvoyStripTrailingHostDot: ptr.To(false), }, }, Gateway: nil, diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml index c1f6eacc65b..3f3f416f5d1 100644 --- a/examples/contour/01-crds.yaml +++ b/examples/contour/01-crds.yaml @@ -521,6 +521,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- @@ -4323,6 +4334,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml index 1b89dcd4a1c..ee0195ac9a4 100644 --- a/examples/render/contour-deployment.yaml +++ b/examples/render/contour-deployment.yaml @@ -741,6 +741,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- @@ -4543,6 +4554,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index 31b631cca9a..41d3692955c 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -532,6 +532,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- @@ -4334,6 +4345,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index f37bdc1a9b5..f256e725bb9 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -557,6 +557,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- @@ -4359,6 +4370,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml index 5361950a894..a8a563bc22e 100644 --- a/examples/render/contour.yaml +++ b/examples/render/contour.yaml @@ -741,6 +741,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- @@ -4543,6 +4554,17 @@ spec: Contour's default is 0. format: int32 type: integer + stripTrailingHostDot: + description: |- + EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + before any processing of request by HTTP filters or routing. This + affects the upstream host header. Without setting this option to true, incoming + requests with host example.com. will not match against route with domains + match set to example.com. + See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + for more information. + Contour's default is false. + type: boolean type: object service: description: |- diff --git a/internal/contourconfig/contourconfiguration.go b/internal/contourconfig/contourconfiguration.go index 0c369f170cb..7c2f822658b 100644 --- a/internal/contourconfig/contourconfiguration.go +++ b/internal/contourconfig/contourconfiguration.go @@ -128,8 +128,9 @@ func Defaults() contour_v1alpha1.ContourConfigurationSpec { }, }, Network: &contour_v1alpha1.NetworkParameters{ - XffNumTrustedHops: ptr.To(uint32(0)), - EnvoyAdminPort: ptr.To(9001), + XffNumTrustedHops: ptr.To(uint32(0)), + EnvoyAdminPort: ptr.To(9001), + EnvoyStripTrailingHostDot: ptr.To(false), }, }, Gateway: nil, diff --git a/internal/contourconfig/contourconfiguration_test.go b/internal/contourconfig/contourconfiguration_test.go index bb13b8229da..c1cc3efae83 100644 --- a/internal/contourconfig/contourconfiguration_test.go +++ b/internal/contourconfig/contourconfiguration_test.go @@ -131,8 +131,9 @@ func TestOverlayOnDefaults(t *testing.T) { }, }, Network: &contour_v1alpha1.NetworkParameters{ - XffNumTrustedHops: ptr.To(uint32(77)), - EnvoyAdminPort: ptr.To(9997), + XffNumTrustedHops: ptr.To(uint32(77)), + EnvoyAdminPort: ptr.To(9997), + EnvoyStripTrailingHostDot: ptr.To(true), }, }, Gateway: &contour_v1alpha1.GatewayConfig{ diff --git a/internal/envoy/v3/listener.go b/internal/envoy/v3/listener.go index 213a71af9bf..810a546ea08 100644 --- a/internal/envoy/v3/listener.go +++ b/internal/envoy/v3/listener.go @@ -184,6 +184,7 @@ type httpConnectionManagerBuilder struct { serverHeaderTransformation envoy_filter_network_http_connection_manager_v3.HttpConnectionManager_ServerHeaderTransformation forwardClientCertificate *dag.ClientCertificateDetails numTrustedHops uint32 + stripTrailingHostDot bool tracingConfig *envoy_filter_network_http_connection_manager_v3.HttpConnectionManager_Tracing maxRequestsPerConnection *uint32 http2MaxConcurrentStreams *uint32 @@ -293,6 +294,11 @@ func (b *httpConnectionManagerBuilder) NumTrustedHops(num uint32) *httpConnectio return b } +func (b *httpConnectionManagerBuilder) StripTrailingHostDot(strip bool) *httpConnectionManagerBuilder { + b.stripTrailingHostDot = strip + return b +} + // MaxRequestsPerConnection sets max requests per connection for the downstream. func (b *httpConnectionManagerBuilder) MaxRequestsPerConnection(maxRequestsPerConnection *uint32) *httpConnectionManagerBuilder { b.maxRequestsPerConnection = maxRequestsPerConnection @@ -505,8 +511,9 @@ func (b *httpConnectionManagerBuilder) Get() *envoy_config_listener_v3.Filter { AllowChunkedLength: b.allowChunkedLength, }, - UseRemoteAddress: wrapperspb.Bool(true), - XffNumTrustedHops: b.numTrustedHops, + UseRemoteAddress: wrapperspb.Bool(true), + XffNumTrustedHops: b.numTrustedHops, + StripTrailingHostDot: b.stripTrailingHostDot, NormalizePath: wrapperspb.Bool(true), diff --git a/internal/envoy/v3/listener_test.go b/internal/envoy/v3/listener_test.go index e2aa3a64fee..927cf72e89c 100644 --- a/internal/envoy/v3/listener_test.go +++ b/internal/envoy/v3/listener_test.go @@ -662,6 +662,7 @@ func TestHTTPConnectionManager(t *testing.T) { serverHeaderTranformation contour_v1alpha1.ServerHeaderTransformationType forwardClientCertificate *dag.ClientCertificateDetails xffNumTrustedHops uint32 + stripTrailingHostDot bool maxRequestsPerConnection *uint32 http2MaxConcurrentStreams *uint32 want *envoy_config_listener_v3.Filter @@ -1359,6 +1360,54 @@ func TestHTTPConnectionManager(t *testing.T) { }, }, }, + "enable StripTrailingHostDot": { + routename: "default/kuard", + accesslogger: FileAccessLogEnvoy("/dev/stdout", "", nil, contour_v1alpha1.LogLevelInfo), + stripTrailingHostDot: true, + want: &envoy_config_listener_v3.Filter{ + Name: wellknown.HTTPConnectionManager, + ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&envoy_filter_network_http_connection_manager_v3.HttpConnectionManager{ + StatPrefix: "default/kuard", + RouteSpecifier: &envoy_filter_network_http_connection_manager_v3.HttpConnectionManager_Rds{ + Rds: &envoy_filter_network_http_connection_manager_v3.Rds{ + RouteConfigName: "default/kuard", + ConfigSource: &envoy_config_core_v3.ConfigSource{ + ResourceApiVersion: envoy_config_core_v3.ApiVersion_V3, + ConfigSourceSpecifier: &envoy_config_core_v3.ConfigSource_ApiConfigSource{ + ApiConfigSource: &envoy_config_core_v3.ApiConfigSource{ + ApiType: envoy_config_core_v3.ApiConfigSource_GRPC, + TransportApiVersion: envoy_config_core_v3.ApiVersion_V3, + GrpcServices: []*envoy_config_core_v3.GrpcService{{ + TargetSpecifier: &envoy_config_core_v3.GrpcService_EnvoyGrpc_{ + EnvoyGrpc: &envoy_config_core_v3.GrpcService_EnvoyGrpc{ + ClusterName: "contour", + Authority: "contour", + }, + }, + }}, + }, + }, + }, + }, + }, + HttpFilters: defaultHTTPFilters, + HttpProtocolOptions: &envoy_config_core_v3.Http1ProtocolOptions{ + // Enable support for HTTP/1.0 requests that carry + // a Host: header. See #537. + AcceptHttp_10: true, + }, + CommonHttpProtocolOptions: &envoy_config_core_v3.HttpProtocolOptions{}, + AccessLog: FileAccessLogEnvoy("/dev/stdout", "", nil, contour_v1alpha1.LogLevelInfo), + UseRemoteAddress: wrapperspb.Bool(true), + NormalizePath: wrapperspb.Bool(true), + PreserveExternalRequestId: true, + MergeSlashes: false, + StripTrailingHostDot: true, + }), + }, + }, + }, "maxRequestsPerConnection set to 1": { routename: "default/kuard", accesslogger: FileAccessLogEnvoy("/dev/stdout", "", nil, contour_v1alpha1.LogLevelInfo), @@ -1475,6 +1524,7 @@ func TestHTTPConnectionManager(t *testing.T) { MergeSlashes(tc.mergeSlashes). ServerHeaderTransformation(tc.serverHeaderTranformation). NumTrustedHops(tc.xffNumTrustedHops). + StripTrailingHostDot(tc.stripTrailingHostDot). ForwardClientCertificate(tc.forwardClientCertificate). MaxRequestsPerConnection(tc.maxRequestsPerConnection). HTTP2MaxConcurrentStreams(tc.http2MaxConcurrentStreams). diff --git a/internal/featuretests/v3/listeners_test.go b/internal/featuretests/v3/listeners_test.go index 8167dc6dfe5..c465452259b 100644 --- a/internal/featuretests/v3/listeners_test.go +++ b/internal/featuretests/v3/listeners_test.go @@ -1211,6 +1211,60 @@ func TestHTTPProxyXffNumTrustedHops(t *testing.T) { }) } +func TestHTTPProxyStripTrailingHostDot(t *testing.T) { + rh, c, done := setup(t, func(conf *xdscache_v3.ListenerConfig) { + conf.StripTrailingHostDot = true + }) + + defer done() + + rh.OnAdd(fixture.NewService("backend"). + WithPorts(core_v1.ServicePort{Name: "http", Port: 80})) + + // p1 is a httpproxy + p1 := &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: "default", + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "kuard.example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: []contour_v1.MatchCondition{{ + Prefix: "/", + }}, + Services: []contour_v1.Service{{ + Name: "backend", + Port: 80, + }}, + }}, + }, + } + rh.OnAdd(p1) + + // verify that the xff-num-trusted-hops have been set to 1. + httpListener := defaultHTTPListener() + + httpListener.FilterChains = envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). + RouteConfigName("ingress_http"). + MetricsPrefix("ingress_http"). + AccessLoggers(envoy_v3.FileAccessLogEnvoy("/dev/stdout", "", nil, contour_v1alpha1.LogLevelInfo)). + RequestTimeout(timeout.DurationSetting(0)). + StripTrailingHostDot(true). + DefaultFilters(). + Get()) + + c.Request(listenerType).Equals(&envoy_service_discovery_v3.DiscoveryResponse{ + Resources: resources(t, + httpListener, + statsListener(), + ), + TypeUrl: listenerType, + }) +} + func TestHTTPProxyServerHeaderTransformation(t *testing.T) { rh, c, done := setup(t, func(conf *xdscache_v3.ListenerConfig) { conf.ServerHeaderTransformation = contour_v1alpha1.AppendIfAbsentServerHeader diff --git a/internal/xdscache/v3/listener.go b/internal/xdscache/v3/listener.go index 6176fdcaad0..8f06ba749e9 100644 --- a/internal/xdscache/v3/listener.go +++ b/internal/xdscache/v3/listener.go @@ -120,6 +120,10 @@ type ListenerConfig struct { // right side of the x-forwarded-for HTTP header to trust. XffNumTrustedHops uint32 + // StripTrailingHostDot sets if trailing dot of the host should be removed from host/authority header before any + // processing of request by HTTP filters or routing. + StripTrailingHostDot bool + // ConnectionBalancer // The validated value is 'exact'. // If no configuration is specified, Envoy will not attempt to balance active connections between worker threads @@ -408,6 +412,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { MergeSlashes(cfg.MergeSlashes). ServerHeaderTransformation(cfg.ServerHeaderTransformation). NumTrustedHops(cfg.XffNumTrustedHops). + StripTrailingHostDot(cfg.StripTrailingHostDot). MaxRequestsPerConnection(cfg.MaxRequestsPerConnection). HTTP2MaxConcurrentStreams(cfg.HTTP2MaxConcurrentStreams). AddFilter(httpGlobalExternalAuthConfig(cfg.GlobalExternalAuthConfig)). @@ -483,6 +488,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { MergeSlashes(cfg.MergeSlashes). ServerHeaderTransformation(cfg.ServerHeaderTransformation). NumTrustedHops(cfg.XffNumTrustedHops). + StripTrailingHostDot(cfg.StripTrailingHostDot). Tracing(envoy_v3.TracingConfig(envoyTracingConfig(cfg.TracingConfig))). AddFilter(envoy_v3.GlobalRateLimitFilter(envoyGlobalRateLimitConfig(cfg.RateLimitConfig))). ForwardClientCertificate(forwardClientCertificate). @@ -564,6 +570,7 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { MergeSlashes(cfg.MergeSlashes). ServerHeaderTransformation(cfg.ServerHeaderTransformation). NumTrustedHops(cfg.XffNumTrustedHops). + StripTrailingHostDot(cfg.StripTrailingHostDot). Tracing(envoy_v3.TracingConfig(envoyTracingConfig(cfg.TracingConfig))). AddFilter(envoy_v3.GlobalRateLimitFilter(envoyGlobalRateLimitConfig(cfg.RateLimitConfig))). ForwardClientCertificate(forwardClientCertificate). diff --git a/internal/xdscache/v3/listener_test.go b/internal/xdscache/v3/listener_test.go index 095f248210a..086654fc14e 100644 --- a/internal/xdscache/v3/listener_test.go +++ b/internal/xdscache/v3/listener_test.go @@ -2173,6 +2173,48 @@ func TestListenerVisit(t *testing.T) { SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), }), }, + "httpproxy with StripTrailingHostDot set in listener config": { + ListenerConfig: ListenerConfig{ + StripTrailingHostDot: true, + }, + objs: []any{ + &contour_v1.HTTPProxy{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "simple", + Namespace: "default", + }, + Spec: contour_v1.HTTPProxySpec{ + VirtualHost: &contour_v1.VirtualHost{ + Fqdn: "www.example.com", + }, + Routes: []contour_v1.Route{{ + Conditions: []contour_v1.MatchCondition{{ + Prefix: "/", + }}, + Services: []contour_v1.Service{{ + Name: "backend", + Port: 80, + }}, + }}, + }, + }, + service, + }, + want: listenermap(&envoy_config_listener_v3.Listener{ + Name: ENVOY_HTTP_LISTENER, + Address: envoy_v3.SocketAddress("0.0.0.0", 8080), + FilterChains: envoy_v3.FilterChains( + envoy_v3.HTTPConnectionManagerBuilder(). + RouteConfigName(ENVOY_HTTP_LISTENER). + MetricsPrefix(ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, contour_v1alpha1.LogLevelInfo)). + DefaultFilters(). + StripTrailingHostDot(true). + Get(), + ), + SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), + }), + }, "httpsproxy with secret with stream idle timeout set in listener config": { ListenerConfig: ListenerConfig{ Timeouts: contourconfig.Timeouts{ diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index 04931c8d349..b90b84767f2 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -482,6 +482,16 @@ type NetworkParameters struct { // Configure the port used to access the Envoy Admin interface. // If configured to port "0" then the admin interface is disabled. EnvoyAdminPort int `yaml:"admin-port,omitempty"` + + // EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header + // before any processing of request by HTTP filters or routing. This + // affects the upstream host header. Without setting this option to true, incoming + // requests with host example.com. will not match against route with domains + // match set to example.com. + // + // See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot + // for more information. + EnvoyStripTrailingHostDot bool `yaml:"strip-trailing-host-dot,omitempty"` } // ListenerParameters hold various configurable listener values. @@ -1067,8 +1077,9 @@ func Defaults() Parameters { DNSLookupFamily: AutoClusterDNSFamily, }, Network: NetworkParameters{ - XffNumTrustedHops: 0, - EnvoyAdminPort: 9001, + XffNumTrustedHops: 0, + EnvoyStripTrailingHostDot: false, + EnvoyAdminPort: 9001, }, Listener: ListenerParameters{ ConnectionBalancer: "", diff --git a/pkg/config/parameters_test.go b/pkg/config/parameters_test.go index 7f6ad7a7dcd..93489e3c01d 100644 --- a/pkg/config/parameters_test.go +++ b/pkg/config/parameters_test.go @@ -460,6 +460,15 @@ network: admin-port: 9001 `) + check(func(t *testing.T, conf *Parameters) { + assert.True(t, conf.Network.EnvoyStripTrailingHostDot) + }, ` +network: + strip-trailing-host-dot: true + num-trusted-hops: 0 + admin-port: 9001 +`) + check(func(t *testing.T, conf *Parameters) { assert.Equal(t, ptr.To(uint32(1)), conf.Listener.MaxRequestsPerConnection) }, ` diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html index ad1062f70d4..5c84a9bb522 100644 --- a/site/content/docs/main/config/api-reference.html +++ b/site/content/docs/main/config/api-reference.html @@ -8266,6 +8266,26 @@

NetworkParameters

Contour’s default is 9001.

+ + +stripTrailingHostDot +
+ +bool + + + +(Optional) +

EnvoyStripTrailingHostDot defines if trailing dot of the host should be removed from host/authority header +before any processing of request by HTTP filters or routing. This +affects the upstream host header. Without setting this option to true, incoming +requests with host example.com. will not match against route with domains +match set to example.com.

+

See https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto?highlight=strip_trailing_host_dot +for more information.

+

Contour’s default is false.

+ +

NetworkPublishing