diff --git a/docs/configuration/backends/file.md b/docs/configuration/backends/file.md index 2621a5695..9a23703bd 100644 --- a/docs/configuration/backends/file.md +++ b/docs/configuration/backends/file.md @@ -92,7 +92,10 @@ entryPoints = ["https"] ``` !!! note - adding certificates directly to the entrypoint is still maintained but certificates declared in this way cannot be managed dynamically. + If `tlsConfiguration.entryPoints` is not defined, the certificate is attached to all the `defaultEntryPoints` with a TLS configuration. + +!!! note + Adding certificates directly to the entryPoint is still maintained but certificates declared in this way cannot be managed dynamically. It's recommended to use the file provider to declare certificates. ## Rules in a Separate File diff --git a/docs/user-guide/kv-config.md b/docs/user-guide/kv-config.md index dc1542a74..0fe581983 100644 --- a/docs/user-guide/kv-config.md +++ b/docs/user-guide/kv-config.md @@ -271,7 +271,6 @@ Here is the toml configuration we would like to store in the store : rule = "Path:/test" [[tlsConfiguration]] -entryPoints = ["https"] [tlsConfiguration.certificate] certFile = "path/to/your.cert" keyFile = "path/to/your.key" @@ -333,10 +332,12 @@ And there, the same dynamic configuration in a KV Store (using `prefix = "traefi | Key | Value | |----------------------------------------------------|--------------------| -| `/traefik/tlsconfiguration/1/entrypoints` | `https` | | `/traefik/tlsconfiguration/1/certificate/certfile` | `path/to/your.cert`| | `/traefik/tlsconfiguration/1/certificate/keyfile` | `path/to/your.key` | +!!! note + As `/traefik/tlsconfiguration/1/entrypoints` is not defined, the certificate will be attached to all `defaulEntryPoints` with a TLS configuration (in the example, the entryPoint `https`) + - certificate 2 | Key | Value | diff --git a/integration/https_test.go b/integration/https_test.go index d657eca14..9e59c10d5 100644 --- a/integration/https_test.go +++ b/integration/https_test.go @@ -534,7 +534,6 @@ func modifyCertificateConfFileContent(c *check.C, certFileName, confFileName str CertFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".cert"), KeyFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".key"), }, - EntryPoints: []string{"https"}, }, }, } diff --git a/server/server.go b/server/server.go index 729955fe3..0a9a8d2db 100644 --- a/server/server.go +++ b/server/server.go @@ -435,8 +435,12 @@ func (s *Server) loadConfiguration(configMsg types.ConfigMessage) { if err == nil { for newServerEntryPointName, newServerEntryPoint := range newServerEntryPoints { s.serverEntryPoints[newServerEntryPointName].httpRouter.UpdateHandler(newServerEntryPoint.httpRouter.GetHandler()) - if &newServerEntryPoint.certs != nil { - s.serverEntryPoints[newServerEntryPointName].certs.Set(newServerEntryPoint.certs.Get()) + if newServerEntryPoint.certs.Get() != nil { + if s.globalConfiguration.EntryPoints[newServerEntryPointName].TLS == nil { + log.Debugf("Certificates not added to non-TLS entryPoint %s.", newServerEntryPointName) + } else { + s.serverEntryPoints[newServerEntryPointName].certs.Set(newServerEntryPoint.certs.Get()) + } } log.Infof("Server configuration reloaded on %s", s.serverEntryPoints[newServerEntryPointName].httpServer.Addr) } @@ -448,12 +452,12 @@ func (s *Server) loadConfiguration(configMsg types.ConfigMessage) { } // loadHTTPSConfiguration add/delete HTTPS certificate managed dynamically -func (s *Server) loadHTTPSConfiguration(configurations types.Configurations) (map[string]*traefikTls.DomainsCertificates, error) { +func (s *Server) loadHTTPSConfiguration(configurations types.Configurations, defaultEntryPoints configuration.DefaultEntryPoints) (map[string]*traefikTls.DomainsCertificates, error) { newEPCertificates := make(map[string]*traefikTls.DomainsCertificates) // Get all certificates for _, configuration := range configurations { if configuration.TLSConfiguration != nil && len(configuration.TLSConfiguration) > 0 { - if err := traefikTls.SortTLSConfigurationPerEntryPoints(configuration.TLSConfiguration, newEPCertificates); err != nil { + if err := traefikTls.SortTLSConfigurationPerEntryPoints(configuration.TLSConfiguration, newEPCertificates, defaultEntryPoints); err != nil { return nil, err } } @@ -1204,7 +1208,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura healthcheck.GetHealthCheck().SetBackendsConfiguration(s.routinesPool.Ctx(), backendsHealthCheck) // Get new certificates list sorted per entrypoints // Update certificates - entryPointsCertificates, err := s.loadHTTPSConfiguration(configurations) + entryPointsCertificates, err := s.loadHTTPSConfiguration(configurations, globalConfiguration.DefaultEntryPoints) //sort routes and update certificates for serverEntryPointName, serverEntryPoint := range serverEntryPoints { serverEntryPoint.httpRouter.GetHandler().SortRoutes() diff --git a/server/server_test.go b/server/server_test.go index c93587370..7768717ff 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -644,15 +644,6 @@ func TestServerLoadConfigEmptyBasicAuth(t *testing.T) { }, }, }, - TLSConfiguration: []*tls.Configuration{ - { - Certificate: &tls.Certificate{ - CertFile: localhostCert, - KeyFile: localhostKey, - }, - EntryPoints: []string{"http"}, - }, - }, }, } @@ -662,6 +653,36 @@ func TestServerLoadConfigEmptyBasicAuth(t *testing.T) { } } +func TestServerLoadCertificateWithDefaultEntryPoint(t *testing.T) { + globalConfig := configuration.GlobalConfiguration{ + EntryPoints: configuration.EntryPoints{ + "https": &configuration.EntryPoint{TLS: &tls.TLS{}}, + "http": &configuration.EntryPoint{}, + }, + DefaultEntryPoints: []string{"http", "https"}, + } + + dynamicConfigs := types.Configurations{ + "config": &types.Configuration{ + TLSConfiguration: []*tls.Configuration{ + { + Certificate: &tls.Certificate{ + CertFile: localhostCert, + KeyFile: localhostKey, + }, + }, + }, + }, + } + + srv := NewServer(globalConfig) + if mapEntryPoints, err := srv.loadConfig(dynamicConfigs, globalConfig); err != nil { + t.Fatalf("got error: %s", err) + } else if mapEntryPoints["https"].certs.Get() == nil { + t.Fatal("got error: https entryPoint must have TLS certificates.") + } +} + func TestConfigureBackends(t *testing.T) { validMethod := "Drr" defaultMethod := "wrr" diff --git a/tls/certificate.go b/tls/certificate.go index 09a69bb57..b0a7ef9e0 100644 --- a/tls/certificate.go +++ b/tls/certificate.go @@ -67,6 +67,12 @@ func (f FileOrContent) String() string { return string(f) } +// IsPath returns true if the FileOrContent is a file path, otherwise returns false +func (f FileOrContent) IsPath() bool { + _, err := os.Stat(f.String()) + return err == nil +} + func (f FileOrContent) Read() ([]byte, error) { var content []byte if _, err := os.Stat(f.String()); err == nil { @@ -160,7 +166,7 @@ func (c *Certificate) AppendCertificates(certs map[string]*DomainsCertificates, } } if certExists { - log.Warnf("Into EntryPoint %s, try to add certificate for domains which already have a certificate (%s). The new certificate will not be append to the EntryPoint.", ep, certKey) + log.Warnf("Into EntryPoint %s, try to add certificate for domains which already have this certificate (%s). The new certificate will not be append to the EntryPoint.", ep, certKey) } else { log.Debugf("Add certificate for domains %s", certKey) err = certs[ep].add(certKey, &tlsCert) diff --git a/tls/tls.go b/tls/tls.go index 1798da12d..451cfb511 100644 --- a/tls/tls.go +++ b/tls/tls.go @@ -4,6 +4,13 @@ import ( "crypto/tls" "fmt" "strings" + + "github.com/Sirupsen/logrus" + "github.com/containous/traefik/log" +) + +const ( + certificateHeader = "-----BEGIN CERTIFICATE-----\n" ) // ClientCA defines traefik CA files for a entryPoint @@ -87,11 +94,22 @@ func (r *RootCAs) Type() string { } // SortTLSConfigurationPerEntryPoints converts TLS configuration sorted by Certificates into TLS configuration sorted by EntryPoints -func SortTLSConfigurationPerEntryPoints(configurations []*Configuration, epConfiguration map[string]*DomainsCertificates) error { +func SortTLSConfigurationPerEntryPoints(configurations []*Configuration, epConfiguration map[string]*DomainsCertificates, defaultEntryPoints []string) error { if epConfiguration == nil { epConfiguration = make(map[string]*DomainsCertificates) } for _, conf := range configurations { + if conf.EntryPoints == nil || len(conf.EntryPoints) == 0 { + if log.GetLevel() >= logrus.DebugLevel { + certName := conf.Certificate.CertFile.String() + // Truncate certificate information only if it's a well formed certificate content with more than 50 characters + if !conf.Certificate.CertFile.IsPath() && strings.HasPrefix(conf.Certificate.CertFile.String(), certificateHeader) && len(conf.Certificate.CertFile.String()) > len(certificateHeader)+50 { + certName = strings.TrimPrefix(conf.Certificate.CertFile.String(), certificateHeader)[:50] + } + log.Debugf("No entryPoint is defined to add the certificate %s, it will be added to the default entryPoints: %s", certName, strings.Join(defaultEntryPoints, ", ")) + } + conf.EntryPoints = append(conf.EntryPoints, defaultEntryPoints...) + } for _, ep := range conf.EntryPoints { if err := conf.Certificate.AppendCertificates(epConfiguration, ep); err != nil { return err