1
0
mirror of https://github.com/containous/traefik.git synced 2025-03-19 18:50:12 +03:00

Set rule priority in Gateway API TLSRoute

This commit is contained in:
Augusto Zanellato 2025-01-23 11:46:04 +01:00 committed by GitHub
parent ef887332c2
commit 2b6a04bc1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 75 additions and 35 deletions

View File

@ -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
},

View File

@ -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{

View File

@ -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
}

View File

@ -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)
})
}
}