From ef4de09c219e6d2c1c5f47514e9a8472461c7c4e Mon Sep 17 00:00:00 2001 From: Leonard Cohnen Date: Tue, 21 Jan 2025 04:47:46 +0100 Subject: [PATCH 1/3] service-mesh: clarify iptables error message --- service-mesh/iptables.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-mesh/iptables.go b/service-mesh/iptables.go index 3efec5fabe..a87766b5d6 100644 --- a/service-mesh/iptables.go +++ b/service-mesh/iptables.go @@ -48,7 +48,7 @@ func IngressIPTableRules(ingressEntries []ingressConfigEntry) error { // RETURN all local traffic from the CONTRAST_INBOUND chain back to the PREROUTING chain. if err := iptablesExec.AppendUnique("mangle", "CONTRAST_INBOUND", "-p", "tcp", "-i", "lo", "-j", "RETURN"); err != nil { - return fmt.Errorf("failed to append dport exception to CONTRAST_INBOUND chain: %w", err) + return fmt.Errorf("failed to append local traffic exception to CONTRAST_INBOUND chain: %w", err) } // RETURN all related and established traffic. // Since the mangle table executes on every packet and not just before the From 19a5c9f8504e1df2fb6726611bd9dd4699e7008b Mon Sep 17 00:00:00 2001 From: Leonard Cohnen Date: Tue, 21 Jan 2025 04:51:54 +0100 Subject: [PATCH 2/3] service-mesh: blackhole traffic destined for the TPROXY port Traffic to the TPROXY port (15006/15007) led to a traffic storm as envoy used the original destination to forward the traffic to, therefore forwarding it again to the TPROXY port where envoy listens. This commit introduces a Blackhole cluster where we send traffic to, that arrives on the TPROXY listeners and which original destination port is the TPROXY. --- service-mesh/config.go | 157 +++++++++++++++++++++++++++++++++++++++-- service-mesh/go.mod | 2 +- 2 files changed, 152 insertions(+), 7 deletions(-) diff --git a/service-mesh/config.go b/service-mesh/config.go index a1d8a4a5e9..f817bafc3a 100644 --- a/service-mesh/config.go +++ b/service-mesh/config.go @@ -7,9 +7,13 @@ import ( "fmt" "net" "net/netip" + "slices" "strconv" "strings" + "time" + envoyXDSCoreV3 "github.com/cncf/xds/go/xds/core/v3" + envoyXDSMatcherV3 "github.com/cncf/xds/go/xds/type/matcher/v3" envoyConfigBootstrapV3 "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3" envoyConfigClusterV3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" envoyCoreV3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" @@ -17,14 +21,21 @@ import ( envoyConfigListenerV3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" envoyOrigDstV3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/listener/original_dst/v3" envoyConfigTCPProxyV3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3" + envoyConfigNetworkV3 "github.com/envoyproxy/go-control-plane/envoy/extensions/matching/common_inputs/network/v3" envoyTLSV3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" ) var loopbackCIDR = netip.MustParsePrefix("127.0.0.1/8") +const ( + blackHoleClusterName = "BlackHoleCluster" + ingressClusterName = "IngressCluster" +) + // ProxyConfig represents the configuration for the proxy. type ProxyConfig struct { egress []egressConfigEntry @@ -169,17 +180,17 @@ func (c ProxyConfig) ToEnvoyConfig() ([]byte, error) { } // Create listeners and clusters for ingress traffic. - ingrListenerClientAuth, err := ingressListener("ingress", 15006, true) + ingrListenerClientAuth, err := ingressListener("ingress", EnvoyIngressPort, true) if err != nil { return nil, err } - ingrListenerNoClientAuth, err := ingressListener("ingressWithoutClientAuth", 15007, false) + ingrListenerNoClientAuth, err := ingressListener("ingressWithoutClientAuth", EnvoyIngressPortNoClientCert, false) if err != nil { return nil, err } ingressCluster := &envoyConfigClusterV3.Cluster{ - Name: "ingress", + Name: ingressClusterName, ClusterDiscoveryType: &envoyConfigClusterV3.Cluster_Type{Type: envoyConfigClusterV3.Cluster_ORIGINAL_DST}, DnsLookupFamily: envoyConfigClusterV3.Cluster_V4_ONLY, LbPolicy: envoyConfigClusterV3.Cluster_CLUSTER_PROVIDED, @@ -192,6 +203,10 @@ func (c ProxyConfig) ToEnvoyConfig() ([]byte, error) { config.StaticResources.Listeners = listeners config.StaticResources.Clusters = clusters + if err := addBlackHoleToConfig(config, []int{EnvoyIngressPort, EnvoyIngressPortNoClientCert}); err != nil { + return nil, err + } + if err := config.ValidateAll(); err != nil { return nil, err } @@ -231,9 +246,10 @@ func listener(entry egressConfigEntry) (*envoyConfigListenerV3.Listener, error) }, FilterChains: []*envoyConfigListenerV3.FilterChain{ { + Name: entry.name, Filters: []*envoyConfigListenerV3.Filter{ { - Name: "envoy.filters.network.tcp_proxy", + Name: "ingress", ConfigType: &envoyConfigListenerV3.Filter_TypedConfig{ TypedConfig: proxyAny, }, @@ -288,7 +304,7 @@ func cluster(entry egressConfigEntry) (*envoyConfigClusterV3.Cluster, error) { func ingressListener(name string, listenPort uint16, requireClientCertificate bool) (*envoyConfigListenerV3.Listener, error) { ingressListener, err := listener(egressConfigEntry{ name: name, - clusterName: "ingress", + clusterName: ingressClusterName, listenAddr: netip.MustParseAddr("0.0.0.0"), listenPort: listenPort, }) @@ -303,7 +319,7 @@ func ingressListener(name string, listenPort uint16, requireClientCertificate bo } ingressListener.ListenerFilters = []*envoyConfigListenerV3.ListenerFilter{ { - Name: "envoy.filters.listener.original_dst", + Name: "tcpListener", ConfigType: &envoyConfigListenerV3.ListenerFilter_TypedConfig{TypedConfig: originalDstAny}, }, } @@ -397,3 +413,132 @@ func downstreamTLSTransportSocket(requireClientCertificate bool) (*envoyCoreV3.T }, }, nil } + +func addBlackHoleToConfig(config *envoyConfigBootstrapV3.Bootstrap, listenerPorts []int) error { + // Add blackHoleCluster + config.StaticResources.Clusters = append(config.StaticResources.Clusters, blackHoleCluster()) + + // Add BlackHole matching to all listeners + for _, listener := range config.StaticResources.Listeners { + if listener.FilterChainMatcher != nil { + return fmt.Errorf("listener %s already has a filterChainMatcher", listener.Name) + } + listenPort := listener.Address.GetSocketAddress().GetPortValue() + if listenPort == 0 { + return fmt.Errorf("listener %s listens on port 0", listener.Name) + } + if !slices.Contains(listenerPorts, int(listenPort)) { + // listener is none of the ingress listeners + continue + } + if len(listener.FilterChains) != 1 { + return fmt.Errorf("listener %s doesn't have exactly one existing listener", listener.Name) + } + var err error + listener.FilterChainMatcher, err = filterChainMatcher(int(listenPort), listener.FilterChains[0].GetName()) + if err != nil { + return fmt.Errorf("could not add filterChainMatcher to listener %s: %w", listener.Name, err) + } + + bhFilter, err := blackHoleFilter() + if err != nil { + return err + } + listener.FilterChains = append(listener.FilterChains, bhFilter) + } + return nil +} + +// Blackhole traffic that arrives on the original destination listerners, +// which original port is the envoy itself, i.e. traffic that was not redirected +// to the envoy via the TROXY iptables rule. Such traffic would lead to a +// traffic storm since envoy would connect to the original destination +// i.e. itself again. Instead of using the original destination envoy cluster +// we forward this traffic to the blackhole cluster, which is +// "STATIC" but has no static endpoints, therefore envoy drops this traffic. +// see: https://istio.io/latest/blog/2019/monitoring-external-service-traffic/#what-are-blackhole-and-passthrough-clusters +func blackHoleCluster() *envoyConfigClusterV3.Cluster { + return &envoyConfigClusterV3.Cluster{ + Name: blackHoleClusterName, + ClusterDiscoveryType: &envoyConfigClusterV3.Cluster_Type{ + Type: envoyConfigClusterV3.Cluster_STATIC, + }, + ConnectTimeout: durationpb.New(10 * time.Second), + } +} + +func blackHoleFilter() (*envoyConfigListenerV3.FilterChain, error) { + blackHole := &envoyConfigTCPProxyV3.TcpProxy{ + StatPrefix: blackHoleClusterName, + ClusterSpecifier: &envoyConfigTCPProxyV3.TcpProxy_Cluster{ + Cluster: blackHoleClusterName, + }, + } + + blackHoleAny, err := anypb.New(blackHole) + if err != nil { + return nil, err + } + + return &envoyConfigListenerV3.FilterChain{ + Name: "BlackHoleFilter", + Filters: []*envoyConfigListenerV3.Filter{ + { + Name: "BlackHoleFilter", + ConfigType: &envoyConfigListenerV3.Filter_TypedConfig{ + TypedConfig: blackHoleAny, + }, + }, + }, + }, nil +} + +func filterChainMatcher(port int, defaultFilter string) (*envoyXDSMatcherV3.Matcher, error) { + ingressStringValueAny, err := anypb.New(wrapperspb.String(defaultFilter)) + if err != nil { + return nil, err + } + + blackHoleStringValueAny, err := anypb.New(wrapperspb.String("BlackHoleFilter")) + if err != nil { + return nil, err + } + + destPortStringValueAny, err := anypb.New(&envoyConfigNetworkV3.DestinationPortInput{}) + if err != nil { + return nil, err + } + + return &envoyXDSMatcherV3.Matcher{ + MatcherType: &envoyXDSMatcherV3.Matcher_MatcherTree_{ + MatcherTree: &envoyXDSMatcherV3.Matcher_MatcherTree{ + Input: &envoyXDSCoreV3.TypedExtensionConfig{ + Name: "port", + TypedConfig: destPortStringValueAny, + }, + TreeType: &envoyXDSMatcherV3.Matcher_MatcherTree_ExactMatchMap{ + ExactMatchMap: &envoyXDSMatcherV3.Matcher_MatcherTree_MatchMap{ + Map: map[string]*envoyXDSMatcherV3.Matcher_OnMatch{ + strconv.Itoa(port): { + OnMatch: &envoyXDSMatcherV3.Matcher_OnMatch_Action{ + Action: &envoyXDSCoreV3.TypedExtensionConfig{ + Name: "forwardToBlackHoleFilter", + TypedConfig: blackHoleStringValueAny, + }, + }, + }, + }, + }, + }, + }, + }, + OnNoMatch: &envoyXDSMatcherV3.Matcher_OnMatch{ + OnMatch: &envoyXDSMatcherV3.Matcher_OnMatch_Action{ + Action: &envoyXDSCoreV3.TypedExtensionConfig{ + Name: "forwardToIngress", + TypedConfig: ingressStringValueAny, + }, + }, + }, + }, nil +} diff --git a/service-mesh/go.mod b/service-mesh/go.mod index 4c36bfbcb1..3f49e878bc 100644 --- a/service-mesh/go.mod +++ b/service-mesh/go.mod @@ -3,6 +3,7 @@ module github.com/edgelesssys/contrast/service-mesh go 1.23.0 require ( + github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 github.com/coreos/go-iptables v0.8.0 github.com/envoyproxy/go-control-plane/envoy v1.32.2 google.golang.org/protobuf v1.36.3 @@ -10,7 +11,6 @@ require ( require ( cel.dev/expr v0.16.0 // indirect - github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 // indirect github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect From e938b279ee8238405482640a6d03bdd46e89355d Mon Sep 17 00:00:00 2001 From: Leonard Cohnen Date: Tue, 21 Jan 2025 04:54:16 +0100 Subject: [PATCH 3/3] service-mesh: introduce config generation tests With increasing envoy config complexity it gets more difficult to parse the final envoy config. Therefore we introduce tests which compare the envoy config for specific scenarios with golden JSON representations of the expected output. --- packages/by-name/service-mesh/package.nix | 3 +- service-mesh/config_test.go | 44 +++++ service-mesh/go.mod | 6 + service-mesh/go.sum | 18 ++ service-mesh/golden/defaultEnvoy.json | 223 ++++++++++++++++++++++ 5 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 service-mesh/config_test.go create mode 100644 service-mesh/golden/defaultEnvoy.json diff --git a/packages/by-name/service-mesh/package.nix b/packages/by-name/service-mesh/package.nix index 6773886714..3aa713367d 100644 --- a/packages/by-name/service-mesh/package.nix +++ b/packages/by-name/service-mesh/package.nix @@ -19,12 +19,13 @@ buildGoModule rec { fileset = fileset.unions [ (path.append root "go.mod") (path.append root "go.sum") + (path.append root "golden/defaultEnvoy.json") (fileset.fileFilter (file: hasSuffix ".go" file.name) root) ]; }; proxyVendor = true; - vendorHash = "sha256-xCPPdZZGSnzJatJ0HaKL19hlsHFC/FGhze0i7D1cPOI="; + vendorHash = "sha256-6Sa4w3csRX5oXFhazK8Yd/Lw56dR/46dtxksiCoghcY="; subPackages = [ "." ]; diff --git a/service-mesh/config_test.go b/service-mesh/config_test.go new file mode 100644 index 0000000000..821ef92968 --- /dev/null +++ b/service-mesh/config_test.go @@ -0,0 +1,44 @@ +// Copyright 2024 Edgeless Systems GmbH +// SPDX-License-Identifier: AGPL-3.0-only + +package main + +import ( + _ "embed" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" +) + +//go:embed golden/defaultEnvoy.json +var defaultEnvoyConfig []byte + +func TestCompareEnvoyConfigToGolden(t *testing.T) { + require := require.New(t) + + config, err := ParseProxyConfig("", "", "") + require.NoError(err) + + testCases := map[string]struct { + pConfig ProxyConfig + }{ + "success": { + pConfig: config, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + configJSON, err := tc.pConfig.ToEnvoyConfig() + require.NoError(err) + assert.JSONEq(string(defaultEnvoyConfig), string(configJSON)) + }) + } +} + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/service-mesh/go.mod b/service-mesh/go.mod index 3f49e878bc..432e575757 100644 --- a/service-mesh/go.mod +++ b/service-mesh/go.mod @@ -6,16 +6,22 @@ require ( github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 github.com/coreos/go-iptables v0.8.0 github.com/envoyproxy/go-control-plane/envoy v1.32.2 + github.com/stretchr/testify v1.8.4 + go.uber.org/goleak v1.3.0 google.golang.org/protobuf v1.36.3 ) require ( cel.dev/expr v0.16.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) // A refactoring of the go-control-plane library let's Go detect ambiguous imports: diff --git a/service-mesh/go.sum b/service-mesh/go.sum index c2b3fe93e2..f8cb7caf58 100644 --- a/service-mesh/go.sum +++ b/service-mesh/go.sum @@ -4,17 +4,35 @@ github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0Tx github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc= github.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane/envoy v1.32.2 h1:zidqwmijfcbyKqVxjQDFx042PgX+p9U+/fu/f9VtSk8= github.com/envoyproxy/go-control-plane/envoy v1.32.2/go.mod h1:eR2SOX2IedqlPvmiKjUH7Wu//S602JKI7HPC/L3SRq8= github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/service-mesh/golden/defaultEnvoy.json b/service-mesh/golden/defaultEnvoy.json new file mode 100644 index 0000000000..a50d4d26a9 --- /dev/null +++ b/service-mesh/golden/defaultEnvoy.json @@ -0,0 +1,223 @@ +{ + "staticResources": { + "listeners": [ + { + "name": "ingress", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 15006 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "ingress", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "ingress", + "cluster": "IngressCluster" + } + } + ], + "transportSocket": { + "name": "envoy.transport_sockets.tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsCertificates": [ + { + "certificateChain": { + "filename": "/contrast/tls-config/certChain.pem" + }, + "privateKey": { + "filename": "/contrast/tls-config/key.pem" + } + } + ], + "validationContext": { + "trustedCa": { + "filename": "/contrast/tls-config/mesh-ca.pem" + } + } + }, + "requireClientCertificate": true + } + }, + "name": "ingress" + }, + { + "filters": [ + { + "name": "BlackHoleFilter", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "BlackHoleCluster", + "cluster": "BlackHoleCluster" + } + } + ], + "name": "BlackHoleFilter" + } + ], + "filterChainMatcher": { + "matcherTree": { + "input": { + "name": "port", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput" + } + }, + "exactMatchMap": { + "map": { + "15006": { + "action": { + "name": "forwardToBlackHoleFilter", + "typedConfig": { + "@type": "type.googleapis.com/google.protobuf.StringValue", + "value": "BlackHoleFilter" + } + } + } + } + } + }, + "onNoMatch": { + "action": { + "name": "forwardToIngress", + "typedConfig": { + "@type": "type.googleapis.com/google.protobuf.StringValue", + "value": "ingress" + } + } + } + }, + "listenerFilters": [ + { + "name": "tcpListener", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst" + } + } + ], + "transparent": true + }, + { + "name": "ingressWithoutClientAuth", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 15007 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "ingress", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "ingressWithoutClientAuth", + "cluster": "IngressCluster" + } + } + ], + "transportSocket": { + "name": "envoy.transport_sockets.tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsCertificates": [ + { + "certificateChain": { + "filename": "/contrast/tls-config/certChain.pem" + }, + "privateKey": { + "filename": "/contrast/tls-config/key.pem" + } + } + ], + "validationContext": { + "trustedCa": { + "filename": "/contrast/tls-config/mesh-ca.pem" + } + } + }, + "requireClientCertificate": false + } + }, + "name": "ingressWithoutClientAuth" + }, + { + "filters": [ + { + "name": "BlackHoleFilter", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "BlackHoleCluster", + "cluster": "BlackHoleCluster" + } + } + ], + "name": "BlackHoleFilter" + } + ], + "filterChainMatcher": { + "matcherTree": { + "input": { + "name": "port", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput" + } + }, + "exactMatchMap": { + "map": { + "15007": { + "action": { + "name": "forwardToBlackHoleFilter", + "typedConfig": { + "@type": "type.googleapis.com/google.protobuf.StringValue", + "value": "BlackHoleFilter" + } + } + } + } + } + }, + "onNoMatch": { + "action": { + "name": "forwardToIngress", + "typedConfig": { + "@type": "type.googleapis.com/google.protobuf.StringValue", + "value": "ingressWithoutClientAuth" + } + } + } + }, + "listenerFilters": [ + { + "name": "tcpListener", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst" + } + } + ], + "transparent": true + } + ], + "clusters": [ + { + "name": "IngressCluster", + "type": "ORIGINAL_DST", + "lbPolicy": "CLUSTER_PROVIDED", + "dnsLookupFamily": "V4_ONLY" + }, + { + "name": "BlackHoleCluster", + "type": "STATIC", + "connectTimeout": "10s" + } + ] + } +}