diff --git a/integration/testdata/rawdata-gateway.json b/integration/testdata/rawdata-gateway.json index 6ed949440..c51f00a39 100644 --- a/integration/testdata/rawdata-gateway.json +++ b/integration/testdata/rawdata-gateway.json @@ -186,7 +186,7 @@ "service": "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-footlspassthrough-0-e3b0c44298fc1c149afb-wrr", "rule": "HostSNI(`foo.bar`)", "ruleSyntax": "v3", - "priority": 18, + "priority": 7, "tls": { "passthrough": true }, diff --git a/pkg/provider/kubernetes/gateway/kubernetes_test.go b/pkg/provider/kubernetes/gateway/kubernetes_test.go index c25a4b4c0..183fe4dae 100644 --- a/pkg/provider/kubernetes/gateway/kubernetes_test.go +++ b/pkg/provider/kubernetes/gateway/kubernetes_test.go @@ -4582,6 +4582,7 @@ func TestLoadTLSRoutes(t *testing.T) { Routers: map[string]*dynamic.TCPRouter{ "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-TCP-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"TCP"}, + Priority: 0, Rule: "HostSNI(`*`)", RuleSyntax: "v3", Service: "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-TCP-0-e3b0c44298fc1c149afb-wrr", @@ -4799,6 +4800,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, Service: "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-tcp-0-e3b0c44298fc1c149afb-wrr", + Priority: 15, Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -4866,6 +4868,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, Service: "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-tcp-0-e3b0c44298fc1c149afb-wrr", + Priority: 0, Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5026,6 +5029,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, Service: "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb-wrr", + Priority: 15, Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5085,6 +5089,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, Service: "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb-wrr", + Priority: 15, Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5144,6 +5149,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, Service: "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb-wrr", + Priority: 15, Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5203,6 +5209,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, Service: "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb-wrr", + Priority: 15, Rule: "HostSNI(`foo.example.com`) || HostSNI(`bar.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5262,6 +5269,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-default-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, Service: "tlsroute-default-tls-app-default-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb-wrr", + Priority: 11, Rule: "HostSNI(`foo.default`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5321,6 +5329,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-default-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, Service: "tlsroute-default-tls-app-default-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb-wrr", + Priority: 11, Rule: "HostSNI(`foo.default`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5330,6 +5339,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-bar-tls-app-bar-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, Service: "tlsroute-bar-tls-app-bar-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb-wrr", + Priority: 7, Rule: "HostSNI(`foo.bar`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5411,6 +5421,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-bar-tls-app-bar-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls"}, Service: "tlsroute-bar-tls-app-bar-gw-default-my-gateway-ep-tls-0-e3b0c44298fc1c149afb-wrr", + Priority: 7, Rule: "HostSNI(`foo.bar`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5470,6 +5481,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-gw-default-my-gateway-ep-tcp-1-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp-1"}, Service: "tlsroute-default-tls-app-gw-default-my-gateway-ep-tcp-1-0-e3b0c44298fc1c149afb-wrr", + Priority: 0, Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5479,6 +5491,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-gw-default-my-gateway-ep-tcp-1-1-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp-1"}, Service: "tlsroute-default-tls-app-gw-default-my-gateway-ep-tcp-1-1-e3b0c44298fc1c149afb-wrr", + Priority: 0, Rule: "HostSNI(`*`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5561,6 +5574,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, Service: "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-tcp-0-e3b0c44298fc1c149afb-wrr", + Priority: 15, Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5617,6 +5631,7 @@ func TestLoadTLSRoutes(t *testing.T) { "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-tcp-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tcp"}, Service: "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-tcp-0-e3b0c44298fc1c149afb-wrr", + Priority: 15, Rule: "HostSNI(`foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -5839,6 +5854,7 @@ func TestLoadMixedRoutes(t *testing.T) { "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-2-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-2"}, Service: "tlsroute-default-tls-app-1-gw-default-my-gateway-ep-tls-2-0-e3b0c44298fc1c149afb-wrr", + Priority: 24, Rule: "HostSNI(`pass.tls.foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -6026,6 +6042,7 @@ func TestLoadMixedRoutes(t *testing.T) { "tlsroute-default-tls-app-default-gw-default-my-gateway-ep-tls-2-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-2"}, Service: "tlsroute-default-tls-app-default-gw-default-my-gateway-ep-tls-2-0-e3b0c44298fc1c149afb-wrr", + Priority: 24, Rule: "HostSNI(`pass.tls.foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -6185,6 +6202,7 @@ func TestLoadMixedRoutes(t *testing.T) { "tlsroute-default-tls-app-default-gw-default-my-gateway-ep-tls-2-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-2"}, Service: "tlsroute-default-tls-app-default-gw-default-my-gateway-ep-tls-2-0-e3b0c44298fc1c149afb-wrr", + Priority: 24, Rule: "HostSNI(`pass.tls.foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ @@ -6440,6 +6458,7 @@ func TestLoadMixedRoutes(t *testing.T) { "tlsroute-bar-tls-app-bar-gw-default-my-gateway-ep-tls-2-0-e3b0c44298fc1c149afb": { EntryPoints: []string{"tls-2"}, Service: "tlsroute-bar-tls-app-bar-gw-default-my-gateway-ep-tls-2-0-e3b0c44298fc1c149afb-wrr", + Priority: 24, Rule: "HostSNI(`pass.tls.foo.example.com`)", RuleSyntax: "v3", TLS: &dynamic.RouterTCPTLSConfig{ diff --git a/pkg/provider/kubernetes/gateway/tlsroute.go b/pkg/provider/kubernetes/gateway/tlsroute.go index 8c8e1cb76..d481ccacd 100644 --- a/pkg/provider/kubernetes/gateway/tlsroute.go +++ b/pkg/provider/kubernetes/gateway/tlsroute.go @@ -122,9 +122,11 @@ func (p *Provider) loadTLSRoute(listener gatewayListener, route *gatev1alpha2.TL continue } + rule, priority := hostSNIRule(hostnames) router := dynamic.TCPRouter{ RuleSyntax: "v3", - Rule: hostSNIRule(hostnames), + Rule: rule, + Priority: priority, EntryPoints: []string{listener.EPName}, TLS: &dynamic.RouterTCPTLSConfig{ Passthrough: listener.TLS != nil && listener.TLS.Mode != nil && *listener.TLS.Mode == gatev1.TLSModePassthrough, @@ -298,7 +300,9 @@ func (p *Provider) loadTLSServers(namespace string, route *gatev1alpha2.TLSRoute return lb, nil } -func hostSNIRule(hostnames []gatev1.Hostname) string { +func hostSNIRule(hostnames []gatev1.Hostname) (string, int) { + var priority int + rules := make([]string, 0, len(hostnames)) uniqHostnames := map[gatev1.Hostname]struct{}{} @@ -307,14 +311,21 @@ func hostSNIRule(hostnames []gatev1.Hostname) string { continue } + host := string(hostname) + wildcard := strings.Count(host, "*") + + thisPriority := len(hostname) - wildcard + + if priority < thisPriority { + priority = thisPriority + } + if _, exists := uniqHostnames[hostname]; exists { continue } - host := string(hostname) uniqHostnames[hostname] = struct{}{} - wildcard := strings.Count(host, "*") if wildcard == 0 { rules = append(rules, fmt.Sprintf("HostSNI(`%s`)", host)) continue @@ -325,8 +336,8 @@ func hostSNIRule(hostnames []gatev1.Hostname) string { } if len(hostnames) == 0 || len(rules) == 0 { - return "HostSNI(`*`)" + return "HostSNI(`*`)", 0 } - return strings.Join(rules, " || ") + return strings.Join(rules, " || "), priority } diff --git a/pkg/provider/kubernetes/gateway/tlsroute_test.go b/pkg/provider/kubernetes/gateway/tlsroute_test.go index 89a688e5e..64858b09b 100644 --- a/pkg/provider/kubernetes/gateway/tlsroute_test.go +++ b/pkg/provider/kubernetes/gateway/tlsroute_test.go @@ -9,49 +9,58 @@ import ( func Test_hostSNIRule(t *testing.T) { testCases := []struct { - desc string - hostnames []gatev1.Hostname - expectedRule string - expectError bool + desc string + hostnames []gatev1.Hostname + expectedRule string + expectedPriority int + expectError bool }{ { - desc: "Empty", - expectedRule: "HostSNI(`*`)", + desc: "Empty", + expectedRule: "HostSNI(`*`)", + expectedPriority: 0, }, { - desc: "Empty hostname", - hostnames: []gatev1.Hostname{""}, - expectedRule: "HostSNI(`*`)", + desc: "Empty hostname", + hostnames: []gatev1.Hostname{""}, + expectedRule: "HostSNI(`*`)", + expectedPriority: 0, }, { - desc: "Supported wildcard", - hostnames: []gatev1.Hostname{"*.foo"}, - expectedRule: "HostSNIRegexp(`^[a-z0-9-\\.]+\\.foo$`)", + desc: "Supported wildcard", + hostnames: []gatev1.Hostname{"*.foo"}, + expectedRule: "HostSNIRegexp(`^[a-z0-9-\\.]+\\.foo$`)", + expectedPriority: 4, }, { - desc: "Some empty hostnames", - hostnames: []gatev1.Hostname{"foo", "", "bar"}, - expectedRule: "HostSNI(`foo`) || HostSNI(`bar`)", + desc: "Some empty hostnames", + hostnames: []gatev1.Hostname{"foo", "", "bar"}, + expectedRule: "HostSNI(`foo`) || HostSNI(`bar`)", + expectedPriority: 3, }, { - desc: "Valid hostname", - hostnames: []gatev1.Hostname{"foo"}, - expectedRule: "HostSNI(`foo`)", + desc: "Valid hostname", + hostnames: []gatev1.Hostname{"foo"}, + expectedRule: "HostSNI(`foo`)", + expectedPriority: 3, }, { - desc: "Multiple valid hostnames", - hostnames: []gatev1.Hostname{"foo", "bar"}, - expectedRule: "HostSNI(`foo`) || HostSNI(`bar`)", + desc: "Multiple valid hostnames", + hostnames: []gatev1.Hostname{"foo", "bar"}, + expectedRule: "HostSNI(`foo`) || HostSNI(`bar`)", + expectedPriority: 3, }, { - desc: "Multiple valid hostnames with wildcard", - hostnames: []gatev1.Hostname{"bar.foo", "foo.foo", "*.foo"}, - expectedRule: "HostSNI(`bar.foo`) || HostSNI(`foo.foo`) || HostSNIRegexp(`^[a-z0-9-\\.]+\\.foo$`)", + desc: "Multiple valid hostnames with wildcard", + hostnames: []gatev1.Hostname{"bar.foo", "foo.foo", "*.foo"}, + expectedRule: "HostSNI(`bar.foo`) || HostSNI(`foo.foo`) || HostSNIRegexp(`^[a-z0-9-\\.]+\\.foo$`)", + expectedPriority: 7, }, { - desc: "Multiple overlapping hostnames", - hostnames: []gatev1.Hostname{"foo", "bar", "foo", "baz"}, - expectedRule: "HostSNI(`foo`) || HostSNI(`bar`) || HostSNI(`baz`)", + desc: "Multiple overlapping hostnames", + hostnames: []gatev1.Hostname{"foo", "bar", "foo", "baz"}, + expectedRule: "HostSNI(`foo`) || HostSNI(`bar`) || HostSNI(`baz`)", + expectedPriority: 3, }, } @@ -59,8 +68,9 @@ func Test_hostSNIRule(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() - rule := hostSNIRule(test.hostnames) + rule, priority := hostSNIRule(test.hostnames) assert.Equal(t, test.expectedRule, rule) + assert.Equal(t, test.expectedPriority, priority) }) } }