github.com/cilium/cilium@v1.16.2/operator/pkg/model/translation/ingress/dedicated_ingress_fixture_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package ingress
     5  
     6  import (
     7  	"fmt"
     8  	"syscall"
     9  
    10  	envoy_config_cluster_v3 "github.com/cilium/proxy/go/envoy/config/cluster/v3"
    11  	envoy_config_core_v3 "github.com/cilium/proxy/go/envoy/config/core/v3"
    12  	envoy_config_listener "github.com/cilium/proxy/go/envoy/config/listener/v3"
    13  	envoy_config_route_v3 "github.com/cilium/proxy/go/envoy/config/route/v3"
    14  	grpc_stats_v3 "github.com/cilium/proxy/go/envoy/extensions/filters/http/grpc_stats/v3"
    15  	grpc_web_v3 "github.com/cilium/proxy/go/envoy/extensions/filters/http/grpc_web/v3"
    16  	envoy_extensions_filters_http_router_v3 "github.com/cilium/proxy/go/envoy/extensions/filters/http/router/v3"
    17  	envoy_extensions_listener_proxy_protocol_v3 "github.com/cilium/proxy/go/envoy/extensions/filters/listener/proxy_protocol/v3"
    18  	envoy_extensions_listener_tls_inspector_v3 "github.com/cilium/proxy/go/envoy/extensions/filters/listener/tls_inspector/v3"
    19  	http_connection_manager_v3 "github.com/cilium/proxy/go/envoy/extensions/filters/network/http_connection_manager/v3"
    20  	envoy_extensions_transport_sockets_tls_v3 "github.com/cilium/proxy/go/envoy/extensions/transport_sockets/tls/v3"
    21  	envoy_upstreams_http_v3 "github.com/cilium/proxy/go/envoy/extensions/upstreams/http/v3"
    22  	envoy_type_matcher_v3 "github.com/cilium/proxy/go/envoy/type/matcher/v3"
    23  	"google.golang.org/protobuf/proto"
    24  	"google.golang.org/protobuf/types/known/anypb"
    25  	"google.golang.org/protobuf/types/known/durationpb"
    26  	"google.golang.org/protobuf/types/known/wrapperspb"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  
    29  	"github.com/cilium/cilium/operator/pkg/model"
    30  	ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    31  	slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1"
    32  )
    33  
    34  var socketOptions = []*envoy_config_core_v3.SocketOption{
    35  	{
    36  		Description: "Enable TCP keep-alive (default to enabled)",
    37  		Level:       syscall.SOL_SOCKET,
    38  		Name:        syscall.SO_KEEPALIVE,
    39  		Value: &envoy_config_core_v3.SocketOption_IntValue{
    40  			IntValue: 1,
    41  		},
    42  		State: envoy_config_core_v3.SocketOption_STATE_PREBIND,
    43  	},
    44  	{
    45  		Description: "TCP keep-alive idle time (in seconds) (defaults to 10s)",
    46  		Level:       syscall.IPPROTO_TCP,
    47  		Name:        syscall.TCP_KEEPIDLE,
    48  		Value: &envoy_config_core_v3.SocketOption_IntValue{
    49  			IntValue: 10,
    50  		},
    51  		State: envoy_config_core_v3.SocketOption_STATE_PREBIND,
    52  	},
    53  	{
    54  		Description: "TCP keep-alive probe intervals (in seconds) (defaults to 5s)",
    55  		Level:       syscall.IPPROTO_TCP,
    56  		Name:        syscall.TCP_KEEPINTVL,
    57  		Value: &envoy_config_core_v3.SocketOption_IntValue{
    58  			IntValue: 5,
    59  		},
    60  		State: envoy_config_core_v3.SocketOption_STATE_PREBIND,
    61  	},
    62  	{
    63  		Description: "TCP keep-alive probe max failures.",
    64  		Level:       syscall.IPPROTO_TCP,
    65  		Name:        syscall.TCP_KEEPCNT,
    66  		Value: &envoy_config_core_v3.SocketOption_IntValue{
    67  			IntValue: 10,
    68  		},
    69  		State: envoy_config_core_v3.SocketOption_STATE_PREBIND,
    70  	},
    71  }
    72  
    73  func toEnvoyCluster(namespace, name, port string) *envoy_config_cluster_v3.Cluster {
    74  	return &envoy_config_cluster_v3.Cluster{
    75  		Name: fmt.Sprintf("%s:%s:%s", namespace, name, port),
    76  		EdsClusterConfig: &envoy_config_cluster_v3.Cluster_EdsClusterConfig{
    77  			ServiceName: fmt.Sprintf("%s/%s:%s", namespace, name, port),
    78  		},
    79  		TypedExtensionProtocolOptions: map[string]*anypb.Any{
    80  			"envoy.extensions.upstreams.http.v3.HttpProtocolOptions": toAny(&envoy_upstreams_http_v3.HttpProtocolOptions{
    81  				CommonHttpProtocolOptions: &envoy_config_core_v3.HttpProtocolOptions{
    82  					IdleTimeout: &durationpb.Duration{Seconds: int64(60)},
    83  				},
    84  				UpstreamProtocolOptions: &envoy_upstreams_http_v3.HttpProtocolOptions_UseDownstreamProtocolConfig{
    85  					UseDownstreamProtocolConfig: &envoy_upstreams_http_v3.HttpProtocolOptions_UseDownstreamHttpConfig{
    86  						Http2ProtocolOptions: &envoy_config_core_v3.Http2ProtocolOptions{},
    87  					},
    88  				},
    89  			}),
    90  		},
    91  		ClusterDiscoveryType: &envoy_config_cluster_v3.Cluster_Type{
    92  			Type: envoy_config_cluster_v3.Cluster_EDS,
    93  		},
    94  		ConnectTimeout: &durationpb.Duration{Seconds: int64(5)},
    95  		LbPolicy:       envoy_config_cluster_v3.Cluster_ROUND_ROBIN,
    96  		OutlierDetection: &envoy_config_cluster_v3.OutlierDetection{
    97  			SplitExternalLocalOriginErrors: true,
    98  		},
    99  	}
   100  }
   101  
   102  func toRouteAction(namespace, name, port string) *envoy_config_route_v3.Route_Route {
   103  	return &envoy_config_route_v3.Route_Route{
   104  		Route: &envoy_config_route_v3.RouteAction{
   105  			ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
   106  				Cluster: fmt.Sprintf("%s:%s:%s", namespace, name, port),
   107  			},
   108  			MaxStreamDuration: &envoy_config_route_v3.RouteAction_MaxStreamDuration{
   109  				MaxStreamDuration: &durationpb.Duration{Seconds: 0},
   110  			},
   111  		},
   112  	}
   113  }
   114  
   115  func toHTTPSRedirectAction() *envoy_config_route_v3.Route_Redirect {
   116  	return &envoy_config_route_v3.Route_Redirect{
   117  		Redirect: &envoy_config_route_v3.RedirectAction{
   118  			SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_HttpsRedirect{
   119  				HttpsRedirect: true,
   120  			},
   121  		},
   122  	}
   123  }
   124  
   125  func toListenerFilter(name string) *envoy_config_listener.Filter {
   126  	return &envoy_config_listener.Filter{
   127  		Name: "envoy.filters.network.http_connection_manager",
   128  		ConfigType: &envoy_config_listener.Filter_TypedConfig{
   129  			TypedConfig: toAny(&http_connection_manager_v3.HttpConnectionManager{
   130  				StatPrefix: name,
   131  				RouteSpecifier: &http_connection_manager_v3.HttpConnectionManager_Rds{
   132  					Rds: &http_connection_manager_v3.Rds{RouteConfigName: name},
   133  				},
   134  				UpgradeConfigs: []*http_connection_manager_v3.HttpConnectionManager_UpgradeConfig{
   135  					{UpgradeType: "websocket"},
   136  				},
   137  				UseRemoteAddress: &wrapperspb.BoolValue{Value: true},
   138  				SkipXffAppend:    false,
   139  				HttpFilters: []*http_connection_manager_v3.HttpFilter{
   140  					{
   141  						Name: "envoy.filters.http.grpc_web",
   142  						ConfigType: &http_connection_manager_v3.HttpFilter_TypedConfig{
   143  							TypedConfig: toAny(&grpc_web_v3.GrpcWeb{}),
   144  						},
   145  					},
   146  					{
   147  						Name: "envoy.filters.http.grpc_stats",
   148  						ConfigType: &http_connection_manager_v3.HttpFilter_TypedConfig{
   149  							TypedConfig: toAny(&grpc_stats_v3.FilterConfig{
   150  								EmitFilterState:     true,
   151  								EnableUpstreamStats: true,
   152  							}),
   153  						},
   154  					},
   155  					{
   156  						Name: "envoy.filters.http.router",
   157  						ConfigType: &http_connection_manager_v3.HttpFilter_TypedConfig{
   158  							TypedConfig: toAny(&envoy_extensions_filters_http_router_v3.Router{}),
   159  						},
   160  					},
   161  				},
   162  				CommonHttpProtocolOptions: &envoy_config_core_v3.HttpProtocolOptions{
   163  					MaxStreamDuration: &durationpb.Duration{
   164  						Seconds: 0,
   165  					},
   166  				},
   167  			}),
   168  		},
   169  	}
   170  }
   171  
   172  func toSecureListenerFilterChain(serverNames []string, certName string) *envoy_config_listener.FilterChain {
   173  	return &envoy_config_listener.FilterChain{
   174  		FilterChainMatch: &envoy_config_listener.FilterChainMatch{
   175  			ServerNames:       serverNames,
   176  			TransportProtocol: "tls",
   177  		},
   178  		Filters: []*envoy_config_listener.Filter{
   179  			toListenerFilter("listener-secure"),
   180  		},
   181  		TransportSocket: &envoy_config_core_v3.TransportSocket{
   182  			Name: "envoy.transport_sockets.tls",
   183  			ConfigType: &envoy_config_core_v3.TransportSocket_TypedConfig{
   184  				TypedConfig: toAny(&envoy_extensions_transport_sockets_tls_v3.DownstreamTlsContext{
   185  					CommonTlsContext: &envoy_extensions_transport_sockets_tls_v3.CommonTlsContext{
   186  						TlsCertificateSdsSecretConfigs: []*envoy_extensions_transport_sockets_tls_v3.SdsSecretConfig{
   187  							{
   188  								Name: certName,
   189  							},
   190  						},
   191  					},
   192  				}),
   193  			},
   194  		},
   195  	}
   196  }
   197  
   198  func toInsecureListenerFilterChain() *envoy_config_listener.FilterChain {
   199  	return &envoy_config_listener.FilterChain{
   200  		FilterChainMatch: &envoy_config_listener.FilterChainMatch{
   201  			TransportProtocol: "raw_buffer",
   202  		},
   203  		Filters: []*envoy_config_listener.Filter{
   204  			toListenerFilter("listener-insecure"),
   205  		},
   206  	}
   207  }
   208  
   209  func toHTTPListenerXDSResource(proxyProtocol bool, address *string, port *uint32) *anypb.Any {
   210  	listenerFilters := []*envoy_config_listener.ListenerFilter{
   211  		{
   212  			Name: "envoy.filters.listener.tls_inspector",
   213  			ConfigType: &envoy_config_listener.ListenerFilter_TypedConfig{
   214  				TypedConfig: toAny(&envoy_extensions_listener_tls_inspector_v3.TlsInspector{}),
   215  			},
   216  		},
   217  	}
   218  	if proxyProtocol {
   219  		proxyListener := &envoy_config_listener.ListenerFilter{
   220  			Name: "envoy.filters.listener.proxy_protocol",
   221  			ConfigType: &envoy_config_listener.ListenerFilter_TypedConfig{
   222  				TypedConfig: toAny(&envoy_extensions_listener_proxy_protocol_v3.ProxyProtocol{}),
   223  			},
   224  		}
   225  		listenerFilters = append([]*envoy_config_listener.ListenerFilter{proxyListener}, listenerFilters...)
   226  	}
   227  	l := &envoy_config_listener.Listener{
   228  		Name: "listener",
   229  		FilterChains: []*envoy_config_listener.FilterChain{
   230  			toInsecureListenerFilterChain(),
   231  		},
   232  		ListenerFilters: listenerFilters,
   233  		SocketOptions:   socketOptions,
   234  	}
   235  
   236  	if address != nil && port != nil {
   237  		l.Address = &envoy_config_core_v3.Address{
   238  			Address: &envoy_config_core_v3.Address_SocketAddress{
   239  				SocketAddress: &envoy_config_core_v3.SocketAddress{
   240  					Protocol: envoy_config_core_v3.SocketAddress_TCP,
   241  					Address:  *address,
   242  					PortSpecifier: &envoy_config_core_v3.SocketAddress_PortValue{
   243  						PortValue: *port,
   244  					},
   245  				},
   246  			},
   247  		}
   248  	}
   249  
   250  	return toAny(l)
   251  }
   252  
   253  func toBothListenersXDSResource(serverNames []string, certName string) *anypb.Any {
   254  	return toAny(&envoy_config_listener.Listener{
   255  		Name: "listener",
   256  		FilterChains: []*envoy_config_listener.FilterChain{
   257  			toInsecureListenerFilterChain(),
   258  			toSecureListenerFilterChain(serverNames, certName),
   259  		},
   260  		ListenerFilters: []*envoy_config_listener.ListenerFilter{
   261  			{
   262  				Name: "envoy.filters.listener.tls_inspector",
   263  				ConfigType: &envoy_config_listener.ListenerFilter_TypedConfig{
   264  					TypedConfig: toAny(&envoy_extensions_listener_tls_inspector_v3.TlsInspector{}),
   265  				},
   266  			},
   267  		},
   268  		SocketOptions: socketOptions,
   269  	})
   270  }
   271  
   272  // Ingress Conformance test resources
   273  
   274  // Conformance/DefaultBackend test
   275  var defaultBackendListeners = []model.HTTPListener{
   276  	{
   277  		Sources: []model.FullyQualifiedResource{
   278  			{
   279  				Name:      "load-balancing",
   280  				Namespace: "random-namespace",
   281  				Version:   "networking.k8s.io/v1",
   282  				Kind:      "Ingress",
   283  			},
   284  		},
   285  		Port:     80,
   286  		Hostname: "*",
   287  		Routes: []model.HTTPRoute{
   288  			{
   289  				Backends: []model.Backend{
   290  					{
   291  						Name:      "default-backend",
   292  						Namespace: "random-namespace",
   293  						Port: &model.BackendPort{
   294  							Port: 8080,
   295  						},
   296  					},
   297  				},
   298  			},
   299  		},
   300  	},
   301  }
   302  
   303  var defaultBackendListenersCiliumEnvoyConfig = &ciliumv2.CiliumEnvoyConfig{
   304  	ObjectMeta: metav1.ObjectMeta{
   305  		Name:      "cilium-ingress-random-namespace-load-balancing",
   306  		Namespace: "random-namespace",
   307  		Labels: map[string]string{
   308  			"cilium.io/use-original-source-address": "false",
   309  		},
   310  	},
   311  	Spec: ciliumv2.CiliumEnvoyConfigSpec{
   312  		Services: []*ciliumv2.ServiceListener{
   313  			{
   314  				Name:      "cilium-ingress-load-balancing",
   315  				Namespace: "random-namespace",
   316  				Ports: []uint16{
   317  					80,
   318  				},
   319  			},
   320  		},
   321  		BackendServices: []*ciliumv2.Service{
   322  			{
   323  				Name:      "default-backend",
   324  				Namespace: "random-namespace",
   325  				Ports:     []string{"8080"},
   326  			},
   327  		},
   328  		Resources: []ciliumv2.XDSResource{
   329  			{Any: toHTTPListenerXDSResource(false, nil, nil)},
   330  			{
   331  				Any: toAny(&envoy_config_route_v3.RouteConfiguration{
   332  					Name: "listener-insecure",
   333  					VirtualHosts: []*envoy_config_route_v3.VirtualHost{
   334  						{
   335  							Name:    "*",
   336  							Domains: []string{"*"},
   337  							Routes: []*envoy_config_route_v3.Route{
   338  								{
   339  									Match: &envoy_config_route_v3.RouteMatch{
   340  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
   341  											Prefix: "/",
   342  										},
   343  									},
   344  									Action: toRouteAction("random-namespace", "default-backend", "8080"),
   345  								},
   346  							},
   347  						},
   348  					},
   349  				}),
   350  			},
   351  			{Any: toAny(toEnvoyCluster("random-namespace", "default-backend", "8080"))},
   352  		},
   353  	},
   354  }
   355  
   356  // Conformance/HostRules test, enforce HTTPS is enabled
   357  var hostRulesListenersEnforceHTTPS = []model.HTTPListener{
   358  	{
   359  		Name: "ing-host-rules-random-namespace-*.foo.com",
   360  		Sources: []model.FullyQualifiedResource{
   361  			{
   362  				Name:      "host-rules",
   363  				Namespace: "random-namespace",
   364  				Version:   "networking.k8s.io/v1",
   365  				Kind:      "Ingress",
   366  			},
   367  		},
   368  		Port:     80,
   369  		Hostname: "*.foo.com",
   370  		Routes: []model.HTTPRoute{
   371  			{
   372  				PathMatch: model.StringMatch{
   373  					Prefix: "/",
   374  				},
   375  				Backends: []model.Backend{
   376  					{
   377  						Name:      "wildcard-foo-com",
   378  						Namespace: "random-namespace",
   379  						Port: &model.BackendPort{
   380  							Port: 8080,
   381  						},
   382  					},
   383  				},
   384  			},
   385  		},
   386  	},
   387  	{
   388  		Name: "ing-host-rules-random-namespace-foo.bar.com",
   389  		Sources: []model.FullyQualifiedResource{
   390  			{
   391  				Name:      "host-rules",
   392  				Namespace: "random-namespace",
   393  				Version:   "networking.k8s.io/v1",
   394  				Kind:      "Ingress",
   395  			},
   396  		},
   397  		Port:     80,
   398  		Hostname: "foo.bar.com",
   399  		Routes: []model.HTTPRoute{
   400  			{
   401  				PathMatch: model.StringMatch{
   402  					Prefix: "/",
   403  				},
   404  				Backends: []model.Backend{
   405  					{
   406  						Name:      "foo-bar-com",
   407  						Namespace: "random-namespace",
   408  						Port: &model.BackendPort{
   409  							Name: "http",
   410  						},
   411  					},
   412  				},
   413  			},
   414  		},
   415  	},
   416  	{
   417  		Name: "ing-host-rules-random-namespace-foo.bar.com",
   418  		Sources: []model.FullyQualifiedResource{
   419  			{
   420  				Name:      "host-rules",
   421  				Namespace: "random-namespace",
   422  				Version:   "networking.k8s.io/v1",
   423  				Kind:      "Ingress",
   424  			},
   425  		},
   426  		Port:     443,
   427  		Hostname: "foo.bar.com",
   428  		TLS: []model.TLSSecret{
   429  			{
   430  				Name:      "conformance-tls",
   431  				Namespace: "random-namespace",
   432  			},
   433  		},
   434  		ForceHTTPtoHTTPSRedirect: true,
   435  		Routes: []model.HTTPRoute{
   436  			{
   437  				PathMatch: model.StringMatch{
   438  					Prefix: "/",
   439  				},
   440  				Backends: []model.Backend{
   441  					{
   442  						Name:      "foo-bar-com",
   443  						Namespace: "random-namespace",
   444  						Port: &model.BackendPort{
   445  							Name: "http",
   446  						},
   447  					},
   448  				},
   449  			},
   450  		},
   451  	},
   452  }
   453  
   454  var hostRulesListenersEnforceHTTPSCiliumEnvoyConfig = &ciliumv2.CiliumEnvoyConfig{
   455  	ObjectMeta: metav1.ObjectMeta{
   456  		Name:      "cilium-ingress-random-namespace-host-rules",
   457  		Namespace: "random-namespace",
   458  		Labels: map[string]string{
   459  			"cilium.io/use-original-source-address": "false",
   460  		},
   461  	},
   462  	Spec: ciliumv2.CiliumEnvoyConfigSpec{
   463  		Services: []*ciliumv2.ServiceListener{
   464  			{
   465  				Name:      "cilium-ingress-host-rules",
   466  				Namespace: "random-namespace",
   467  				Ports: []uint16{
   468  					80,
   469  					443,
   470  				},
   471  			},
   472  		},
   473  		BackendServices: []*ciliumv2.Service{
   474  			{
   475  				Name:      "foo-bar-com",
   476  				Namespace: "random-namespace",
   477  				Ports:     []string{"http"},
   478  			},
   479  			{
   480  				Name:      "wildcard-foo-com",
   481  				Namespace: "random-namespace",
   482  				Ports:     []string{"8080"},
   483  			},
   484  		},
   485  		Resources: []ciliumv2.XDSResource{
   486  			{Any: toBothListenersXDSResource([]string{"foo.bar.com"}, "cilium-secrets/random-namespace-conformance-tls")},
   487  			{
   488  				Any: toAny(&envoy_config_route_v3.RouteConfiguration{
   489  					Name: "listener-insecure",
   490  					VirtualHosts: []*envoy_config_route_v3.VirtualHost{
   491  						{
   492  							Name:    "*.foo.com",
   493  							Domains: []string{"*.foo.com", "*.foo.com:*"},
   494  							Routes: []*envoy_config_route_v3.Route{
   495  								{
   496  									Match: &envoy_config_route_v3.RouteMatch{
   497  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
   498  											Prefix: "/",
   499  										},
   500  										Headers: []*envoy_config_route_v3.HeaderMatcher{
   501  											{
   502  												Name: ":authority",
   503  												HeaderMatchSpecifier: &envoy_config_route_v3.HeaderMatcher_StringMatch{
   504  													StringMatch: &envoy_type_matcher_v3.StringMatcher{
   505  														MatchPattern: &envoy_type_matcher_v3.StringMatcher_SafeRegex{
   506  															SafeRegex: &envoy_type_matcher_v3.RegexMatcher{
   507  																Regex: "^[^.]+[.]foo[.]com$",
   508  															},
   509  														},
   510  													},
   511  												},
   512  											},
   513  										},
   514  										QueryParameters: []*envoy_config_route_v3.QueryParameterMatcher{},
   515  									},
   516  									Action: toRouteAction("random-namespace", "wildcard-foo-com", "8080"),
   517  								},
   518  							},
   519  						},
   520  						{
   521  							Name:    "foo.bar.com",
   522  							Domains: []string{"foo.bar.com", "foo.bar.com:*"},
   523  							Routes: []*envoy_config_route_v3.Route{
   524  								{
   525  									Match: &envoy_config_route_v3.RouteMatch{
   526  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
   527  											Prefix: "/",
   528  										},
   529  									},
   530  									Action: toHTTPSRedirectAction(),
   531  								},
   532  							},
   533  						},
   534  					},
   535  				}),
   536  			},
   537  			{
   538  				Any: toAny(&envoy_config_route_v3.RouteConfiguration{
   539  					Name: "listener-secure",
   540  					VirtualHosts: []*envoy_config_route_v3.VirtualHost{
   541  						{
   542  							Name:    "foo.bar.com",
   543  							Domains: []string{"foo.bar.com", "foo.bar.com:*"},
   544  							Routes: []*envoy_config_route_v3.Route{
   545  								{
   546  									Match: &envoy_config_route_v3.RouteMatch{
   547  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
   548  											Prefix: "/",
   549  										},
   550  									},
   551  									Action: toRouteAction("random-namespace", "foo-bar-com", "http"),
   552  								},
   553  							},
   554  						},
   555  					},
   556  				}),
   557  			},
   558  			{Any: toAny(toEnvoyCluster("random-namespace", "foo-bar-com", "http"))},
   559  			{Any: toAny(toEnvoyCluster("random-namespace", "wildcard-foo-com", "8080"))},
   560  		},
   561  	},
   562  }
   563  
   564  var hostRulesListeners = []model.HTTPListener{
   565  	{
   566  		Name: "ing-host-rules-random-namespace-*.foo.com",
   567  		Sources: []model.FullyQualifiedResource{
   568  			{
   569  				Name:      "host-rules",
   570  				Namespace: "random-namespace",
   571  				Version:   "networking.k8s.io/v1",
   572  				Kind:      "Ingress",
   573  			},
   574  		},
   575  		Port:     80,
   576  		Hostname: "*.foo.com",
   577  		Routes: []model.HTTPRoute{
   578  			{
   579  				PathMatch: model.StringMatch{
   580  					Prefix: "/",
   581  				},
   582  				Backends: []model.Backend{
   583  					{
   584  						Name:      "wildcard-foo-com",
   585  						Namespace: "random-namespace",
   586  						Port: &model.BackendPort{
   587  							Port: 8080,
   588  						},
   589  					},
   590  				},
   591  			},
   592  		},
   593  	},
   594  	{
   595  		Name: "ing-host-rules-random-namespace-foo.bar.com",
   596  		Sources: []model.FullyQualifiedResource{
   597  			{
   598  				Name:      "host-rules",
   599  				Namespace: "random-namespace",
   600  				Version:   "networking.k8s.io/v1",
   601  				Kind:      "Ingress",
   602  			},
   603  		},
   604  		Port:     80,
   605  		Hostname: "foo.bar.com",
   606  		Routes: []model.HTTPRoute{
   607  			{
   608  				PathMatch: model.StringMatch{
   609  					Prefix: "/",
   610  				},
   611  				Backends: []model.Backend{
   612  					{
   613  						Name:      "foo-bar-com",
   614  						Namespace: "random-namespace",
   615  						Port: &model.BackendPort{
   616  							Name: "http",
   617  						},
   618  					},
   619  				},
   620  			},
   621  		},
   622  	},
   623  	{
   624  		Name: "ing-host-rules-random-namespace-foo.bar.com",
   625  		Sources: []model.FullyQualifiedResource{
   626  			{
   627  				Name:      "host-rules",
   628  				Namespace: "random-namespace",
   629  				Version:   "networking.k8s.io/v1",
   630  				Kind:      "Ingress",
   631  			},
   632  		},
   633  		Port:     443,
   634  		Hostname: "foo.bar.com",
   635  		TLS: []model.TLSSecret{
   636  			{
   637  				Name:      "conformance-tls",
   638  				Namespace: "random-namespace",
   639  			},
   640  		},
   641  		Routes: []model.HTTPRoute{
   642  			{
   643  				PathMatch: model.StringMatch{
   644  					Prefix: "/",
   645  				},
   646  				Backends: []model.Backend{
   647  					{
   648  						Name:      "foo-bar-com",
   649  						Namespace: "random-namespace",
   650  						Port: &model.BackendPort{
   651  							Name: "http",
   652  						},
   653  					},
   654  				},
   655  			},
   656  		},
   657  	},
   658  }
   659  
   660  var hostRulesListenersCiliumEnvoyConfig = &ciliumv2.CiliumEnvoyConfig{
   661  	ObjectMeta: metav1.ObjectMeta{
   662  		Name:      "cilium-ingress-random-namespace-host-rules",
   663  		Namespace: "random-namespace",
   664  		Labels: map[string]string{
   665  			"cilium.io/use-original-source-address": "false",
   666  		},
   667  	},
   668  	Spec: ciliumv2.CiliumEnvoyConfigSpec{
   669  		Services: []*ciliumv2.ServiceListener{
   670  			{
   671  				Name:      "cilium-ingress-host-rules",
   672  				Namespace: "random-namespace",
   673  				Ports: []uint16{
   674  					80,
   675  					443,
   676  				},
   677  			},
   678  		},
   679  		BackendServices: []*ciliumv2.Service{
   680  			{
   681  				Name:      "foo-bar-com",
   682  				Namespace: "random-namespace",
   683  				Ports:     []string{"http"},
   684  			},
   685  			{
   686  				Name:      "wildcard-foo-com",
   687  				Namespace: "random-namespace",
   688  				Ports:     []string{"8080"},
   689  			},
   690  		},
   691  		Resources: []ciliumv2.XDSResource{
   692  			{Any: toBothListenersXDSResource([]string{"foo.bar.com"}, "cilium-secrets/random-namespace-conformance-tls")},
   693  			{
   694  				Any: toAny(&envoy_config_route_v3.RouteConfiguration{
   695  					Name: "listener-insecure",
   696  					VirtualHosts: []*envoy_config_route_v3.VirtualHost{
   697  						{
   698  							Name:    "*.foo.com",
   699  							Domains: []string{"*.foo.com", "*.foo.com:*"},
   700  							Routes: []*envoy_config_route_v3.Route{
   701  								{
   702  									Match: &envoy_config_route_v3.RouteMatch{
   703  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
   704  											Prefix: "/",
   705  										},
   706  										Headers: []*envoy_config_route_v3.HeaderMatcher{
   707  											{
   708  												Name: ":authority",
   709  												HeaderMatchSpecifier: &envoy_config_route_v3.HeaderMatcher_StringMatch{
   710  													StringMatch: &envoy_type_matcher_v3.StringMatcher{
   711  														MatchPattern: &envoy_type_matcher_v3.StringMatcher_SafeRegex{
   712  															SafeRegex: &envoy_type_matcher_v3.RegexMatcher{
   713  																Regex: "^[^.]+[.]foo[.]com$",
   714  															},
   715  														},
   716  													},
   717  												},
   718  											},
   719  										},
   720  										QueryParameters: []*envoy_config_route_v3.QueryParameterMatcher{},
   721  									},
   722  									Action: toRouteAction("random-namespace", "wildcard-foo-com", "8080"),
   723  								},
   724  							},
   725  						},
   726  						{
   727  							Name:    "foo.bar.com",
   728  							Domains: []string{"foo.bar.com", "foo.bar.com:*"},
   729  							Routes: []*envoy_config_route_v3.Route{
   730  								{
   731  									Match: &envoy_config_route_v3.RouteMatch{
   732  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
   733  											Prefix: "/",
   734  										},
   735  									},
   736  									Action: toRouteAction("random-namespace", "foo-bar-com", "http"),
   737  								},
   738  							},
   739  						},
   740  					},
   741  				}),
   742  			},
   743  			{
   744  				Any: toAny(&envoy_config_route_v3.RouteConfiguration{
   745  					Name: "listener-secure",
   746  					VirtualHosts: []*envoy_config_route_v3.VirtualHost{
   747  						{
   748  							Name:    "foo.bar.com",
   749  							Domains: []string{"foo.bar.com", "foo.bar.com:*"},
   750  							Routes: []*envoy_config_route_v3.Route{
   751  								{
   752  									Match: &envoy_config_route_v3.RouteMatch{
   753  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
   754  											Prefix: "/",
   755  										},
   756  									},
   757  									Action: toRouteAction("random-namespace", "foo-bar-com", "http"),
   758  								},
   759  							},
   760  						},
   761  					},
   762  				}),
   763  			},
   764  			{Any: toAny(toEnvoyCluster("random-namespace", "foo-bar-com", "http"))},
   765  			{Any: toAny(toEnvoyCluster("random-namespace", "wildcard-foo-com", "8080"))},
   766  		},
   767  	},
   768  }
   769  
   770  // Conformance/PathRules test
   771  var pathRulesListeners = []model.HTTPListener{
   772  	{
   773  		Name: "ing-path-rules-random-namespace-exact-path-rules",
   774  		Sources: []model.FullyQualifiedResource{
   775  			{
   776  				Name:      "path-rules",
   777  				Namespace: "random-namespace",
   778  				Version:   "networking.k8s.io/v1",
   779  				Kind:      "Ingress",
   780  			},
   781  		},
   782  		Port:     80,
   783  		Hostname: "exact-path-rules",
   784  		Routes: []model.HTTPRoute{
   785  			{
   786  				PathMatch: model.StringMatch{
   787  					Exact: "/foo",
   788  				},
   789  				Backends: []model.Backend{
   790  					{
   791  						Name:      "foo-exact",
   792  						Namespace: "random-namespace",
   793  						Port: &model.BackendPort{
   794  							Port: 8080,
   795  						},
   796  					},
   797  				},
   798  			},
   799  		},
   800  	},
   801  	{
   802  		Name: "ing-path-rules-random-namespace-mixed-path-rules",
   803  		Sources: []model.FullyQualifiedResource{
   804  			{
   805  				Name:      "path-rules",
   806  				Namespace: "random-namespace",
   807  				Version:   "networking.k8s.io/v1",
   808  				Kind:      "Ingress",
   809  			},
   810  		},
   811  		Port:     80,
   812  		Hostname: "mixed-path-rules",
   813  		Routes: []model.HTTPRoute{
   814  			{
   815  				PathMatch: model.StringMatch{
   816  					Prefix: "/foo",
   817  				},
   818  				Backends: []model.Backend{
   819  					{
   820  						Name:      "foo-prefix",
   821  						Namespace: "random-namespace",
   822  						Port: &model.BackendPort{
   823  							Port: 8080,
   824  						},
   825  					},
   826  				},
   827  			},
   828  			{
   829  				PathMatch: model.StringMatch{
   830  					Exact: "/foo",
   831  				},
   832  				Backends: []model.Backend{
   833  					{
   834  						Name:      "foo-exact",
   835  						Namespace: "random-namespace",
   836  						Port: &model.BackendPort{
   837  							Port: 8080,
   838  						},
   839  					},
   840  				},
   841  			},
   842  		},
   843  	},
   844  	{
   845  		Name: "ing-path-rules-random-namespace-prefix-path-rules",
   846  		Sources: []model.FullyQualifiedResource{
   847  			{
   848  				Name:      "path-rules",
   849  				Namespace: "random-namespace",
   850  				Version:   "networking.k8s.io/v1",
   851  				Kind:      "Ingress",
   852  			},
   853  		},
   854  		Port:     80,
   855  		Hostname: "prefix-path-rules",
   856  		Routes: []model.HTTPRoute{
   857  			{
   858  				PathMatch: model.StringMatch{
   859  					Prefix: "/foo",
   860  				},
   861  				Backends: []model.Backend{
   862  					{
   863  						Name:      "foo-prefix",
   864  						Namespace: "random-namespace",
   865  						Port: &model.BackendPort{
   866  							Port: 8080,
   867  						},
   868  					},
   869  				},
   870  			},
   871  			{
   872  				PathMatch: model.StringMatch{
   873  					Prefix: "/aaa/bbb",
   874  				},
   875  				Backends: []model.Backend{
   876  					{
   877  						Name:      "aaa-slash-bbb-prefix",
   878  						Namespace: "random-namespace",
   879  						Port: &model.BackendPort{
   880  							Port: 8080,
   881  						},
   882  					},
   883  				},
   884  			},
   885  			{
   886  				PathMatch: model.StringMatch{
   887  					Prefix: "/aaa",
   888  				},
   889  				Backends: []model.Backend{
   890  					{
   891  						Name:      "aaa-prefix",
   892  						Namespace: "random-namespace",
   893  						Port: &model.BackendPort{
   894  							Port: 8080,
   895  						},
   896  					},
   897  				},
   898  			},
   899  		},
   900  	},
   901  	{
   902  		Name: "ing-path-rules-random-namespace-trailing-slash-path-rules",
   903  		Sources: []model.FullyQualifiedResource{
   904  			{
   905  				Name:      "path-rules",
   906  				Namespace: "random-namespace",
   907  				Version:   "networking.k8s.io/v1",
   908  				Kind:      "Ingress",
   909  			},
   910  		},
   911  		Port:     80,
   912  		Hostname: "trailing-slash-path-rules",
   913  		Routes: []model.HTTPRoute{
   914  			{
   915  				PathMatch: model.StringMatch{
   916  					Prefix: "/aaa/bbb/",
   917  				},
   918  				Backends: []model.Backend{
   919  					{
   920  						Name:      "aaa-slash-bbb-slash-prefix",
   921  						Namespace: "random-namespace",
   922  						Port: &model.BackendPort{
   923  							Port: 8080,
   924  						},
   925  					},
   926  				},
   927  			},
   928  			{
   929  				PathMatch: model.StringMatch{
   930  					Exact: "/foo/",
   931  				},
   932  				Backends: []model.Backend{
   933  					{
   934  						Name:      "foo-slash-exact",
   935  						Namespace: "random-namespace",
   936  						Port: &model.BackendPort{
   937  							Port: 8080,
   938  						},
   939  					},
   940  				},
   941  			},
   942  		},
   943  	},
   944  }
   945  
   946  var pathRulesListenersCiliumEnvoyConfig = &ciliumv2.CiliumEnvoyConfig{
   947  	ObjectMeta: metav1.ObjectMeta{
   948  		Name:      "cilium-ingress-random-namespace-path-rules",
   949  		Namespace: "random-namespace",
   950  		Labels: map[string]string{
   951  			"cilium.io/use-original-source-address": "false",
   952  		},
   953  	},
   954  	Spec: ciliumv2.CiliumEnvoyConfigSpec{
   955  		Services: []*ciliumv2.ServiceListener{
   956  			{
   957  				Name:      "cilium-ingress-path-rules",
   958  				Namespace: "random-namespace",
   959  				Ports: []uint16{
   960  					80,
   961  				},
   962  			},
   963  		},
   964  		BackendServices: []*ciliumv2.Service{
   965  			{
   966  				Name:      "aaa-prefix",
   967  				Namespace: "random-namespace",
   968  				Ports:     []string{"8080"},
   969  			},
   970  			{
   971  				Name:      "aaa-slash-bbb-prefix",
   972  				Namespace: "random-namespace",
   973  				Ports:     []string{"8080"},
   974  			},
   975  			{
   976  				Name:      "aaa-slash-bbb-slash-prefix",
   977  				Namespace: "random-namespace",
   978  				Ports:     []string{"8080"},
   979  			},
   980  			{
   981  				Name:      "foo-exact",
   982  				Namespace: "random-namespace",
   983  				Ports:     []string{"8080"},
   984  			},
   985  			{
   986  				Name:      "foo-prefix",
   987  				Namespace: "random-namespace",
   988  				Ports:     []string{"8080"},
   989  			},
   990  			{
   991  				Name:      "foo-slash-exact",
   992  				Namespace: "random-namespace",
   993  				Ports:     []string{"8080"},
   994  			},
   995  		},
   996  		Resources: []ciliumv2.XDSResource{
   997  			{Any: toHTTPListenerXDSResource(false, nil, nil)},
   998  			{
   999  				Any: toAny(&envoy_config_route_v3.RouteConfiguration{
  1000  					Name: "listener-insecure",
  1001  					VirtualHosts: []*envoy_config_route_v3.VirtualHost{
  1002  						{
  1003  							Name:    "exact-path-rules",
  1004  							Domains: []string{"exact-path-rules", "exact-path-rules:*"},
  1005  							Routes: []*envoy_config_route_v3.Route{
  1006  								{
  1007  									Match: &envoy_config_route_v3.RouteMatch{
  1008  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Path{
  1009  											Path: "/foo",
  1010  										},
  1011  									},
  1012  									Action: toRouteAction("random-namespace", "foo-exact", "8080"),
  1013  								},
  1014  							},
  1015  						},
  1016  						{
  1017  							Name:    "mixed-path-rules",
  1018  							Domains: []string{"mixed-path-rules", "mixed-path-rules:*"},
  1019  							Routes: []*envoy_config_route_v3.Route{
  1020  								{
  1021  									Match: &envoy_config_route_v3.RouteMatch{
  1022  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Path{
  1023  											Path: "/foo",
  1024  										},
  1025  									},
  1026  									Action: toRouteAction("random-namespace", "foo-exact", "8080"),
  1027  								},
  1028  								{
  1029  									Match: &envoy_config_route_v3.RouteMatch{
  1030  										PathSpecifier: &envoy_config_route_v3.RouteMatch_PathSeparatedPrefix{
  1031  											PathSeparatedPrefix: "/foo",
  1032  										},
  1033  									},
  1034  									Action: toRouteAction("random-namespace", "foo-prefix", "8080"),
  1035  								},
  1036  							},
  1037  						},
  1038  						{
  1039  							Name:    "prefix-path-rules",
  1040  							Domains: []string{"prefix-path-rules", "prefix-path-rules:*"},
  1041  							Routes: []*envoy_config_route_v3.Route{
  1042  								{
  1043  									Match: &envoy_config_route_v3.RouteMatch{
  1044  										PathSpecifier: &envoy_config_route_v3.RouteMatch_PathSeparatedPrefix{
  1045  											PathSeparatedPrefix: "/aaa/bbb",
  1046  										},
  1047  									},
  1048  									Action: toRouteAction("random-namespace", "aaa-slash-bbb-prefix", "8080"),
  1049  								},
  1050  								{
  1051  									Match: &envoy_config_route_v3.RouteMatch{
  1052  										PathSpecifier: &envoy_config_route_v3.RouteMatch_PathSeparatedPrefix{
  1053  											PathSeparatedPrefix: "/foo",
  1054  										},
  1055  									},
  1056  									Action: toRouteAction("random-namespace", "foo-prefix", "8080"),
  1057  								},
  1058  								{
  1059  									Match: &envoy_config_route_v3.RouteMatch{
  1060  										PathSpecifier: &envoy_config_route_v3.RouteMatch_PathSeparatedPrefix{
  1061  											PathSeparatedPrefix: "/aaa",
  1062  										},
  1063  									},
  1064  									Action: toRouteAction("random-namespace", "aaa-prefix", "8080"),
  1065  								},
  1066  							},
  1067  						},
  1068  						{
  1069  							Name:    "trailing-slash-path-rules",
  1070  							Domains: []string{"trailing-slash-path-rules", "trailing-slash-path-rules:*"},
  1071  							Routes: []*envoy_config_route_v3.Route{
  1072  								{
  1073  									Match: &envoy_config_route_v3.RouteMatch{
  1074  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Path{
  1075  											Path: "/foo/",
  1076  										},
  1077  									},
  1078  									Action: toRouteAction("random-namespace", "foo-slash-exact", "8080"),
  1079  								},
  1080  								{
  1081  									Match: &envoy_config_route_v3.RouteMatch{
  1082  										PathSpecifier: &envoy_config_route_v3.RouteMatch_PathSeparatedPrefix{
  1083  											PathSeparatedPrefix: "/aaa/bbb",
  1084  										},
  1085  									},
  1086  									Action: toRouteAction("random-namespace", "aaa-slash-bbb-slash-prefix", "8080"),
  1087  								},
  1088  							},
  1089  						},
  1090  					},
  1091  				}),
  1092  			},
  1093  			{Any: toAny(toEnvoyCluster("random-namespace", "aaa-prefix", "8080"))},
  1094  			{Any: toAny(toEnvoyCluster("random-namespace", "aaa-slash-bbb-prefix", "8080"))},
  1095  			{Any: toAny(toEnvoyCluster("random-namespace", "aaa-slash-bbb-slash-prefix", "8080"))},
  1096  			{Any: toAny(toEnvoyCluster("random-namespace", "foo-exact", "8080"))},
  1097  			{Any: toAny(toEnvoyCluster("random-namespace", "foo-prefix", "8080"))},
  1098  			{Any: toAny(toEnvoyCluster("random-namespace", "foo-slash-exact", "8080"))},
  1099  		},
  1100  	},
  1101  }
  1102  
  1103  // Conformance/ProxyProtocol test
  1104  var proxyProtocolListeners = []model.HTTPListener{
  1105  	{
  1106  		Sources: []model.FullyQualifiedResource{
  1107  			{
  1108  				Name:      "load-balancing",
  1109  				Namespace: "random-namespace",
  1110  				Version:   "networking.k8s.io/v1",
  1111  				Kind:      "Ingress",
  1112  			},
  1113  		},
  1114  		Port:     80,
  1115  		Hostname: "*",
  1116  		Routes: []model.HTTPRoute{
  1117  			{
  1118  				Backends: []model.Backend{
  1119  					{
  1120  						Name:      "default-backend",
  1121  						Namespace: "random-namespace",
  1122  						Port: &model.BackendPort{
  1123  							Port: 8080,
  1124  						},
  1125  					},
  1126  				},
  1127  			},
  1128  		},
  1129  	},
  1130  }
  1131  
  1132  func hostNetworkListeners(port uint32) []model.HTTPListener {
  1133  	return []model.HTTPListener{
  1134  		{
  1135  			Sources: []model.FullyQualifiedResource{
  1136  				{
  1137  					Name:      "load-balancing",
  1138  					Namespace: "random-namespace",
  1139  					Version:   "networking.k8s.io/v1",
  1140  					Kind:      "Ingress",
  1141  				},
  1142  			},
  1143  			Port:     port,
  1144  			Hostname: "*",
  1145  			Routes: []model.HTTPRoute{
  1146  				{
  1147  					Backends: []model.Backend{
  1148  						{
  1149  							Name:      "default-backend",
  1150  							Namespace: "random-namespace",
  1151  							Port: &model.BackendPort{
  1152  								Port: 8080,
  1153  							},
  1154  						},
  1155  					},
  1156  				},
  1157  			},
  1158  		},
  1159  	}
  1160  }
  1161  
  1162  var proxyProtoListenersCiliumEnvoyConfig = &ciliumv2.CiliumEnvoyConfig{
  1163  	ObjectMeta: metav1.ObjectMeta{
  1164  		Name:      "cilium-ingress-random-namespace-load-balancing",
  1165  		Namespace: "random-namespace",
  1166  		Labels: map[string]string{
  1167  			"cilium.io/use-original-source-address": "false",
  1168  		},
  1169  	},
  1170  	Spec: ciliumv2.CiliumEnvoyConfigSpec{
  1171  		Services: []*ciliumv2.ServiceListener{
  1172  			{
  1173  				Name:      "cilium-ingress-load-balancing",
  1174  				Namespace: "random-namespace",
  1175  				Ports: []uint16{
  1176  					80,
  1177  				},
  1178  			},
  1179  		},
  1180  		BackendServices: []*ciliumv2.Service{
  1181  			{
  1182  				Name:      "default-backend",
  1183  				Namespace: "random-namespace",
  1184  				Ports:     []string{"8080"},
  1185  			},
  1186  		},
  1187  		Resources: []ciliumv2.XDSResource{
  1188  			{Any: toHTTPListenerXDSResource(true, nil, nil)},
  1189  			{
  1190  				Any: toAny(&envoy_config_route_v3.RouteConfiguration{
  1191  					Name: "listener-insecure",
  1192  					VirtualHosts: []*envoy_config_route_v3.VirtualHost{
  1193  						{
  1194  							Name:    "*",
  1195  							Domains: []string{"*"},
  1196  							Routes: []*envoy_config_route_v3.Route{
  1197  								{
  1198  									Match: &envoy_config_route_v3.RouteMatch{
  1199  										PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
  1200  											Prefix: "/",
  1201  										},
  1202  									},
  1203  									Action: toRouteAction("random-namespace", "default-backend", "8080"),
  1204  								},
  1205  							},
  1206  						},
  1207  					},
  1208  				}),
  1209  			},
  1210  			{Any: toAny(toEnvoyCluster("random-namespace", "default-backend", "8080"))},
  1211  		},
  1212  	},
  1213  }
  1214  
  1215  func hostNetworkListenersCiliumEnvoyConfig(address string, port uint32, nodeLabelSelector *slim_metav1.LabelSelector) *ciliumv2.CiliumEnvoyConfig {
  1216  	return &ciliumv2.CiliumEnvoyConfig{
  1217  		ObjectMeta: metav1.ObjectMeta{
  1218  			Name:      "cilium-ingress-random-namespace-load-balancing",
  1219  			Namespace: "random-namespace",
  1220  			Labels: map[string]string{
  1221  				"cilium.io/use-original-source-address": "false",
  1222  			},
  1223  		},
  1224  		Spec: ciliumv2.CiliumEnvoyConfigSpec{
  1225  			NodeSelector: nodeLabelSelector,
  1226  			Services: []*ciliumv2.ServiceListener{
  1227  				{
  1228  					Name:      "cilium-ingress-load-balancing",
  1229  					Namespace: "random-namespace",
  1230  					Ports: []uint16{
  1231  						uint16(port),
  1232  					},
  1233  				},
  1234  			},
  1235  			BackendServices: []*ciliumv2.Service{
  1236  				{
  1237  					Name:      "default-backend",
  1238  					Namespace: "random-namespace",
  1239  					Ports:     []string{"8080"},
  1240  				},
  1241  			},
  1242  			Resources: []ciliumv2.XDSResource{
  1243  				{Any: toHTTPListenerXDSResource(false, model.AddressOf(address), model.AddressOf(port))},
  1244  				{
  1245  					Any: toAny(&envoy_config_route_v3.RouteConfiguration{
  1246  						Name: "listener-insecure",
  1247  						VirtualHosts: []*envoy_config_route_v3.VirtualHost{
  1248  							{
  1249  								Name:    "*",
  1250  								Domains: []string{"*"},
  1251  								Routes: []*envoy_config_route_v3.Route{
  1252  									{
  1253  										Match: &envoy_config_route_v3.RouteMatch{
  1254  											PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
  1255  												Prefix: "/",
  1256  											},
  1257  										},
  1258  										Action: toRouteAction("random-namespace", "default-backend", "8080"),
  1259  									},
  1260  								},
  1261  							},
  1262  						},
  1263  					}),
  1264  				},
  1265  				{Any: toAny(toEnvoyCluster("random-namespace", "default-backend", "8080"))},
  1266  			},
  1267  		},
  1268  	}
  1269  }
  1270  
  1271  func toAny(message proto.Message) *anypb.Any {
  1272  	a, err := anypb.New(message)
  1273  	if err != nil {
  1274  		return nil
  1275  	}
  1276  	return a
  1277  }
  1278  
  1279  // default timeout for the ingress conformance tests
  1280  var listenerDefaultTimeout = model.Timeout{
  1281  	Request: nil,
  1282  }
  1283  
  1284  func uint32p(in uint32) *uint32 {
  1285  	return &in
  1286  }
  1287  
  1288  var complexNodePortIngressListeners = []model.HTTPListener{
  1289  	{
  1290  		Sources: []model.FullyQualifiedResource{
  1291  			{
  1292  				Name:      "dummy-ingress",
  1293  				Namespace: "dummy-namespace",
  1294  				Version:   "v1",
  1295  				Kind:      "Ingress",
  1296  				UID:       "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e",
  1297  			},
  1298  		},
  1299  		Port:     80,
  1300  		Hostname: "*",
  1301  		Routes: []model.HTTPRoute{
  1302  			{
  1303  				Backends: []model.Backend{
  1304  					{
  1305  						Name:      "default-backend",
  1306  						Namespace: "dummy-namespace",
  1307  						Port: &model.BackendPort{
  1308  							Port: 8080,
  1309  						},
  1310  					},
  1311  				},
  1312  				Timeout: listenerDefaultTimeout,
  1313  			},
  1314  			{
  1315  				PathMatch: model.StringMatch{
  1316  					Exact: "/dummy-path",
  1317  				},
  1318  				Backends: []model.Backend{
  1319  					{
  1320  						Name:      "dummy-backend",
  1321  						Namespace: "dummy-namespace",
  1322  						Port: &model.BackendPort{
  1323  							Port: 8080,
  1324  						},
  1325  					},
  1326  				},
  1327  				Timeout: listenerDefaultTimeout,
  1328  			},
  1329  			{
  1330  				PathMatch: model.StringMatch{
  1331  					Prefix: "/another-dummy-path",
  1332  				},
  1333  				Backends: []model.Backend{
  1334  					{
  1335  						Name:      "another-dummy-backend",
  1336  						Namespace: "dummy-namespace",
  1337  						Port: &model.BackendPort{
  1338  							Port: 8081,
  1339  						},
  1340  					},
  1341  				},
  1342  				Timeout: listenerDefaultTimeout,
  1343  			},
  1344  		},
  1345  		Service: &model.Service{
  1346  			Type:             "NodePort",
  1347  			InsecureNodePort: uint32p(30000),
  1348  			SecureNodePort:   uint32p(30001),
  1349  		},
  1350  	},
  1351  	{
  1352  		Sources: []model.FullyQualifiedResource{
  1353  			{
  1354  				Name:      "dummy-ingress",
  1355  				Namespace: "dummy-namespace",
  1356  				Version:   "v1",
  1357  				Kind:      "Ingress",
  1358  				UID:       "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e",
  1359  			},
  1360  		},
  1361  		Port:     443,
  1362  		Hostname: "another-very-secure.server.com",
  1363  		TLS: []model.TLSSecret{
  1364  			{
  1365  				Name:      "tls-another-very-secure-server-com",
  1366  				Namespace: "dummy-namespace",
  1367  			},
  1368  		},
  1369  		Routes: []model.HTTPRoute{
  1370  			{
  1371  				Backends: []model.Backend{
  1372  					{
  1373  						Name:      "default-backend",
  1374  						Namespace: "dummy-namespace",
  1375  						Port: &model.BackendPort{
  1376  							Port: 8080,
  1377  						},
  1378  					},
  1379  				},
  1380  				Timeout: listenerDefaultTimeout,
  1381  			},
  1382  			{
  1383  				PathMatch: model.StringMatch{
  1384  					Exact: "/dummy-path",
  1385  				},
  1386  				Backends: []model.Backend{
  1387  					{
  1388  						Name:      "dummy-backend",
  1389  						Namespace: "dummy-namespace",
  1390  						Port: &model.BackendPort{
  1391  							Port: 8080,
  1392  						},
  1393  					},
  1394  				},
  1395  				Timeout: listenerDefaultTimeout,
  1396  			},
  1397  			{
  1398  				PathMatch: model.StringMatch{
  1399  					Prefix: "/another-dummy-path",
  1400  				},
  1401  				Backends: []model.Backend{
  1402  					{
  1403  						Name:      "another-dummy-backend",
  1404  						Namespace: "dummy-namespace",
  1405  						Port: &model.BackendPort{
  1406  							Port: 8081,
  1407  						},
  1408  					},
  1409  				},
  1410  				Timeout: listenerDefaultTimeout,
  1411  			},
  1412  		},
  1413  		Service: &model.Service{
  1414  			Type:             "NodePort",
  1415  			InsecureNodePort: uint32p(30000),
  1416  			SecureNodePort:   uint32p(30001),
  1417  		},
  1418  	},
  1419  	{
  1420  		Sources: []model.FullyQualifiedResource{
  1421  			{
  1422  				Name:      "dummy-ingress",
  1423  				Namespace: "dummy-namespace",
  1424  				Version:   "v1",
  1425  				Kind:      "Ingress",
  1426  				UID:       "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e",
  1427  			},
  1428  		},
  1429  		Port:     443,
  1430  		Hostname: "not-in-use.another-very-secure.server.com",
  1431  		TLS: []model.TLSSecret{
  1432  			{
  1433  				Name:      "tls-another-very-secure-server-com",
  1434  				Namespace: "dummy-namespace",
  1435  			},
  1436  		},
  1437  		Routes: []model.HTTPRoute{
  1438  			{
  1439  				Backends: []model.Backend{
  1440  					{
  1441  						Name:      "default-backend",
  1442  						Namespace: "dummy-namespace",
  1443  						Port: &model.BackendPort{
  1444  							Port: 8080,
  1445  						},
  1446  					},
  1447  				},
  1448  				Timeout: listenerDefaultTimeout,
  1449  			},
  1450  			{
  1451  				PathMatch: model.StringMatch{
  1452  					Exact: "/dummy-path",
  1453  				},
  1454  				Backends: []model.Backend{
  1455  					{
  1456  						Name:      "dummy-backend",
  1457  						Namespace: "dummy-namespace",
  1458  						Port: &model.BackendPort{
  1459  							Port: 8080,
  1460  						},
  1461  					},
  1462  				},
  1463  				Timeout: listenerDefaultTimeout,
  1464  			},
  1465  			{
  1466  				PathMatch: model.StringMatch{
  1467  					Prefix: "/another-dummy-path",
  1468  				},
  1469  				Backends: []model.Backend{
  1470  					{
  1471  						Name:      "another-dummy-backend",
  1472  						Namespace: "dummy-namespace",
  1473  						Port: &model.BackendPort{
  1474  							Port: 8081,
  1475  						},
  1476  					},
  1477  				},
  1478  				Timeout: listenerDefaultTimeout,
  1479  			},
  1480  		},
  1481  		Service: &model.Service{
  1482  			Type:             "NodePort",
  1483  			InsecureNodePort: uint32p(30000),
  1484  			SecureNodePort:   uint32p(30001),
  1485  		},
  1486  	},
  1487  	{
  1488  		Sources: []model.FullyQualifiedResource{
  1489  			{
  1490  				Name:      "dummy-ingress",
  1491  				Namespace: "dummy-namespace",
  1492  				Version:   "v1",
  1493  				Kind:      "Ingress",
  1494  				UID:       "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e",
  1495  			},
  1496  		},
  1497  		Port:     443,
  1498  		Hostname: "very-secure.server.com",
  1499  		TLS: []model.TLSSecret{
  1500  			{
  1501  				Name:      "tls-very-secure-server-com",
  1502  				Namespace: "dummy-namespace",
  1503  			},
  1504  		},
  1505  		Routes: []model.HTTPRoute{
  1506  			{
  1507  				Backends: []model.Backend{
  1508  					{
  1509  						Name:      "default-backend",
  1510  						Namespace: "dummy-namespace",
  1511  						Port: &model.BackendPort{
  1512  							Port: 8080,
  1513  						},
  1514  					},
  1515  				},
  1516  				Timeout: listenerDefaultTimeout,
  1517  			},
  1518  			{
  1519  				PathMatch: model.StringMatch{
  1520  					Exact: "/dummy-path",
  1521  				},
  1522  				Backends: []model.Backend{
  1523  					{
  1524  						Name:      "dummy-backend",
  1525  						Namespace: "dummy-namespace",
  1526  						Port: &model.BackendPort{
  1527  							Port: 8080,
  1528  						},
  1529  					},
  1530  				},
  1531  				Timeout: listenerDefaultTimeout,
  1532  			},
  1533  			{
  1534  				PathMatch: model.StringMatch{
  1535  					Prefix: "/another-dummy-path",
  1536  				},
  1537  				Backends: []model.Backend{
  1538  					{
  1539  						Name:      "another-dummy-backend",
  1540  						Namespace: "dummy-namespace",
  1541  						Port: &model.BackendPort{
  1542  							Port: 8081,
  1543  						},
  1544  					},
  1545  				},
  1546  				Timeout: listenerDefaultTimeout,
  1547  			},
  1548  		},
  1549  		Service: &model.Service{
  1550  			Type:             "NodePort",
  1551  			InsecureNodePort: uint32p(30000),
  1552  			SecureNodePort:   uint32p(30001),
  1553  		},
  1554  	},
  1555  }
  1556  
  1557  var complexNodePortIngressCiliumEnvoyConfig = &ciliumv2.CiliumEnvoyConfig{
  1558  	ObjectMeta: metav1.ObjectMeta{
  1559  		Name:      "cilium-ingress-dummy-namespace-dummy-ingress",
  1560  		Namespace: "dummy-namespace",
  1561  		Labels: map[string]string{
  1562  			"cilium.io/use-original-source-address": "false",
  1563  		},
  1564  	},
  1565  	Spec: ciliumv2.CiliumEnvoyConfigSpec{
  1566  		NodeSelector: &slim_metav1.LabelSelector{MatchLabels: map[string]slim_metav1.MatchLabelsValue{"a": "b"}},
  1567  		Services: []*ciliumv2.ServiceListener{
  1568  			{
  1569  				Name:      "cilium-ingress-dummy-ingress",
  1570  				Namespace: "dummy-namespace",
  1571  				Ports:     []uint16{80, 443},
  1572  			},
  1573  		},
  1574  		BackendServices: []*ciliumv2.Service{
  1575  			{
  1576  				Name:      "another-dummy-backend",
  1577  				Namespace: "dummy-namespace",
  1578  				Ports:     []string{"8081"},
  1579  			},
  1580  			{
  1581  				Name:      "default-backend",
  1582  				Namespace: "dummy-namespace",
  1583  				Ports:     []string{"8080"},
  1584  			},
  1585  			{
  1586  				Name:      "dummy-backend",
  1587  				Namespace: "dummy-namespace",
  1588  				Ports:     []string{"8080"},
  1589  			},
  1590  		},
  1591  		Resources: []ciliumv2.XDSResource{
  1592  			{Any: toAny(
  1593  				&envoy_config_listener.Listener{
  1594  					Name: "listener",
  1595  					FilterChains: []*envoy_config_listener.FilterChain{
  1596  						toInsecureListenerFilterChain(),
  1597  						toSecureListenerFilterChain([]string{"another-very-secure.server.com", "not-in-use.another-very-secure.server.com"}, "cilium-secrets/dummy-namespace-tls-another-very-secure-server-com"),
  1598  						toSecureListenerFilterChain([]string{"very-secure.server.com"}, "cilium-secrets/dummy-namespace-tls-very-secure-server-com"),
  1599  					},
  1600  					AdditionalAddresses: []*envoy_config_listener.AdditionalAddress{
  1601  						{
  1602  							Address: &envoy_config_core_v3.Address{
  1603  								Address: &envoy_config_core_v3.Address_SocketAddress{
  1604  									SocketAddress: &envoy_config_core_v3.SocketAddress{
  1605  										Address: "0.0.0.0",
  1606  										PortSpecifier: &envoy_config_core_v3.SocketAddress_PortValue{
  1607  											PortValue: 443,
  1608  										},
  1609  									},
  1610  								},
  1611  							},
  1612  						},
  1613  					},
  1614  					Address: &envoy_config_core_v3.Address{
  1615  						Address: &envoy_config_core_v3.Address_SocketAddress{
  1616  							SocketAddress: &envoy_config_core_v3.SocketAddress{
  1617  								Address: "0.0.0.0",
  1618  								PortSpecifier: &envoy_config_core_v3.SocketAddress_PortValue{
  1619  									PortValue: 80,
  1620  								},
  1621  							},
  1622  						},
  1623  					},
  1624  					ListenerFilters: []*envoy_config_listener.ListenerFilter{
  1625  						{
  1626  							Name: "envoy.filters.listener.tls_inspector",
  1627  							ConfigType: &envoy_config_listener.ListenerFilter_TypedConfig{
  1628  								TypedConfig: toAny(&envoy_extensions_listener_tls_inspector_v3.TlsInspector{}),
  1629  							},
  1630  						},
  1631  					},
  1632  					SocketOptions: socketOptions,
  1633  				})},
  1634  			{
  1635  				Any: toAny(&envoy_config_route_v3.RouteConfiguration{
  1636  					Name: "listener-insecure",
  1637  					VirtualHosts: []*envoy_config_route_v3.VirtualHost{
  1638  						{
  1639  							Name:    "*",
  1640  							Domains: domainsHelper("*"),
  1641  							Routes: []*envoy_config_route_v3.Route{
  1642  								{
  1643  									Match:  envoyRouteMatchExactPath("/dummy-path"),
  1644  									Action: envoyRouteAction("dummy-namespace", "dummy-backend", "8080"),
  1645  								},
  1646  								{
  1647  									Match:  envoyRouteMatchPrefixPath("/another-dummy-path"),
  1648  									Action: envoyRouteAction("dummy-namespace", "another-dummy-backend", "8081"),
  1649  								},
  1650  								{
  1651  									Match:  envoyRouteMatchRootPath(),
  1652  									Action: envoyRouteAction("dummy-namespace", "default-backend", "8080"),
  1653  								},
  1654  							},
  1655  						},
  1656  					},
  1657  				}),
  1658  			},
  1659  			{
  1660  				Any: toAny(&envoy_config_route_v3.RouteConfiguration{
  1661  					Name: "listener-secure",
  1662  					VirtualHosts: []*envoy_config_route_v3.VirtualHost{
  1663  						{
  1664  							Name:    "another-very-secure.server.com",
  1665  							Domains: domainsHelper("another-very-secure.server.com"),
  1666  							Routes: []*envoy_config_route_v3.Route{
  1667  								{
  1668  									Match:  envoyRouteMatchExactPath("/dummy-path"),
  1669  									Action: envoyRouteAction("dummy-namespace", "dummy-backend", "8080"),
  1670  								},
  1671  								{
  1672  									Match:  envoyRouteMatchPrefixPath("/another-dummy-path"),
  1673  									Action: envoyRouteAction("dummy-namespace", "another-dummy-backend", "8081"),
  1674  								},
  1675  								{
  1676  									Match:  envoyRouteMatchRootPath(),
  1677  									Action: envoyRouteAction("dummy-namespace", "default-backend", "8080"),
  1678  								},
  1679  							},
  1680  						},
  1681  						{
  1682  							Name:    "not-in-use.another-very-secure.server.com",
  1683  							Domains: domainsHelper("not-in-use.another-very-secure.server.com"),
  1684  							Routes: []*envoy_config_route_v3.Route{
  1685  								{
  1686  									Match:  envoyRouteMatchExactPath("/dummy-path"),
  1687  									Action: envoyRouteAction("dummy-namespace", "dummy-backend", "8080"),
  1688  								},
  1689  								{
  1690  									Match:  envoyRouteMatchPrefixPath("/another-dummy-path"),
  1691  									Action: envoyRouteAction("dummy-namespace", "another-dummy-backend", "8081"),
  1692  								},
  1693  								{
  1694  									Match:  envoyRouteMatchRootPath(),
  1695  									Action: envoyRouteAction("dummy-namespace", "default-backend", "8080"),
  1696  								},
  1697  							},
  1698  						},
  1699  						{
  1700  							Name:    "very-secure.server.com",
  1701  							Domains: domainsHelper("very-secure.server.com"),
  1702  							Routes: []*envoy_config_route_v3.Route{
  1703  								{
  1704  									Match:  envoyRouteMatchExactPath("/dummy-path"),
  1705  									Action: envoyRouteAction("dummy-namespace", "dummy-backend", "8080"),
  1706  								},
  1707  								{
  1708  									Match:  envoyRouteMatchPrefixPath("/another-dummy-path"),
  1709  									Action: envoyRouteAction("dummy-namespace", "another-dummy-backend", "8081"),
  1710  								},
  1711  								{
  1712  									Match:  envoyRouteMatchRootPath(),
  1713  									Action: envoyRouteAction("dummy-namespace", "default-backend", "8080"),
  1714  								},
  1715  							},
  1716  						},
  1717  					},
  1718  				}),
  1719  			},
  1720  			{Any: toAny(toEnvoyCluster("dummy-namespace", "another-dummy-backend", "8081"))},
  1721  			{Any: toAny(toEnvoyCluster("dummy-namespace", "default-backend", "8080"))},
  1722  			{Any: toAny(toEnvoyCluster("dummy-namespace", "dummy-backend", "8080"))},
  1723  		},
  1724  	},
  1725  }
  1726  
  1727  func domainsHelper(domain string) []string {
  1728  	if domain == "*" {
  1729  		return []string{domain}
  1730  	}
  1731  
  1732  	return []string{domain, fmt.Sprintf("%s:*", domain)}
  1733  }
  1734  
  1735  func envoyRouteMatchExactPath(path string) *envoy_config_route_v3.RouteMatch {
  1736  	return &envoy_config_route_v3.RouteMatch{
  1737  		PathSpecifier: &envoy_config_route_v3.RouteMatch_Path{
  1738  			Path: path,
  1739  		},
  1740  	}
  1741  }
  1742  
  1743  func envoyRouteMatchRootPath() *envoy_config_route_v3.RouteMatch {
  1744  	return &envoy_config_route_v3.RouteMatch{
  1745  		PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
  1746  			Prefix: "/",
  1747  		},
  1748  	}
  1749  }
  1750  
  1751  func envoyRouteMatchPrefixPath(path string) *envoy_config_route_v3.RouteMatch {
  1752  	return &envoy_config_route_v3.RouteMatch{
  1753  		PathSpecifier: &envoy_config_route_v3.RouteMatch_PathSeparatedPrefix{
  1754  			PathSeparatedPrefix: path,
  1755  		},
  1756  	}
  1757  }
  1758  
  1759  func envoyRouteAction(namespace, backend, port string) *envoy_config_route_v3.Route_Route {
  1760  	return &envoy_config_route_v3.Route_Route{
  1761  		Route: &envoy_config_route_v3.RouteAction{
  1762  			ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
  1763  				Cluster: fmt.Sprintf("%s:%s:%s", namespace, backend, port),
  1764  			},
  1765  			MaxStreamDuration: &envoy_config_route_v3.RouteAction_MaxStreamDuration{
  1766  				MaxStreamDuration: &durationpb.Duration{Seconds: 0},
  1767  			},
  1768  		},
  1769  	}
  1770  }