diff --git a/internal/xds/translator/testdata/in/xds-ir/tcp-emptycluster.yaml b/internal/xds/translator/testdata/in/xds-ir/tcp-emptycluster.yaml new file mode 100644 index 0000000000..696f372e7a --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/tcp-emptycluster.yaml @@ -0,0 +1,35 @@ +tcp: +- address: 0.0.0.0 + connection: + bufferLimit: 50000000 + limit: + closeDelay: 10s + value: 3 + proxyProtocol: + optional: false + name: envoy-gateway/gateway-1/tls-1 + port: 10443 + tcpKeepalive: + idleTime: 1200 + interval: 60 + probes: 3 + timeout: + tcp: + idleTimeout: 20m0s +- address: 0.0.0.0 + connection: + bufferLimit: 50000000 + limit: + closeDelay: 10s + value: 3 + proxyProtocol: + optional: false + name: envoy-gateway/gateway-1/tls-2 + port: 11443 + tcpKeepalive: + idleTime: 1200 + interval: 60 + probes: 3 + timeout: + tcp: + idleTimeout: 20m0s diff --git a/internal/xds/translator/testdata/in/xds-ir/tcp-multiple-tls-passthrough-no-routes.yaml b/internal/xds/translator/testdata/in/xds-ir/tcp-multiple-tls-passthrough-no-routes.yaml new file mode 100644 index 0000000000..e4a08bf14a --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/tcp-multiple-tls-passthrough-no-routes.yaml @@ -0,0 +1,16 @@ +tcp: +- name: tls-passthrough-1 + address: 0.0.0.0 + port: 10443 + tls: {} + routes: [] +- name: tls-passthrough-2 + address: 0.0.0.0 + port: 10443 + tls: {} + routes: [] +- name: tls-passthrough-3 + address: 0.0.0.0 + port: 10443 + tls: {} + routes: [] diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.clusters.yaml new file mode 100644 index 0000000000..0764d46f0e --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.clusters.yaml @@ -0,0 +1,2 @@ +- name: EmptyCluster + type: STATIC diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.endpoints.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.endpoints.yaml @@ -0,0 +1 @@ +[] diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.listeners.yaml new file mode 100644 index 0000000000..4a9b369d40 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.listeners.yaml @@ -0,0 +1,86 @@ +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10443 + filterChains: + - filters: + - name: envoy.filters.network.connection_limit + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.connection_limit.v3.ConnectionLimit + delay: 10s + maxConnections: "3" + statPrefix: tcp-10443 + - name: envoy.filters.network.tcp_proxy + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + cluster: EmptyCluster + idleTimeout: 1200s + statPrefix: tcp-10443 + name: EmptyCluster + listenerFilters: + - name: envoy.filters.listener.proxy_protocol + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/tls-1 + perConnectionBufferLimitBytes: 50000000 + socketOptions: + - description: socket option to enable tcp keep alive + intValue: "1" + level: "1" + name: "9" + - description: socket option for keep alive probes + intValue: "3" + level: "6" + name: "6" + - description: socket option for keep alive idle time + intValue: "1200" + level: "6" + name: "4" + - description: socket option for keep alive interval + intValue: "60" + level: "6" + name: "5" +- address: + socketAddress: + address: 0.0.0.0 + portValue: 11443 + filterChains: + - filters: + - name: envoy.filters.network.connection_limit + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.connection_limit.v3.ConnectionLimit + delay: 10s + maxConnections: "3" + statPrefix: tcp-11443 + - name: envoy.filters.network.tcp_proxy + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + cluster: EmptyCluster + idleTimeout: 1200s + statPrefix: tcp-11443 + name: EmptyCluster + listenerFilters: + - name: envoy.filters.listener.proxy_protocol + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/tls-2 + perConnectionBufferLimitBytes: 50000000 + socketOptions: + - description: socket option to enable tcp keep alive + intValue: "1" + level: "1" + name: "9" + - description: socket option for keep alive probes + intValue: "3" + level: "6" + name: "6" + - description: socket option for keep alive idle time + intValue: "1200" + level: "6" + name: "4" + - description: socket option for keep alive interval + intValue: "60" + level: "6" + name: "5" diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.routes.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/tcp-emptycluster.routes.yaml @@ -0,0 +1 @@ +[] diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.clusters.yaml new file mode 100644 index 0000000000..28becabe36 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.clusters.yaml @@ -0,0 +1,6 @@ +- name: EmptyCluster-tls-passthrough-1 + type: STATIC +- name: EmptyCluster-tls-passthrough-2 + type: STATIC +- name: EmptyCluster-tls-passthrough-3 + type: STATIC diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.endpoints.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.endpoints.yaml @@ -0,0 +1 @@ +[] diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.listeners.yaml new file mode 100644 index 0000000000..fd6f114e8b --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.listeners.yaml @@ -0,0 +1,29 @@ +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10443 + filterChains: + - filters: + - name: envoy.filters.network.tcp_proxy + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + cluster: EmptyCluster-tls-passthrough-1 + statPrefix: tcp-10443 + name: EmptyCluster-tls-passthrough-1 + - filters: + - name: envoy.filters.network.tcp_proxy + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + cluster: EmptyCluster-tls-passthrough-2 + statPrefix: tcp-10443 + name: EmptyCluster-tls-passthrough-2 + - filters: + - name: envoy.filters.network.tcp_proxy + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + cluster: EmptyCluster-tls-passthrough-3 + statPrefix: tcp-10443 + name: EmptyCluster-tls-passthrough-3 + maxConnectionsToAcceptPerSocketEvent: 1 + name: tls-passthrough-1 + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.routes.yaml new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/tcp-multiple-tls-passthrough-no-routes.routes.yaml @@ -0,0 +1 @@ +[] diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go index 89b3f1aed7..8cd9d82130 100644 --- a/internal/xds/translator/translator.go +++ b/internal/xds/translator/translator.go @@ -750,6 +750,8 @@ func (t *Translator) processTCPListenerXdsTranslation( // errors and return them at the end. var errs, err error + var sharedEmptyTCPRoute *ir.TCPRoute + for _, tcpListener := range tcpListeners { // Search for an existing listener, if it does not exist, create one. xdsListener := findXdsListenerByHostPort(tCtx, tcpListener.Address, tcpListener.Port, corev3.SocketAddress_TCP) @@ -822,25 +824,57 @@ func (t *Translator) processTCPListenerXdsTranslation( } } - // If there are no routes, add a route without a destination to the listener to create a filter chain - // This is needed because Envoy requires a filter chain to be present in the listener, otherwise it will reject the listener and report a warning if len(tcpListener.Routes) == 0 { - if findXdsCluster(tCtx, emptyClusterName) == nil { - if err := tCtx.AddXdsResource(resourcev3.ClusterType, emptyRouteCluster); err != nil { - errs = errors.Join(errs, err) + isTLSPassthrough := tcpListener.TLS != nil + + clusterName := emptyClusterName + var route *ir.TCPRoute + + if isTLSPassthrough { + // TLS passthrough listeners must not share EmptyCluster + clusterName = fmt.Sprintf("%s-%s", emptyClusterName, tcpListener.Name) + + if findXdsCluster(tCtx, clusterName) == nil { + if err := tCtx.AddXdsResource( + resourcev3.ClusterType, + &clusterv3.Cluster{ + Name: clusterName, + ClusterDiscoveryType: &clusterv3.Cluster_Type{Type: clusterv3.Cluster_STATIC}, + }, + ); err != nil { + errs = errors.Join(errs, err) + } } - } - emptyRoute := &ir.TCPRoute{ - Name: emptyClusterName, - Destination: &ir.RouteDestination{ - Name: emptyClusterName, - }, + route = &ir.TCPRoute{ + Name: clusterName, + Destination: &ir.RouteDestination{ + Name: clusterName, + }, + } + } else { + // Non-TLS-passthrough: reuse shared EmptyCluster + if findXdsCluster(tCtx, emptyClusterName) == nil { + if err := tCtx.AddXdsResource(resourcev3.ClusterType, emptyRouteCluster); err != nil { + errs = errors.Join(errs, err) + } + } + + if sharedEmptyTCPRoute == nil { + sharedEmptyTCPRoute = &ir.TCPRoute{ + Name: emptyClusterName, + Destination: &ir.RouteDestination{ + Name: emptyClusterName, + }, + } + } + route = sharedEmptyTCPRoute } + if err := t.addXdsTCPFilterChain( xdsListener, - emptyRoute, - emptyClusterName, + route, + clusterName, accesslog, tcpListener.Timeout, tcpListener.Connection, @@ -848,6 +882,7 @@ func (t *Translator) processTCPListenerXdsTranslation( errs = errors.Join(errs, err) } } + } return errs