diff --git a/_integration/testsuite/httpproxy/004-https-sni-enforcement.yaml b/_integration/testsuite/httpproxy/004-https-sni-enforcement.yaml index 3b1c3fee297..bdef79e0299 100644 --- a/_integration/testsuite/httpproxy/004-https-sni-enforcement.yaml +++ b/_integration/testsuite/httpproxy/004-https-sni-enforcement.yaml @@ -117,7 +117,7 @@ fatal_proxy_is_not_present[msg] { msg := sprintf("HTTPProxy for %q is not present", [ fqdn ]) } ---- +--- Name := "echo-one" @@ -243,7 +243,7 @@ fatal_proxy_is_not_present[msg] { msg := sprintf("HTTPProxy for %q is not present", [ fqdn ]) } ---- +--- Name := "echo-two" @@ -309,9 +309,10 @@ error_path_routing_mismatch[msg] { --- import data.contour.http.client +import data.contour.http.response # Ensure that sending a request to "echo-one" with the SNI from "echo-two" -# generates a 404. +# generates a 4xx response status. Response := client.Get({ "url": sprintf("https://%s/https-sni-enforcement/%d", [ @@ -324,23 +325,18 @@ Response := client.Get({ "tls_server_name": "echo-two.projectcontour.io", }) -Wanted := 404 - -error_non_404_response [msg] { - Response.status_code != Wanted - - msg := sprintf("got status %d, wanted %d", [ - Response.status_code, Wanted - ]) +error_non_400_response [msg] { + not response.is_4xx(Response) + msg := sprintf("got status %d, wanted 4xx", [ Response.status_code ]) } - --- import data.contour.http.client +import data.contour.http.response # Ensure that sending a request to "echo-two" with the SNI from "echo-one" -# generates a 404. +# generates a 4xx response status. Response := client.Get({ "url": sprintf("https://%s/https-sni-enforcement/%d", [ @@ -353,18 +349,7 @@ Response := client.Get({ "tls_server_name": "echo-one.projectcontour.io", }) -Wanted := 404 - -error_no_response { - not Response -} - error_non_404_response [msg] { - Response.status_code != Wanted - - msg := sprintf("got status %d, wanted %d", [ - Response.status_code, Wanted - ]) + not response.is_4xx(Response) + msg := sprintf("got status %d, wanted 4xx", [ Response.status_code ]) } - - diff --git a/_integration/testsuite/httpproxy/009-https-misdirected-request.yaml b/_integration/testsuite/httpproxy/009-https-misdirected-request.yaml new file mode 100644 index 00000000000..71b27fb432b --- /dev/null +++ b/_integration/testsuite/httpproxy/009-https-misdirected-request.yaml @@ -0,0 +1,192 @@ +# Copyright 2020 VMware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import data.contour.resources + +# Ensure that cert-manager is installed. +# Version check the certificates resource. + +Group := "cert-manager.io" +Version := "v1alpha2" + +have_certmanager_version { + v := resources.versions["certificates"] + v[_].Group == Group + v[_].Version == Version +} + +skip[msg] { + not resources.is_supported("certificates") + msg := "cert-manager is not installed" +} + +skip[msg] { + not have_certmanager_version + + avail := resources.versions["certificates"] + + msg := concat("\n", [ + sprintf("cert-manager version %s/%s is not installed", [Group, Version]), + "available versions:", + yaml.marshal(avail) + ]) +} + +--- + +# Create a self-signed issuer to give us secrets. + +apiVersion: cert-manager.io/v1alpha2 +kind: Issuer +metadata: + name: selfsigned +spec: + selfSigned: {} + +--- + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ingress-conformance-echo +$apply: + fixture: + as: echo + +--- + +apiVersion: v1 +kind: Service +metadata: + name: ingress-conformance-echo +$apply: + fixture: + as: echo + +--- + +apiVersion: cert-manager.io/v1alpha2 +kind: Certificate +metadata: + name: echo-cert +spec: + dnsNames: + - echo.projectcontour.io + secretName: echo + issuerRef: + name: selfsigned + +--- + +apiVersion: projectcontour.io/v1 +kind: HTTPProxy +metadata: + name: echo +spec: + virtualhost: + fqdn: echo.projectcontour.io + tls: + secretName: echo + routes: + - services: + - name: echo + port: 80 + +--- + +import data.contour.resources + +Name := "echo" + +fatal_proxy_is_not_present[msg] { + not resources.is_present("httpproxies", Name) + msg := sprintf("HTTPProxy for %q is not present", [ Name ]) +} + +--- + +import data.contour.resources + +Name := "echo" + +fatal_proxy_is_not_valid[msg] { + status := resources.status("httpproxies", Name) + + object.get(status, "currentStatus", "") != "valid" + + msg := sprintf("HTTPProxy %q is not valid\n%s", [ + Name, yaml.marshal(status) + ]) +} + +--- + +import data.contour.http.client +import data.contour.http.request +import data.contour.http.response + +Response := client.Get({ + "url": sprintf("https://%s/misdirected/%d", [ + client.target_addr, time.now_ns() + ]), + "headers": { + "Host": "echo.projectcontour.io", + "User-Agent": client.ua("misdirected-request"), + }, + "tls_insecure_skip_verify": true, +}) + +error_non_200_response [msg] { + not response.status_is(Response, 200) + msg := sprintf("got status %d, wanted %d", [Response.status_code, 200]) +} + +error_wrong_routing [msg] { + not response.has_testid(Response) + msg := "response has missing body or test ID" +} + +error_wrong_routing[msg] { + wanted := "echo" + testid := response.testid(Response) + testid != wanted + msg := sprintf("got test ID %q, wanted %q", [testid, wanted]) +} + +--- + +import data.contour.http.client +import data.contour.http.request +import data.contour.http.response + +# Send a request with a Host header that doesn't match the SNI name that +# we have for the proxy document. We expect the mismatch will generate a +# 421 response, not 404. + +Response := client.Get({ + "url": sprintf("https://%s/misdirected/%d", [ + client.target_addr, time.now_ns() + ]), + "headers": { + "Host": "echo-two.projectcontour.io", + "User-Agent": client.ua("misdirected-request"), + }, + "tls_server_name": "echo.projectcontour.io", + "tls_insecure_skip_verify": true, +}) + +error_non_421_response [msg] { + not response.status_is(Response, 421) + msg := sprintf("got status %d, wanted %d", [Response.status_code, 421]) +} diff --git a/_integration/testsuite/policies/contour-client.rego b/_integration/testsuite/policies/contour-client.rego index 97b741a6b82..3197d528216 100644 --- a/_integration/testsuite/policies/contour-client.rego +++ b/_integration/testsuite/policies/contour-client.rego @@ -38,4 +38,12 @@ Get(params) = response { } response := http.send(object.union(to_send, params)) +} else = response { + # If the Get wasn't evaluated for any reason, return a dummy object to ensure + # subsequent field references are valid. + response := { + "status_code": 0, + "body": {}, + "headers": {}, + } } diff --git a/_integration/testsuite/policies/contour-resources.rego b/_integration/testsuite/policies/contour-resources.rego index dab9af2cb53..ade42935b55 100644 --- a/_integration/testsuite/policies/contour-resources.rego +++ b/_integration/testsuite/policies/contour-resources.rego @@ -81,3 +81,14 @@ get(resource, name) = obj { } else = obj { obj := {} } + +# status returns the status field of the named resource. If the resource +# is not present, and empty object is returned. Implemented in terms of +# 'get', so namespace syntax works for the object name. +# +# Examples: +# resources.status("httpproxies", "foo") +status(resource, name) = s { + r := get(resource, name) + s := object.get(r, "status", {}) +} diff --git a/_integration/testsuite/policies/contour-response.rego b/_integration/testsuite/policies/contour-response.rego index eef84d5fd22..a24d588ca7a 100644 --- a/_integration/testsuite/policies/contour-response.rego +++ b/_integration/testsuite/policies/contour-response.rego @@ -44,3 +44,20 @@ testid(resp) = value { b := body(resp) value := object.get(b, "TestId", "") } + +# Return true if the response status matches. +status_is(resp, expected_code) = true { + status_code := object.get(resp, "status_code", 0) + status_code == expected_code +} else = false { + true +} + +# Return true if the response status is in the 4xx range. +is_4xx(resp) = true { + status_code := object.get(resp, "status_code", 0) + status_code >= 400 + status_code < 500 +} else = false { + true +} diff --git a/internal/contour/listener.go b/internal/contour/listener.go index c1331aba4cc..fa732c4ad89 100644 --- a/internal/contour/listener.go +++ b/internal/contour/listener.go @@ -1,4 +1,4 @@ -// Copyright © 2019 VMware +// Copyright © 2020 VMware // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -298,6 +298,7 @@ func visitListeners(root dag.Vertex, lvc *ListenerVisitorConfig) map[string]*v2. if lv.http { // Add a listener if there are vhosts bound to http. cm := envoy.HTTPConnectionManagerBuilder(). + DefaultFilters(). RouteConfigName(ENVOY_HTTP_LISTENER). MetricsPrefix(ENVOY_HTTP_LISTENER). AccessLoggers(lvc.newInsecureAccessLog()). @@ -366,6 +367,8 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) { // coded into monitoring dashboards. filters = envoy.Filters( envoy.HTTPConnectionManagerBuilder(). + AddFilter(envoy.FilterMisdirectedRequests(vh.VirtualHost.Name)). + DefaultFilters(). RouteConfigName(path.Join("https", vh.VirtualHost.Name)). MetricsPrefix(ENVOY_HTTPS_LISTENER). AccessLoggers(v.ListenerVisitorConfig.newSecureAccessLog()). @@ -403,10 +406,12 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) { v.listeners[ENVOY_HTTPS_LISTENER].FilterChains = append(v.listeners[ENVOY_HTTPS_LISTENER].FilterChains, envoy.FilterChainTLS(vh.VirtualHost.Name, downstreamTLS, filters)) - // If this VirtualHost has enabled the fallback certificate then set a default FilterChain which will allow - // routes with this vhost to accept non SNI TLS requests + // If this VirtualHost has enabled the fallback certificate then set a default + // FilterChain which will allow routes with this vhost to accept non-SNI TLS requests. + // Note that we don't add the misdirected requests filter on this chain because at this + // point we don't actually know the full set of server names that will be bound to the + // filter chain through the ENVOY_FALLBACK_ROUTECONFIG route configuration. if vh.FallbackCertificate != nil && !envoy.ContainsFallbackFilterChain(v.listeners[ENVOY_HTTPS_LISTENER].FilterChains) { - // Construct the downstreamTLSContext passing the configured fallbackCertificate. The TLS minProtocolVersion will use // the value defined in the Contour Configuration file if defined. downstreamTLS = envoy.DownstreamTLSContext( diff --git a/internal/contour/listener_test.go b/internal/contour/listener_test.go index 2d970392224..0a8497463b1 100644 --- a/internal/contour/listener_test.go +++ b/internal/contour/listener_test.go @@ -1,4 +1,4 @@ -// Copyright © 2019 VMware +// Copyright © 2020 VMware // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -129,6 +129,8 @@ func TestListenerCacheQuery(t *testing.T) { func TestListenerVisit(t *testing.T) { httpsFilterFor := func(vhost string) *envoy_api_v2_listener.Filter { return envoy.HTTPConnectionManagerBuilder(). + AddFilter(envoy.FilterMisdirectedRequests(vhost)). + DefaultFilters(). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(path.Join("https", vhost)). AccessLoggers(envoy.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG)). @@ -790,6 +792,8 @@ func TestListenerVisit(t *testing.T) { }, TransportSocket: transportSocket("secret", envoy_api_v2_auth.TlsParameters_TLSv1_1, "h2", "http/1.1"), Filters: envoy.Filters(envoy.HTTPConnectionManagerBuilder(). + AddFilter(envoy.FilterMisdirectedRequests("whatever.example.com")). + DefaultFilters(). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(path.Join("https", "whatever.example.com")). AccessLoggers(envoy.FileAccessLogEnvoy("/tmp/https_access.log")). diff --git a/internal/e2e/lds_test.go b/internal/e2e/lds_test.go index eee60075bc5..7f6e138ae52 100644 --- a/internal/e2e/lds_test.go +++ b/internal/e2e/lds_test.go @@ -1,4 +1,4 @@ -// Copyright © 2019 VMware +// Copyright © 2020 VMware // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -15,6 +15,7 @@ package e2e import ( "context" + "path" "testing" v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" @@ -32,6 +33,16 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" ) +func httpsFilterFor(vhost string) *envoy_api_v2_listener.Filter { + return envoy.HTTPConnectionManagerBuilder(). + AddFilter(envoy.FilterMisdirectedRequests(vhost)). + DefaultFilters(). + RouteConfigName(path.Join("https", vhost)). + MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). + AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). + Get() +} + func TestNonTLSListener(t *testing.T) { rh, cc, done := setup(t) defer done() @@ -227,11 +238,7 @@ func TestTLSListener(t *testing.T) { envoy.TLSInspector(), ), FilterChains: filterchaintls("kuard.example.com", s1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), + httpsFilterFor("kuard.example.com"), "h2", "http/1.1"), }, staticListener(), @@ -279,11 +286,7 @@ func TestTLSListener(t *testing.T) { envoy.TLSInspector(), ), FilterChains: filterchaintls("kuard.example.com", s1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), + httpsFilterFor("kuard.example.com"), "h2", "http/1.1"), }, staticListener(), @@ -400,11 +403,7 @@ func TestIngressRouteTLSListener(t *testing.T) { envoy.TLSInspector(), ), FilterChains: filterchaintls("kuard.example.com", secret1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), + httpsFilterFor("kuard.example.com"), "h2", "http/1.1"), } @@ -460,13 +459,7 @@ func TestIngressRouteTLSListener(t *testing.T) { envoy_api_v2_auth.TlsParameters_TLSv1_3, nil, "h2", "http/1.1"), - envoy.Filters( - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - ), + envoy.Filters(httpsFilterFor("kuard.example.com")), ), }, } @@ -558,11 +551,7 @@ func TestLDSFilter(t *testing.T) { envoy.TLSInspector(), ), FilterChains: filterchaintls("kuard.example.com", s1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), + httpsFilterFor("kuard.example.com"), "h2", "http/1.1"), }, ), @@ -747,11 +736,7 @@ func TestLDSIngressHTTPSUseProxyProtocol(t *testing.T) { envoy.TLSInspector(), ), FilterChains: filterchaintls("kuard.example.com", s1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), + httpsFilterFor("kuard.example.com"), "h2", "http/1.1"), } assert.Equal(t, &v2.DiscoveryResponse{ @@ -861,13 +846,7 @@ func TestLDSCustomAddressAndPort(t *testing.T) { envoy.TLSInspector(), ), FilterChains: filterchaintls("kuard.example.com", s1, - - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - + httpsFilterFor("kuard.example.com"), "h2", "http/1.1"), } assert.Equal(t, &v2.DiscoveryResponse{ @@ -967,11 +946,12 @@ func TestLDSCustomAccessLogPaths(t *testing.T) { ), FilterChains: filterchaintls("kuard.example.com", s1, envoy.HTTPConnectionManagerBuilder(). + AddFilter(envoy.FilterMisdirectedRequests("kuard.example.com")). + DefaultFilters(). RouteConfigName("https/kuard.example.com"). MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). AccessLoggers(envoy.FileAccessLogEnvoy("/tmp/https_access.log")). Get(), - "h2", "http/1.1"), } assert.Equal(t, &v2.DiscoveryResponse{ @@ -1071,11 +1051,7 @@ func TestIngressRouteHTTPS(t *testing.T) { envoy.TLSInspector(), ), FilterChains: filterchaintls("example.com", s1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), + httpsFilterFor("example.com"), "h2", "http/1.1"), } assert.Equal(t, &v2.DiscoveryResponse{ @@ -1162,13 +1138,7 @@ func TestIngressRouteMinimumTLSVersion(t *testing.T) { envoy_api_v2_auth.TlsParameters_TLSv1_2, nil, "h2", "http/1.1"), - envoy.Filters( - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - ), + envoy.Filters(httpsFilterFor("kuard.example.com")), ), }, } @@ -1230,13 +1200,7 @@ func TestIngressRouteMinimumTLSVersion(t *testing.T) { envoy_api_v2_auth.TlsParameters_TLSv1_3, nil, "h2", "http/1.1"), - envoy.Filters( - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - ), + envoy.Filters(httpsFilterFor("kuard.example.com")), ), }, } diff --git a/internal/envoy/listener.go b/internal/envoy/listener.go index ab14490200a..dc30c6a9a94 100644 --- a/internal/envoy/listener.go +++ b/internal/envoy/listener.go @@ -1,4 +1,4 @@ -// Copyright © 2019 VMware +// Copyright © 2020 VMware // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -14,6 +14,7 @@ package envoy import ( + "fmt" "sort" "time" @@ -22,6 +23,7 @@ import ( envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2" + lua "github.com/envoyproxy/go-control-plane/envoy/config/filter/http/lua/v2" http "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2" tcp "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/tcp_proxy/v2" "github.com/envoyproxy/go-control-plane/pkg/wellknown" @@ -67,6 +69,7 @@ type httpConnectionManagerBuilder struct { metricsPrefix string accessLoggers []*accesslog.AccessLog requestTimeout time.Duration + filters []*http.HttpFilter } // RouteConfigName sets the name of the RDS element that contains @@ -99,6 +102,27 @@ func (b *httpConnectionManagerBuilder) RequestTimeout(timeout time.Duration) *ht return b } +func (b *httpConnectionManagerBuilder) DefaultFilters() *httpConnectionManagerBuilder { + b.filters = append(b.filters, + &http.HttpFilter{ + Name: wellknown.Gzip, + }, + &http.HttpFilter{ + Name: wellknown.GRPCWeb, + }, + &http.HttpFilter{ + Name: wellknown.Router, + }, + ) + + return b +} + +func (b *httpConnectionManagerBuilder) AddFilter(f *http.HttpFilter) *httpConnectionManagerBuilder { + b.filters = append(b.filters, f) + return b +} + // Get returns a new http.HttpConnectionManager filter, constructed // from the builder settings. // @@ -111,13 +135,7 @@ func (b *httpConnectionManagerBuilder) Get() *envoy_api_v2_listener.Filter { ConfigSource: ConfigSource("contour"), }, }, - HttpFilters: []*http.HttpFilter{{ - Name: wellknown.Gzip, - }, { - Name: wellknown.GRPCWeb, - }, { - Name: wellknown.Router, - }}, + HttpFilters: b.filters, CommonHttpProtocolOptions: &envoy_api_v2_core.HttpProtocolOptions{ // Sets the idle timeout for HTTP connections to 60 seconds. // This is chosen as a rough default to stop idle connections wasting resources, @@ -166,6 +184,7 @@ func HTTPConnectionManager(routename string, accesslogger []*accesslog.AccessLog MetricsPrefix(routename). AccessLoggers(accesslogger). RequestTimeout(requestTimeout). + DefaultFilters(). Get() } @@ -281,6 +300,32 @@ func FilterChains(filters ...*envoy_api_v2_listener.Filter) []*envoy_api_v2_list } } +func FilterMisdirectedRequests(fqdn string) *http.HttpFilter { + code := ` +function envoy_on_request(request_handle) + local headers = request_handle:headers() + local host = headers:get(":authority") + + if host ~= "%s" then + request_handle:respond({ + [":status"] = "421", + }, + "" + ) + end +end +` + + return &http.HttpFilter{ + Name: "envoy.filters.http.lua", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&lua.Lua{ + InlineCode: fmt.Sprintf(code, fqdn), + }), + }, + } +} + // FilterChainTLS returns a TLS enabled envoy_api_v2_listener.FilterChain. func FilterChainTLS(domain string, downstream *envoy_api_v2_auth.DownstreamTlsContext, filters []*envoy_api_v2_listener.Filter) *envoy_api_v2_listener.FilterChain { fc := &envoy_api_v2_listener.FilterChain{ diff --git a/internal/featuretests/downstreamvalidation_test.go b/internal/featuretests/downstreamvalidation_test.go index cdf601092cd..18cb8fabbf7 100644 --- a/internal/featuretests/downstreamvalidation_test.go +++ b/internal/featuretests/downstreamvalidation_test.go @@ -18,7 +18,6 @@ import ( v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/dag" "github.com/projectcontour/contour/internal/envoy" "github.com/projectcontour/contour/internal/fixture" @@ -104,18 +103,16 @@ func TestDownstreamTLSCertificateValidation(t *testing.T) { ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), - FilterChains: filterchaintls("example.com", serverTLSSecret, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - &dag.PeerValidationContext{ - CACertificate: &dag.Secret{ - Object: clientCASecret, + FilterChains: appendFilterChains( + filterchaintls("example.com", serverTLSSecret, + httpsFilterFor("example.com"), + &dag.PeerValidationContext{ + CACertificate: &dag.Secret{ + Object: clientCASecret, + }, }, - }, - "h2", "http/1.1", + "h2", "http/1.1", + ), ), } diff --git a/internal/featuretests/envoy.go b/internal/featuretests/envoy.go index 77d6312d155..0df907dcac1 100644 --- a/internal/featuretests/envoy.go +++ b/internal/featuretests/envoy.go @@ -1,4 +1,4 @@ -// Copyright © 2019 VMware +// Copyright © 2020 VMware // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -16,6 +16,7 @@ package featuretests // envoy helpers import ( + "path" "time" v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" @@ -219,18 +220,51 @@ func weightedClusters(clusters []weightedCluster) *envoy_api_v2_route.WeightedCl return &wc } -func filterchaintls(domain string, secret *v1.Secret, filter *envoy_api_v2_listener.Filter, peerValidationContext *dag.PeerValidationContext, alpn ...string) []*envoy_api_v2_listener.FilterChain { - return []*envoy_api_v2_listener.FilterChain{ - envoy.FilterChainTLS( - domain, - envoy.DownstreamTLSContext( - &dag.Secret{Object: secret}, - envoy_api_v2_auth.TlsParameters_TLSv1_1, - peerValidationContext, - alpn...), - envoy.Filters(filter), +// appendFilterChains is a helper to turn variadic FilterChain arguments into the corresponding slice. +func appendFilterChains(chains ...*envoy_api_v2_listener.FilterChain) []*envoy_api_v2_listener.FilterChain { + return chains +} + +// filterchaintls returns a FilterChain wrapping the given virtual host. +func filterchaintls(domain string, secret *v1.Secret, filter *envoy_api_v2_listener.Filter, peerValidationContext *dag.PeerValidationContext, alpn ...string) *envoy_api_v2_listener.FilterChain { + return envoy.FilterChainTLS( + domain, + envoy.DownstreamTLSContext( + &dag.Secret{Object: secret}, + envoy_api_v2_auth.TlsParameters_TLSv1_1, + peerValidationContext, + alpn...), + envoy.Filters(filter), + ) +} + +// filterchaintlsfallback returns a FilterChain for the given TLS fallback certificate. +func filterchaintlsfallback(fallbackSecret *v1.Secret, peerValidationContext *dag.PeerValidationContext, alpn ...string) *envoy_api_v2_listener.FilterChain { + return envoy.FilterChainTLSFallback( + envoy.DownstreamTLSContext( + &dag.Secret{Object: fallbackSecret}, + envoy_api_v2_auth.TlsParameters_TLSv1_1, + peerValidationContext, + alpn...), + envoy.Filters( + envoy.HTTPConnectionManagerBuilder(). + RouteConfigName(contour.ENVOY_FALLBACK_ROUTECONFIG). + MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). + AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). + RequestTimeout(0). + Get(), ), - } + ) +} + +func httpsFilterFor(vhost string) *envoy_api_v2_listener.Filter { + return envoy.HTTPConnectionManagerBuilder(). + AddFilter(envoy.FilterMisdirectedRequests(vhost)). + DefaultFilters(). + RouteConfigName(path.Join("https", vhost)). + MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). + AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). + Get() } func tcpproxy(statPrefix, cluster string) *envoy_api_v2_listener.Filter { @@ -252,32 +286,3 @@ func tcpproxy(statPrefix, cluster string) *envoy_api_v2_listener.Filter { func staticListener() *v2.Listener { return envoy.StatsListener("0.0.0.0", 8002) } - -func filterchaintlsfallback(domain string, domainSecret, fallbackSecret *v1.Secret, filter *envoy_api_v2_listener.Filter, peerValidationContext *dag.PeerValidationContext, alpn ...string) []*envoy_api_v2_listener.FilterChain { - return []*envoy_api_v2_listener.FilterChain{ - envoy.FilterChainTLS( - domain, - envoy.DownstreamTLSContext( - &dag.Secret{Object: domainSecret}, - envoy_api_v2_auth.TlsParameters_TLSv1_1, - peerValidationContext, - alpn...), - envoy.Filters(filter), - ), - envoy.FilterChainTLSFallback( - envoy.DownstreamTLSContext( - &dag.Secret{Object: fallbackSecret}, - envoy_api_v2_auth.TlsParameters_TLSv1_1, - peerValidationContext, - alpn...), - envoy.Filters( - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName(contour.ENVOY_FALLBACK_ROUTECONFIG). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - RequestTimeout(0). - Get(), - ), - ), - } -} diff --git a/internal/featuretests/fallbackcert_test.go b/internal/featuretests/fallbackcert_test.go index c4d2e9b0925..2692c867b4b 100644 --- a/internal/featuretests/fallbackcert_test.go +++ b/internal/featuretests/fallbackcert_test.go @@ -17,9 +17,9 @@ import ( "testing" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" + "github.com/projectcontour/contour/internal/fixture" v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" - "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/envoy" v1 "k8s.io/api/core/v1" @@ -67,12 +67,8 @@ func TestFallbackCertificate(t *testing.T) { rh.OnAdd(s1) // Valid HTTPProxy without FallbackCertificate enabled - proxy1 := &projcontour.HTTPProxy{ - ObjectMeta: metav1.ObjectMeta{ - Name: "simple", - Namespace: s1.Namespace, - }, - Spec: projcontour.HTTPProxySpec{ + proxy1 := fixture.NewProxy("simple").WithSpec( + projcontour.HTTPProxySpec{ VirtualHost: &projcontour.VirtualHost{ Fqdn: "fallback.example.com", TLS: &projcontour.TLS{ @@ -86,11 +82,12 @@ func TestFallbackCertificate(t *testing.T) { Port: 80, }}, }}, - }, - } + }) rh.OnAdd(proxy1) + // We should start with a single generic HTTPS service. c.Request(listenerType, "ingress_https").Equals(&v2.DiscoveryResponse{ + TypeUrl: listenerType, Resources: resources(t, &v2.Listener{ Name: "ingress_https", @@ -98,26 +95,18 @@ func TestFallbackCertificate(t *testing.T) { ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), - FilterChains: filterchaintls("fallback.example.com", sec1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/fallback.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - nil, - "h2", "http/1.1"), + FilterChains: appendFilterChains( + filterchaintls("fallback.example.com", sec1, + httpsFilterFor("fallback.example.com"), + nil, "h2", "http/1.1"), + ), }, ), - TypeUrl: listenerType, }) // Valid HTTPProxy with FallbackCertificate enabled - proxy2 := &projcontour.HTTPProxy{ - ObjectMeta: metav1.ObjectMeta{ - Name: "simple", - Namespace: s1.Namespace, - }, - Spec: projcontour.HTTPProxySpec{ + proxy2 := fixture.NewProxy("simple").WithSpec( + projcontour.HTTPProxySpec{ VirtualHost: &projcontour.VirtualHost{ Fqdn: "fallback.example.com", TLS: &projcontour.TLS{ @@ -131,12 +120,14 @@ func TestFallbackCertificate(t *testing.T) { Port: 80, }}, }}, - }, - } + }) rh.OnUpdate(proxy1, proxy2) + // Now we should still have the generic HTTPS service filter, + // but also the fallback certificate filter. c.Request(listenerType, "ingress_https").Equals(&v2.DiscoveryResponse{ + TypeUrl: listenerType, Resources: resources(t, &v2.Listener{ Name: "ingress_https", @@ -144,26 +135,19 @@ func TestFallbackCertificate(t *testing.T) { ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), - FilterChains: filterchaintlsfallback("fallback.example.com", sec1, fallbackSecret, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/fallback.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - nil, - "h2", "http/1.1"), + FilterChains: appendFilterChains( + filterchaintls("fallback.example.com", sec1, + httpsFilterFor("fallback.example.com"), + nil, "h2", "http/1.1"), + filterchaintlsfallback(fallbackSecret, nil, "h2", "http/1.1"), + ), }, ), - TypeUrl: listenerType, }) - // InValid HTTPProxy with FallbackCertificate enabled along with ClientValidation - proxy3 := &projcontour.HTTPProxy{ - ObjectMeta: metav1.ObjectMeta{ - Name: "simple", - Namespace: s1.Namespace, - }, - Spec: projcontour.HTTPProxySpec{ + // Invalid HTTPProxy with FallbackCertificate enabled along with ClientValidation + proxy3 := fixture.NewProxy("simple").WithSpec( + projcontour.HTTPProxySpec{ VirtualHost: &projcontour.VirtualHost{ Fqdn: "fallback.example.com", TLS: &projcontour.TLS{ @@ -180,23 +164,18 @@ func TestFallbackCertificate(t *testing.T) { Port: 80, }}, }}, - }, - } + }) rh.OnUpdate(proxy2, proxy3) c.Request(listenerType, "ingress_https").Equals(&v2.DiscoveryResponse{ - Resources: nil, TypeUrl: listenerType, + Resources: nil, }) // Valid HTTPProxy with FallbackCertificate enabled - proxy4 := &projcontour.HTTPProxy{ - ObjectMeta: metav1.ObjectMeta{ - Name: "simple-two", - Namespace: s1.Namespace, - }, - Spec: projcontour.HTTPProxySpec{ + proxy4 := fixture.NewProxy("simple-two").WithSpec( + projcontour.HTTPProxySpec{ VirtualHost: &projcontour.VirtualHost{ Fqdn: "anotherfallback.example.com", TLS: &projcontour.TLS{ @@ -210,13 +189,13 @@ func TestFallbackCertificate(t *testing.T) { Port: 80, }}, }}, - }, - } + }) rh.OnUpdate(proxy3, proxy2) // proxy3 is invalid, resolve that to test two valid proxies rh.OnAdd(proxy4) c.Request(listenerType, "ingress_https").Equals(&v2.DiscoveryResponse{ + TypeUrl: listenerType, Resources: resources(t, &v2.Listener{ Name: "ingress_https", @@ -224,30 +203,23 @@ func TestFallbackCertificate(t *testing.T) { ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), - FilterChains: append(filterchaintls("anotherfallback.example.com", sec1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/anotherfallback.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - nil, - "h2", "http/1.1"), filterchaintlsfallback("fallback.example.com", sec1, fallbackSecret, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/fallback.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - nil, - "h2", "http/1.1")...), + FilterChains: appendFilterChains( + filterchaintls("anotherfallback.example.com", sec1, + httpsFilterFor("anotherfallback.example.com"), + nil, "h2", "http/1.1"), + filterchaintls("fallback.example.com", sec1, + httpsFilterFor("fallback.example.com"), + nil, "h2", "http/1.1"), + filterchaintlsfallback(fallbackSecret, nil, "h2", "http/1.1"), + ), }, ), - TypeUrl: listenerType, }) rh.OnDelete(fallbackSecret) c.Request(listenerType, "ingress_https").Equals(&v2.DiscoveryResponse{ - Resources: nil, TypeUrl: listenerType, + Resources: nil, }) } diff --git a/internal/featuretests/tcpproxy_test.go b/internal/featuretests/tcpproxy_test.go index f6860873be1..7b06a12e258 100644 --- a/internal/featuretests/tcpproxy_test.go +++ b/internal/featuretests/tcpproxy_test.go @@ -1,4 +1,4 @@ -// Copyright © 2019 VMware +// Copyright © 2020 VMware // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -88,9 +88,11 @@ func TestTCPProxy(t *testing.T) { c.Request(listenerType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, &v2.Listener{ - Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - FilterChains: filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/correct-backend/80/da39a3ee5e"), nil), + Name: "ingress_https", + Address: envoy.SocketAddress("0.0.0.0", 8443), + FilterChains: appendFilterChains( + filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/correct-backend/80/da39a3ee5e"), nil), + ), ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), @@ -142,9 +144,11 @@ func TestTCPProxy(t *testing.T) { c.Request(listenerType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, &v2.Listener{ - Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - FilterChains: filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/correct-backend/80/da39a3ee5e"), nil), + Name: "ingress_https", + Address: envoy.SocketAddress("0.0.0.0", 8443), + FilterChains: appendFilterChains( + filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/correct-backend/80/da39a3ee5e"), nil), + ), ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), @@ -232,9 +236,11 @@ func TestTCPProxyDelegation(t *testing.T) { c.Request(listenerType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, &v2.Listener{ - Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - FilterChains: filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "app/backend/80/da39a3ee5e"), nil), + Name: "ingress_https", + Address: envoy.SocketAddress("0.0.0.0", 8443), + FilterChains: appendFilterChains( + filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "app/backend/80/da39a3ee5e"), nil), + ), ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), @@ -295,9 +301,11 @@ func TestTCPProxyDelegation(t *testing.T) { c.Request(listenerType).Equals(&v2.DiscoveryResponse{ Resources: resources(t, &v2.Listener{ - Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - FilterChains: filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "app/backend/80/da39a3ee5e"), nil), + Name: "ingress_https", + Address: envoy.SocketAddress("0.0.0.0", 8443), + FilterChains: appendFilterChains( + filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "app/backend/80/da39a3ee5e"), nil), + ), ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), @@ -523,11 +531,10 @@ func TestTCPProxyTLSBackend(t *testing.T) { &v2.Listener{ Name: "ingress_https", Address: envoy.SocketAddress("0.0.0.0", 8443), - FilterChains: filterchaintls( - "k8s.run.ubisoft.org", - s1, - tcpproxy("ingress_https", svc.Namespace+"/"+svc.Name+"/443/da39a3ee5e"), - nil), + FilterChains: appendFilterChains( + filterchaintls("k8s.run.ubisoft.org", s1, + tcpproxy("ingress_https", svc.Namespace+"/"+svc.Name+"/443/da39a3ee5e"), nil), + ), ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), @@ -630,9 +637,11 @@ func TestTCPProxyAndHTTPService(t *testing.T) { &v2.Listener{ // ingress_https is present for // kuard-tcp.example.com:443 terminated at envoy then forwarded to default/backend:80 - Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - FilterChains: filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/backend/80/da39a3ee5e"), nil), + Name: "ingress_https", + Address: envoy.SocketAddress("0.0.0.0", 8443), + FilterChains: appendFilterChains( + filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/backend/80/da39a3ee5e"), nil), + ), ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), @@ -733,9 +742,11 @@ func TestTCPProxyAndHTTPServicePermitInsecure(t *testing.T) { &v2.Listener{ // ingress_https is present for // kuard-tcp.example.com:443 terminated at envoy then tcpproxied to default/backend:80 - Name: "ingress_https", - Address: envoy.SocketAddress("0.0.0.0", 8443), - FilterChains: filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/backend/80/da39a3ee5e"), nil), + Name: "ingress_https", + Address: envoy.SocketAddress("0.0.0.0", 8443), + FilterChains: appendFilterChains( + filterchaintls("kuard-tcp.example.com", s1, tcpproxy("ingress_https", "default/backend/80/da39a3ee5e"), nil), + ), ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), diff --git a/internal/featuretests/tlscertificatedelegation_test.go b/internal/featuretests/tlscertificatedelegation_test.go index e5376f98327..ab368f219d3 100644 --- a/internal/featuretests/tlscertificatedelegation_test.go +++ b/internal/featuretests/tlscertificatedelegation_test.go @@ -1,4 +1,4 @@ -// Copyright © 2019 VMware +// Copyright © 2020 VMware // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -19,7 +19,6 @@ import ( v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2" ingressroutev1 "github.com/projectcontour/contour/apis/contour/v1beta1" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/envoy" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -127,14 +126,11 @@ func TestTLSCertificateDelegation(t *testing.T) { ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), - FilterChains: filterchaintls("example.com", sec1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - nil, - "h2", "http/1.1"), + FilterChains: appendFilterChains( + filterchaintls("example.com", sec1, + httpsFilterFor("example.com"), + nil, "h2", "http/1.1"), + ), } c.Request(listenerType).Equals(&v2.DiscoveryResponse{ diff --git a/internal/featuretests/tlsprotocolversion_test.go b/internal/featuretests/tlsprotocolversion_test.go index 74ea408262e..d0a6b9bac64 100644 --- a/internal/featuretests/tlsprotocolversion_test.go +++ b/internal/featuretests/tlsprotocolversion_test.go @@ -1,4 +1,4 @@ -// Copyright © 2019 VMware +// Copyright © 2020 VMware // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -21,7 +21,6 @@ import ( envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener" ingressroutev1 "github.com/projectcontour/contour/apis/contour/v1beta1" projcontour "github.com/projectcontour/contour/apis/projectcontour/v1" - "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/dag" "github.com/projectcontour/contour/internal/envoy" v1 "k8s.io/api/core/v1" @@ -90,14 +89,11 @@ func TestTLSMinimumProtocolVersion(t *testing.T) { ListenerFilters: envoy.ListenerFilters( envoy.TLSInspector(), ), - FilterChains: filterchaintls("kuard.example.com", sec1, - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - nil, - "h2", "http/1.1"), + FilterChains: appendFilterChains( + filterchaintls("kuard.example.com", sec1, + httpsFilterFor("kuard.example.com"), + nil, "h2", "http/1.1"), + ), }, ), TypeUrl: listenerType, @@ -144,13 +140,7 @@ func TestTLSMinimumProtocolVersion(t *testing.T) { envoy_api_v2_auth.TlsParameters_TLSv1_3, nil, "h2", "http/1.1"), - envoy.Filters( - envoy.HTTPConnectionManagerBuilder(). - RouteConfigName("https/kuard.example.com"). - MetricsPrefix(contour.ENVOY_HTTPS_LISTENER). - AccessLoggers(envoy.FileAccessLogEnvoy("/dev/stdout")). - Get(), - ), + envoy.Filters(httpsFilterFor("kuard.example.com")), ), }, } diff --git a/site/_resources/envoy.md b/site/_resources/envoy.md index 4a239c93354..8592d39340a 100644 --- a/site/_resources/envoy.md +++ b/site/_resources/envoy.md @@ -34,7 +34,7 @@ If you are using the image recommended in our [example deployment][3] no action If you are providing your own Envoy it must be compiled with the following extensions: - `access_loggers`: `envoy.access_loggers.file`,`envoy.access_loggers.http_grpc`,`envoy.access_loggers.tcp_grpc` -- `filters.http`: `envoy.buffer`,`envoy.cors`,`envoy.csrf`,`envoy.fault`,`envoy.filters.http.adaptive_concurrency`,`envoy.filters.http.dynamic_forward_proxy`,`envoy.filters.http.grpc_http1_reverse_bridge`,`envoy.filters.http.grpc_stats`,`envoy.filters.http.header_to_metadata`,`envoy.filters.http.original_src`,`envoy.grpc_http1_bridge`,`envoy.grpc_json_transcoder`,`envoy.grpc_web`,`envoy.gzip`,`envoy.health_check`,`envoy.ip_tagging`,`envoy.router` +- `filters.http`: `envoy.buffer`, `envoy.cors`, `envoy.csrf`, `envoy.fault`, `envoy.filters.http.adaptive_concurrency`, `envoy.filters.http.dynamic_forward_proxy`, `envoy.filters.http.grpc_http1_reverse_bridge`, `envoy.filters.http.grpc_stats`, `envoy.filters.http.header_to_metadata`, `envoy.filters.http.lua`, `envoy.filters.http.original_src`, `envoy.grpc_http1_bridge`, `envoy.grpc_json_transcoder`, `envoy.grpc_web`, `envoy.gzip`, `envoy.health_check`, `envoy.ip_tagging`, `envoy.router` - `filters.listener`: `envoy.listener.http_inspector`,`envoy.listener.original_dst`,`envoy.listener.original_src`,`envoy.listener.proxy_protocol`,`envoy.listener.tls_inspector` - `filters.network`: `envoy.echo`,`envoy.filters.network.sni_cluster`,`envoy.http_connection_manager`,`envoy.tcp_proxy` - `stat_sinks`: `envoy.metrics_service`