Apply the same approach as the rules system on the TLS configuration choice
Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
This commit is contained in:
parent
4da33c2bc2
commit
0c83ee736c
2 changed files with 132 additions and 38 deletions
|
@ -177,8 +177,8 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
|||
|
||||
// Domain Fronting
|
||||
if !strings.EqualFold(host, serverName) {
|
||||
tlsOptionSNI := findTLSOptionName(tlsOptionsForHost, serverName)
|
||||
tlsOptionHeader := findTLSOptionName(tlsOptionsForHost, host)
|
||||
tlsOptionHeader := findTLSOptionName(tlsOptionsForHost, host, true)
|
||||
tlsOptionSNI := findTLSOptionName(tlsOptionsForHost, serverName, false)
|
||||
|
||||
if tlsOptionHeader != tlsOptionSNI {
|
||||
log.WithoutContext().
|
||||
|
@ -322,16 +322,43 @@ func (m *Manager) buildTCPHandler(ctx context.Context, router *runtime.TCPRouter
|
|||
return tcp.NewChain().Extend(*mHandler).Then(sHandler)
|
||||
}
|
||||
|
||||
func findTLSOptionName(tlsOptionsForHost map[string]string, host string) string {
|
||||
func findTLSOptionName(tlsOptionsForHost map[string]string, host string, fqdn bool) string {
|
||||
name := findTLSOptName(tlsOptionsForHost, host, fqdn)
|
||||
if name != "" {
|
||||
return name
|
||||
}
|
||||
|
||||
name = findTLSOptName(tlsOptionsForHost, strings.ToLower(host), fqdn)
|
||||
if name != "" {
|
||||
return name
|
||||
}
|
||||
|
||||
return traefiktls.DefaultTLSConfigName
|
||||
}
|
||||
|
||||
func findTLSOptName(tlsOptionsForHost map[string]string, host string, fqdn bool) string {
|
||||
tlsOptions, ok := tlsOptionsForHost[host]
|
||||
if ok {
|
||||
return tlsOptions
|
||||
}
|
||||
|
||||
tlsOptions, ok = tlsOptionsForHost[strings.ToLower(host)]
|
||||
if !fqdn {
|
||||
return ""
|
||||
}
|
||||
|
||||
if last := len(host) - 1; last >= 0 && host[last] == '.' {
|
||||
tlsOptions, ok = tlsOptionsForHost[host[:last]]
|
||||
if ok {
|
||||
return tlsOptions
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
tlsOptions, ok = tlsOptionsForHost[host+"."]
|
||||
if ok {
|
||||
return tlsOptions
|
||||
}
|
||||
|
||||
return traefiktls.DefaultTLSConfigName
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
},
|
||||
"bar": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service",
|
||||
Rule: "HostSNI(`foo.bar`)",
|
||||
|
@ -136,7 +135,6 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
},
|
||||
"bar": {
|
||||
Router: &dynamic.Router{
|
||||
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service",
|
||||
Rule: "Host(`bar.foo`) && PathPrefix(`/path`)",
|
||||
|
@ -240,7 +238,6 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
},
|
||||
"bar": {
|
||||
TCPRouter: &dynamic.TCPRouter{
|
||||
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "foo-service",
|
||||
Rule: "HostSNI(`foo.bar`)",
|
||||
|
@ -340,9 +337,26 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDomainFronting(t *testing.T) {
|
||||
tlsOptionsBase := map[string]traefiktls.Options{
|
||||
"default": {
|
||||
MinVersion: "VersionTLS10",
|
||||
},
|
||||
"host1@file": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
"host1@crd": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
}
|
||||
|
||||
entryPoints := []string{"web"}
|
||||
|
||||
tests := []struct {
|
||||
desc string
|
||||
routers map[string]*runtime.RouterInfo
|
||||
tlsOptions map[string]traefiktls.Options
|
||||
host string
|
||||
ServerName string
|
||||
expectedStatus int
|
||||
}{
|
||||
{
|
||||
|
@ -350,7 +364,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
routers: map[string]*runtime.RouterInfo{
|
||||
"router-1@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -359,12 +373,15 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
"router-2@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host2.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
},
|
||||
tlsOptions: tlsOptionsBase,
|
||||
host: "host1.local",
|
||||
ServerName: "host2.local",
|
||||
expectedStatus: http.StatusMisdirectedRequest,
|
||||
},
|
||||
{
|
||||
|
@ -372,7 +389,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
routers: map[string]*runtime.RouterInfo{
|
||||
"router-1@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -381,7 +398,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
"router-2@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host2.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -389,6 +406,9 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
tlsOptions: tlsOptionsBase,
|
||||
host: "host1.local",
|
||||
ServerName: "host2.local",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
|
@ -396,7 +416,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
routers: map[string]*runtime.RouterInfo{
|
||||
"router-1@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -405,7 +425,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
"router-2@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local`) && PathPrefix(`/foo`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "default",
|
||||
|
@ -414,7 +434,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
"router-3@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host2.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -422,6 +442,9 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
tlsOptions: tlsOptionsBase,
|
||||
host: "host1.local",
|
||||
ServerName: "host2.local",
|
||||
expectedStatus: http.StatusMisdirectedRequest,
|
||||
},
|
||||
{
|
||||
|
@ -429,7 +452,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
routers: map[string]*runtime.RouterInfo{
|
||||
"router-1@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -438,7 +461,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
"router-2@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local`) && PathPrefix(`/bar`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -447,7 +470,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
"router-3@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host2.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -455,6 +478,9 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
tlsOptions: tlsOptionsBase,
|
||||
host: "host1.local",
|
||||
ServerName: "host2.local",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
|
@ -462,7 +488,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
routers: map[string]*runtime.RouterInfo{
|
||||
"router-1@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -471,7 +497,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
"router-2@crd": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host2.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1",
|
||||
|
@ -479,6 +505,9 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
tlsOptions: tlsOptionsBase,
|
||||
host: "host1.local",
|
||||
ServerName: "host2.local",
|
||||
expectedStatus: http.StatusMisdirectedRequest,
|
||||
},
|
||||
{
|
||||
|
@ -486,7 +515,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
routers: map[string]*runtime.RouterInfo{
|
||||
"router-1@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1@crd",
|
||||
|
@ -495,7 +524,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
"router-2@crd": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: []string{"web"},
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host2.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1@crd",
|
||||
|
@ -503,25 +532,63 @@ func TestDomainFronting(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
tlsOptions: tlsOptionsBase,
|
||||
host: "host1.local",
|
||||
ServerName: "host2.local",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Request is misdirected when server name is empty and the host name is an FQDN, but router's rule is not",
|
||||
routers: map[string]*runtime.RouterInfo{
|
||||
"router-1@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1@file",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tlsOptions: map[string]traefiktls.Options{
|
||||
"default": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
"host1@file": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
host: "host1.local.",
|
||||
expectedStatus: http.StatusMisdirectedRequest,
|
||||
},
|
||||
{
|
||||
desc: "Request is misdirected when server name is empty and the host name is not FQDN, but router's rule is",
|
||||
routers: map[string]*runtime.RouterInfo{
|
||||
"router-1@file": {
|
||||
Router: &dynamic.Router{
|
||||
EntryPoints: entryPoints,
|
||||
Rule: "Host(`host1.local.`)",
|
||||
TLS: &dynamic.RouterTLSConfig{
|
||||
Options: "host1@file",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tlsOptions: map[string]traefiktls.Options{
|
||||
"default": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
"host1@file": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
host: "host1.local",
|
||||
expectedStatus: http.StatusMisdirectedRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
entryPoints := []string{"web"}
|
||||
tlsOptions := map[string]traefiktls.Options{
|
||||
"default": {
|
||||
MinVersion: "VersionTLS10",
|
||||
},
|
||||
"host1@file": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
"host1@crd": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
}
|
||||
|
||||
conf := &runtime.Configuration{
|
||||
Routers: test.routers,
|
||||
}
|
||||
|
@ -529,7 +596,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
serviceManager := tcp.NewManager(conf)
|
||||
|
||||
tlsManager := traefiktls.NewManager()
|
||||
tlsManager.UpdateConfigs(context.Background(), map[string]traefiktls.Store{}, tlsOptions, []*traefiktls.CertAndStores{})
|
||||
tlsManager.UpdateConfigs(context.Background(), map[string]traefiktls.Store{}, test.tlsOptions, []*traefiktls.CertAndStores{})
|
||||
|
||||
httpsHandler := map[string]http.Handler{
|
||||
"web": http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {}),
|
||||
|
@ -545,9 +612,9 @@ func TestDomainFronting(t *testing.T) {
|
|||
require.True(t, ok)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
req.Host = "host1.local"
|
||||
req.Host = test.host
|
||||
req.TLS = &tls.ConnectionState{
|
||||
ServerName: "host2.local",
|
||||
ServerName: test.ServerName,
|
||||
}
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
Loading…
Reference in a new issue