diff --git a/packages/by-name/service-mesh/package.nix b/packages/by-name/service-mesh/package.nix index 677388671..3aa713367 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.go b/service-mesh/config.go index a1d8a4a5e..f817bafc3 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/config_test.go b/service-mesh/config_test.go new file mode 100644 index 000000000..821ef9296 --- /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 4c36bfbcb..432e57575 100644 --- a/service-mesh/go.mod +++ b/service-mesh/go.mod @@ -3,19 +3,25 @@ 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 + 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/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 // 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 c2b3fe93e..f8cb7caf5 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 000000000..a50d4d26a --- /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" + } + ] + } +} diff --git a/service-mesh/iptables.go b/service-mesh/iptables.go index 3efec5fab..a87766b5d 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