Check all the C/N and SANs of provided certificates before generating ACME certificates in ACME provider
This commit is contained in:
parent
8380de1bd9
commit
d3edccb839
9 changed files with 97 additions and 86 deletions
|
@ -23,7 +23,6 @@ import (
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
acmeprovider "github.com/containous/traefik/provider/acme"
|
acmeprovider "github.com/containous/traefik/provider/acme"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
traefikTls "github.com/containous/traefik/tls"
|
|
||||||
"github.com/containous/traefik/tls/generate"
|
"github.com/containous/traefik/tls/generate"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/eapache/channels"
|
"github.com/eapache/channels"
|
||||||
|
@ -582,7 +581,7 @@ func (a *ACME) getUncheckedDomains(domains []string, account *Account) []string
|
||||||
|
|
||||||
// Get dynamic certificates
|
// Get dynamic certificates
|
||||||
if a.dynamicCerts != nil && a.dynamicCerts.Get() != nil {
|
if a.dynamicCerts != nil && a.dynamicCerts.Get() != nil {
|
||||||
for domains, certificate := range a.dynamicCerts.Get().(*traefikTls.DomainsCertificates).Get().(map[string]*tls.Certificate) {
|
for domains, certificate := range a.dynamicCerts.Get().(map[string]*tls.Certificate) {
|
||||||
allCerts[domains] = certificate
|
allCerts[domains] = certificate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"github.com/containous/traefik/provider/mesos"
|
"github.com/containous/traefik/provider/mesos"
|
||||||
"github.com/containous/traefik/provider/rancher"
|
"github.com/containous/traefik/provider/rancher"
|
||||||
"github.com/containous/traefik/provider/zk"
|
"github.com/containous/traefik/provider/zk"
|
||||||
traefikTls "github.com/containous/traefik/tls"
|
traefiktls "github.com/containous/traefik/tls"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,14 +46,14 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
config.EntryPoints = configuration.EntryPoints{
|
config.EntryPoints = configuration.EntryPoints{
|
||||||
"foo": {
|
"foo": {
|
||||||
Address: "foo Address",
|
Address: "foo Address",
|
||||||
TLS: &traefikTls.TLS{
|
TLS: &traefiktls.TLS{
|
||||||
MinVersion: "foo MinVersion",
|
MinVersion: "foo MinVersion",
|
||||||
CipherSuites: []string{"foo CipherSuites 1", "foo CipherSuites 2", "foo CipherSuites 3"},
|
CipherSuites: []string{"foo CipherSuites 1", "foo CipherSuites 2", "foo CipherSuites 3"},
|
||||||
Certificates: traefikTls.Certificates{
|
Certificates: traefiktls.Certificates{
|
||||||
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
|
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
|
||||||
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
||||||
},
|
},
|
||||||
ClientCA: traefikTls.ClientCA{
|
ClientCA: traefiktls.ClientCA{
|
||||||
Files: []string{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"},
|
Files: []string{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"},
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
|
@ -91,14 +91,14 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
"fii": {
|
"fii": {
|
||||||
Address: "fii Address",
|
Address: "fii Address",
|
||||||
TLS: &traefikTls.TLS{
|
TLS: &traefiktls.TLS{
|
||||||
MinVersion: "fii MinVersion",
|
MinVersion: "fii MinVersion",
|
||||||
CipherSuites: []string{"fii CipherSuites 1", "fii CipherSuites 2", "fii CipherSuites 3"},
|
CipherSuites: []string{"fii CipherSuites 1", "fii CipherSuites 2", "fii CipherSuites 3"},
|
||||||
Certificates: traefikTls.Certificates{
|
Certificates: traefiktls.Certificates{
|
||||||
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
|
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
|
||||||
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
||||||
},
|
},
|
||||||
ClientCA: traefikTls.ClientCA{
|
ClientCA: traefiktls.ClientCA{
|
||||||
Files: []string{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"},
|
Files: []string{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"},
|
||||||
Optional: false,
|
Optional: false,
|
||||||
},
|
},
|
||||||
|
@ -181,7 +181,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
config.MaxIdleConnsPerHost = 666
|
config.MaxIdleConnsPerHost = 666
|
||||||
config.IdleTimeout = flaeg.Duration(666 * time.Second)
|
config.IdleTimeout = flaeg.Duration(666 * time.Second)
|
||||||
config.InsecureSkipVerify = true
|
config.InsecureSkipVerify = true
|
||||||
config.RootCAs = traefikTls.RootCAs{"RootCAs 1", "RootCAs 2", "RootCAs 3"}
|
config.RootCAs = traefiktls.RootCAs{"RootCAs 1", "RootCAs 2", "RootCAs 3"}
|
||||||
config.Retry = &configuration.Retry{
|
config.Retry = &configuration.Retry{
|
||||||
Attempts: 666,
|
Attempts: 666,
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import (
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/server"
|
"github.com/containous/traefik/server"
|
||||||
"github.com/containous/traefik/server/uuid"
|
"github.com/containous/traefik/server/uuid"
|
||||||
traefikTls "github.com/containous/traefik/tls"
|
traefiktls "github.com/containous/traefik/tls"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/containous/traefik/version"
|
"github.com/containous/traefik/version"
|
||||||
"github.com/coreos/go-systemd/daemon"
|
"github.com/coreos/go-systemd/daemon"
|
||||||
|
@ -62,7 +62,7 @@ Complete documentation is available at https://traefik.io`,
|
||||||
// add custom parsers
|
// add custom parsers
|
||||||
f.AddParser(reflect.TypeOf(configuration.EntryPoints{}), &configuration.EntryPoints{})
|
f.AddParser(reflect.TypeOf(configuration.EntryPoints{}), &configuration.EntryPoints{})
|
||||||
f.AddParser(reflect.TypeOf(configuration.DefaultEntryPoints{}), &configuration.DefaultEntryPoints{})
|
f.AddParser(reflect.TypeOf(configuration.DefaultEntryPoints{}), &configuration.DefaultEntryPoints{})
|
||||||
f.AddParser(reflect.TypeOf(traefikTls.RootCAs{}), &traefikTls.RootCAs{})
|
f.AddParser(reflect.TypeOf(traefiktls.RootCAs{}), &traefiktls.RootCAs{})
|
||||||
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
|
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
|
||||||
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
||||||
f.AddParser(reflect.TypeOf(ecs.Clusters{}), &ecs.Clusters{})
|
f.AddParser(reflect.TypeOf(ecs.Clusters{}), &ecs.Clusters{})
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
"github.com/containous/traefik/integration/try"
|
"github.com/containous/traefik/integration/try"
|
||||||
traefikTls "github.com/containous/traefik/tls"
|
traefiktls "github.com/containous/traefik/tls"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/go-check/check"
|
"github.com/go-check/check"
|
||||||
checker "github.com/vdemeester/shakers"
|
checker "github.com/vdemeester/shakers"
|
||||||
|
@ -624,11 +624,11 @@ func modifyCertificateConfFileContent(c *check.C, certFileName, confFileName, en
|
||||||
// If certificate file is not provided, just truncate the configuration file
|
// If certificate file is not provided, just truncate the configuration file
|
||||||
if len(certFileName) > 0 {
|
if len(certFileName) > 0 {
|
||||||
tlsConf := types.Configuration{
|
tlsConf := types.Configuration{
|
||||||
TLS: []*traefikTls.Configuration{
|
TLS: []*traefiktls.Configuration{
|
||||||
{
|
{
|
||||||
Certificate: &traefikTls.Certificate{
|
Certificate: &traefiktls.Certificate{
|
||||||
CertFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
CertFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
||||||
KeyFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
KeyFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
||||||
},
|
},
|
||||||
EntryPoints: []string{entryPoint},
|
EntryPoints: []string{entryPoint},
|
||||||
},
|
},
|
||||||
|
|
|
@ -112,12 +112,12 @@ func (p *Provider) init() error {
|
||||||
|
|
||||||
p.account, err = p.Store.GetAccount()
|
p.account, err = p.Store.GetAccount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("unable to get ACME account : %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.certificates, err = p.Store.GetCertificates()
|
p.certificates, err = p.Store.GetCertificates()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("unable to get ACME account : %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.watchCertificate()
|
p.watchCertificate()
|
||||||
|
@ -215,30 +215,29 @@ func (p *Provider) resolveCertificate(domain types.Domain) (*acme.CertificateRes
|
||||||
}
|
}
|
||||||
domains = fun.Map(types.CanonicalDomain, domains).([]string)
|
domains = fun.Map(types.CanonicalDomain, domains).([]string)
|
||||||
|
|
||||||
log.Debugf("Looking for provided certificate to validate %s...", domains)
|
// Check provided certificates
|
||||||
cert := searchProvidedCertificateForDomains(domains, p.staticCerts)
|
uncheckedDomains := p.getUncheckedDomains(domains)
|
||||||
if cert != nil {
|
if len(uncheckedDomains) == 0 {
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if p.dynamicCerts != nil && p.dynamicCerts.Get() != nil && p.dynamicCerts.Get().(*traefikTLS.DomainsCertificates).Get() != nil {
|
|
||||||
cert = searchProvidedCertificateForDomains(domains, p.dynamicCerts.Get().(*traefikTLS.DomainsCertificates).Get().(map[string]*tls.Certificate))
|
|
||||||
}
|
|
||||||
if cert != nil {
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Loading ACME certificates %+v...", domains)
|
log.Debugf("Loading ACME certificates %+v...", uncheckedDomains)
|
||||||
client, err := p.getClient()
|
client, err := p.getClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot get ACME client %v", err)
|
return nil, fmt.Errorf("cannot get ACME client %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bundle := true
|
bundle := true
|
||||||
certificate, failures := client.ObtainCertificate(domains, bundle, nil, OSCPMustStaple)
|
certificate, failures := client.ObtainCertificate(uncheckedDomains, bundle, nil, OSCPMustStaple)
|
||||||
if len(failures) > 0 {
|
if len(failures) > 0 {
|
||||||
return nil, fmt.Errorf("cannot obtain certificates %+v", failures)
|
return nil, fmt.Errorf("cannot obtain certificates %+v", failures)
|
||||||
}
|
}
|
||||||
log.Debugf("Certificates obtained for domain %+v", domains)
|
log.Debugf("Certificates obtained for domain %+v", uncheckedDomains)
|
||||||
|
if len(uncheckedDomains) > 1 {
|
||||||
|
domain = types.Domain{Main: uncheckedDomains[0], SANs: uncheckedDomains[1:]}
|
||||||
|
} else {
|
||||||
|
domain = types.Domain{Main: uncheckedDomains[0]}
|
||||||
|
}
|
||||||
p.addCertificateForDomain(domain, certificate.Certificate, certificate.PrivateKey)
|
p.addCertificateForDomain(domain, certificate.Certificate, certificate.PrivateKey)
|
||||||
|
|
||||||
return &certificate, nil
|
return &certificate, nil
|
||||||
|
@ -286,7 +285,7 @@ func (p *Provider) getClient() (*acme.Client, error) {
|
||||||
account.Registration = reg
|
account.Registration = reg
|
||||||
err = client.AgreeToTOS()
|
err = client.AgreeToTOS()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("error sending ACME agreement to TOS: %+v: %v", account, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,24 +526,55 @@ func (p *Provider) AddRoutes(router *mux.Router) {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchProvidedCertificateForDomains(domains []string, certs map[string]*tls.Certificate) *tls.Certificate {
|
// Get provided certificate which check a domains list (Main and SANs)
|
||||||
// Use regex to test for provided certs that might have been added into TLSConfig
|
// from static and dynamic provided certificates
|
||||||
providedCertMatch := false
|
func (p *Provider) getUncheckedDomains(domains []string) []string {
|
||||||
for k := range certs {
|
log.Debugf("Looking for provided certificate(s) to validate %q...", domains)
|
||||||
selector := "^" + strings.Replace(k, "*.", "[^\\.]*\\.?", -1) + "$"
|
allCerts := make(map[string]*tls.Certificate)
|
||||||
|
|
||||||
|
// Get static certificates
|
||||||
|
for domains, certificate := range p.staticCerts {
|
||||||
|
allCerts[domains] = certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get dynamic certificates
|
||||||
|
if p.dynamicCerts != nil && p.dynamicCerts.Get() != nil {
|
||||||
|
for domains, certificate := range p.dynamicCerts.Get().(map[string]*tls.Certificate) {
|
||||||
|
allCerts[domains] = certificate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchUncheckedDomains(domains, allCerts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchUncheckedDomains(domains []string, certs map[string]*tls.Certificate) []string {
|
||||||
|
uncheckedDomains := []string{}
|
||||||
for _, domainToCheck := range domains {
|
for _, domainToCheck := range domains {
|
||||||
providedCertMatch, _ = regexp.MatchString(selector, domainToCheck)
|
domainCheck := false
|
||||||
if !providedCertMatch {
|
for certDomains := range certs {
|
||||||
|
domainCheck = false
|
||||||
|
for _, certDomain := range strings.Split(certDomains, ",") {
|
||||||
|
// Use regex to test for provided certs that might have been added into TLSConfig
|
||||||
|
selector := "^" + strings.Replace(certDomain, "*.", "[^\\.]*\\.?", -1) + "$"
|
||||||
|
domainCheck, _ = regexp.MatchString(selector, domainToCheck)
|
||||||
|
if domainCheck {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if providedCertMatch {
|
if domainCheck {
|
||||||
log.Debugf("Got provided certificate for domains %s", domains)
|
break
|
||||||
return certs[k]
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
if !domainCheck {
|
||||||
|
uncheckedDomains = append(uncheckedDomains, domainToCheck)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(uncheckedDomains) == 0 {
|
||||||
|
log.Debugf("No ACME certificate to generate for domains %q.", domains)
|
||||||
|
} else {
|
||||||
|
log.Debugf("Domains %q need ACME certificates generation for domains %q.", domains, strings.Join(uncheckedDomains, ","))
|
||||||
|
}
|
||||||
|
return uncheckedDomains
|
||||||
}
|
}
|
||||||
|
|
||||||
func getX509Certificate(certificate *Certificate) (*x509.Certificate, error) {
|
func getX509Certificate(certificate *Certificate) (*x509.Certificate, error) {
|
||||||
|
|
|
@ -38,7 +38,7 @@ import (
|
||||||
"github.com/containous/traefik/rules"
|
"github.com/containous/traefik/rules"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/server/cookie"
|
"github.com/containous/traefik/server/cookie"
|
||||||
traefikTls "github.com/containous/traefik/tls"
|
traefiktls "github.com/containous/traefik/tls"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/containous/traefik/whitelist"
|
"github.com/containous/traefik/whitelist"
|
||||||
"github.com/eapache/channels"
|
"github.com/eapache/channels"
|
||||||
|
@ -176,7 +176,7 @@ func createHTTPTransport(globalConfiguration configuration.GlobalConfiguration)
|
||||||
return transport
|
return transport
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRootCACertPool(rootCAs traefikTls.RootCAs) *x509.CertPool {
|
func createRootCACertPool(rootCAs traefiktls.RootCAs) *x509.CertPool {
|
||||||
roots := x509.NewCertPool()
|
roots := x509.NewCertPool()
|
||||||
|
|
||||||
for _, cert := range rootCAs {
|
for _, cert := range rootCAs {
|
||||||
|
@ -480,12 +480,12 @@ func (s *serverEntryPoint) SetOnDemandListener(listener func(string) (*tls.Certi
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadHTTPSConfiguration add/delete HTTPS certificate managed dynamically
|
// loadHTTPSConfiguration add/delete HTTPS certificate managed dynamically
|
||||||
func (s *Server) loadHTTPSConfiguration(configurations types.Configurations, defaultEntryPoints configuration.DefaultEntryPoints) (map[string]*traefikTls.DomainsCertificates, error) {
|
func (s *Server) loadHTTPSConfiguration(configurations types.Configurations, defaultEntryPoints configuration.DefaultEntryPoints) (map[string]map[string]*tls.Certificate, error) {
|
||||||
newEPCertificates := make(map[string]*traefikTls.DomainsCertificates)
|
newEPCertificates := make(map[string]map[string]*tls.Certificate)
|
||||||
// Get all certificates
|
// Get all certificates
|
||||||
for _, configuration := range configurations {
|
for _, configuration := range configurations {
|
||||||
if configuration.TLS != nil && len(configuration.TLS) > 0 {
|
if configuration.TLS != nil && len(configuration.TLS) > 0 {
|
||||||
if err := traefikTls.SortTLSPerEntryPoints(configuration.TLS, newEPCertificates, defaultEntryPoints); err != nil {
|
if err := traefiktls.SortTLSPerEntryPoints(configuration.TLS, newEPCertificates, defaultEntryPoints); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,7 +497,7 @@ func (s *Server) loadHTTPSConfiguration(configurations types.Configurations, def
|
||||||
func (s *serverEntryPoint) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
func (s *serverEntryPoint) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
domainToCheck := types.CanonicalDomain(clientHello.ServerName)
|
domainToCheck := types.CanonicalDomain(clientHello.ServerName)
|
||||||
if s.certs.Get() != nil {
|
if s.certs.Get() != nil {
|
||||||
for domains, cert := range *s.certs.Get().(*traefikTls.DomainsCertificates) {
|
for domains, cert := range s.certs.Get().(map[string]*tls.Certificate) {
|
||||||
for _, domain := range strings.Split(domains, ",") {
|
for _, domain := range strings.Split(domains, ",") {
|
||||||
selector := "^" + strings.Replace(domain, "*.", "[^\\.]*\\.?", -1) + "$"
|
selector := "^" + strings.Replace(domain, "*.", "[^\\.]*\\.?", -1) + "$"
|
||||||
domainCheck, _ := regexp.MatchString(selector, domainToCheck)
|
domainCheck, _ := regexp.MatchString(selector, domainToCheck)
|
||||||
|
@ -569,7 +569,7 @@ func (s *Server) startProvider() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func createClientTLSConfig(entryPointName string, tlsOption *traefikTls.TLS) (*tls.Config, error) {
|
func createClientTLSConfig(entryPointName string, tlsOption *traefiktls.TLS) (*tls.Config, error) {
|
||||||
if tlsOption == nil {
|
if tlsOption == nil {
|
||||||
return nil, errors.New("no TLS provided")
|
return nil, errors.New("no TLS provided")
|
||||||
}
|
}
|
||||||
|
@ -602,7 +602,7 @@ func createClientTLSConfig(entryPointName string, tlsOption *traefikTls.TLS) (*t
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates a TLS config that allows terminating HTTPS for multiple domains using SNI
|
// creates a TLS config that allows terminating HTTPS for multiple domains using SNI
|
||||||
func (s *Server) createTLSConfig(entryPointName string, tlsOption *traefikTls.TLS, router *middlewares.HandlerSwitcher) (*tls.Config, error) {
|
func (s *Server) createTLSConfig(entryPointName string, tlsOption *traefiktls.TLS, router *middlewares.HandlerSwitcher) (*tls.Config, error) {
|
||||||
if tlsOption == nil {
|
if tlsOption == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -611,9 +611,8 @@ func (s *Server) createTLSConfig(entryPointName string, tlsOption *traefikTls.TL
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
epDomainsCertificatesTmp := new(traefikTls.DomainsCertificates)
|
|
||||||
*epDomainsCertificatesTmp = make(map[string]*tls.Certificate)
|
s.serverEntryPoints[entryPointName].certs.Set(make(map[string]*tls.Certificate))
|
||||||
s.serverEntryPoints[entryPointName].certs.Set(epDomainsCertificatesTmp)
|
|
||||||
// ensure http2 enabled
|
// ensure http2 enabled
|
||||||
config.NextProtos = []string{"h2", "http/1.1"}
|
config.NextProtos = []string{"h2", "http/1.1"}
|
||||||
|
|
||||||
|
@ -680,7 +679,7 @@ func (s *Server) createTLSConfig(entryPointName string, tlsOption *traefikTls.TL
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the minimum TLS version if set in the config TOML
|
// Set the minimum TLS version if set in the config TOML
|
||||||
if minConst, exists := traefikTls.MinVersion[s.globalConfiguration.EntryPoints[entryPointName].TLS.MinVersion]; exists {
|
if minConst, exists := traefiktls.MinVersion[s.globalConfiguration.EntryPoints[entryPointName].TLS.MinVersion]; exists {
|
||||||
config.PreferServerCipherSuites = true
|
config.PreferServerCipherSuites = true
|
||||||
config.MinVersion = minConst
|
config.MinVersion = minConst
|
||||||
}
|
}
|
||||||
|
@ -689,7 +688,7 @@ func (s *Server) createTLSConfig(entryPointName string, tlsOption *traefikTls.TL
|
||||||
// if our list of CipherSuites is defined in the entrypoint config, we can re-initilize the suites list as empty
|
// if our list of CipherSuites is defined in the entrypoint config, we can re-initilize the suites list as empty
|
||||||
config.CipherSuites = make([]uint16, 0)
|
config.CipherSuites = make([]uint16, 0)
|
||||||
for _, cipher := range s.globalConfiguration.EntryPoints[entryPointName].TLS.CipherSuites {
|
for _, cipher := range s.globalConfiguration.EntryPoints[entryPointName].TLS.CipherSuites {
|
||||||
if cipherConst, exists := traefikTls.CipherSuites[cipher]; exists {
|
if cipherConst, exists := traefiktls.CipherSuites[cipher]; exists {
|
||||||
config.CipherSuites = append(config.CipherSuites, cipherConst)
|
config.CipherSuites = append(config.CipherSuites, cipherConst)
|
||||||
} else {
|
} else {
|
||||||
// CipherSuite listed in the toml does not exist in our listed
|
// CipherSuite listed in the toml does not exist in our listed
|
||||||
|
@ -865,7 +864,7 @@ func (s *Server) buildEntryPoints(globalConfiguration configuration.GlobalConfig
|
||||||
|
|
||||||
// getRoundTripper will either use server.defaultForwardingRoundTripper or create a new one
|
// getRoundTripper will either use server.defaultForwardingRoundTripper or create a new one
|
||||||
// given a custom TLS configuration is passed and the passTLSCert option is set to true.
|
// given a custom TLS configuration is passed and the passTLSCert option is set to true.
|
||||||
func (s *Server) getRoundTripper(entryPointName string, globalConfiguration configuration.GlobalConfiguration, passTLSCert bool, tls *traefikTls.TLS) (http.RoundTripper, error) {
|
func (s *Server) getRoundTripper(entryPointName string, globalConfiguration configuration.GlobalConfiguration, passTLSCert bool, tls *traefiktls.TLS) (http.RoundTripper, error) {
|
||||||
if passTLSCert {
|
if passTLSCert {
|
||||||
tlsConfig, err := createClientTLSConfig(entryPointName, tls)
|
tlsConfig, err := createClientTLSConfig(entryPointName, tls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -89,7 +89,7 @@ func (f FileOrContent) Read() ([]byte, error) {
|
||||||
// CreateTLSConfig creates a TLS config from Certificate structures
|
// CreateTLSConfig creates a TLS config from Certificate structures
|
||||||
func (c *Certificates) CreateTLSConfig(entryPointName string) (*tls.Config, error) {
|
func (c *Certificates) CreateTLSConfig(entryPointName string) (*tls.Config, error) {
|
||||||
config := &tls.Config{}
|
config := &tls.Config{}
|
||||||
domainsCertificates := make(map[string]*DomainsCertificates)
|
domainsCertificates := make(map[string]map[string]*tls.Certificate)
|
||||||
if c.isEmpty() {
|
if c.isEmpty() {
|
||||||
config.Certificates = []tls.Certificate{}
|
config.Certificates = []tls.Certificate{}
|
||||||
cert, err := generate.DefaultCertificate()
|
cert, err := generate.DefaultCertificate()
|
||||||
|
@ -105,7 +105,7 @@ func (c *Certificates) CreateTLSConfig(entryPointName string) (*tls.Config, erro
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, certDom := range domainsCertificates {
|
for _, certDom := range domainsCertificates {
|
||||||
for _, cert := range certDom.Get().(map[string]*tls.Certificate) {
|
for _, cert := range map[string]*tls.Certificate(certDom) {
|
||||||
config.Certificates = append(config.Certificates, *cert)
|
config.Certificates = append(config.Certificates, *cert)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ func (c *Certificates) isEmpty() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendCertificates appends a Certificate to a certificates map sorted by entrypoints
|
// AppendCertificates appends a Certificate to a certificates map sorted by entrypoints
|
||||||
func (c *Certificate) AppendCertificates(certs map[string]*DomainsCertificates, ep string) error {
|
func (c *Certificate) AppendCertificates(certs map[string]map[string]*tls.Certificate, ep string) error {
|
||||||
|
|
||||||
certContent, err := c.CertFile.Read()
|
certContent, err := c.CertFile.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -161,10 +161,9 @@ func (c *Certificate) AppendCertificates(certs map[string]*DomainsCertificates,
|
||||||
|
|
||||||
certExists := false
|
certExists := false
|
||||||
if certs[ep] == nil {
|
if certs[ep] == nil {
|
||||||
certs[ep] = new(DomainsCertificates)
|
certs[ep] = make(map[string]*tls.Certificate)
|
||||||
*certs[ep] = make(map[string]*tls.Certificate)
|
|
||||||
} else {
|
} else {
|
||||||
for domains := range *certs[ep] {
|
for domains := range certs[ep] {
|
||||||
if domains == certKey {
|
if domains == certKey {
|
||||||
certExists = true
|
certExists = true
|
||||||
break
|
break
|
||||||
|
@ -175,7 +174,7 @@ func (c *Certificate) AppendCertificates(certs map[string]*DomainsCertificates,
|
||||||
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)
|
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 {
|
} else {
|
||||||
log.Debugf("Add certificate for domains %s", certKey)
|
log.Debugf("Add certificate for domains %s", certKey)
|
||||||
err = certs[ep].add(certKey, &tlsCert)
|
certs[ep][certKey] = &tlsCert
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
20
tls/tls.go
20
tls/tls.go
|
@ -32,28 +32,12 @@ type TLS struct {
|
||||||
// RootCAs hold the CA we want to have in root
|
// RootCAs hold the CA we want to have in root
|
||||||
type RootCAs []FileOrContent
|
type RootCAs []FileOrContent
|
||||||
|
|
||||||
// DomainsCertificates allows mapping TLS certificates to a list of domains
|
|
||||||
type DomainsCertificates map[string]*tls.Certificate
|
|
||||||
|
|
||||||
// Configuration allows mapping a TLS certificate to a list of entrypoints
|
// Configuration allows mapping a TLS certificate to a list of entrypoints
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
EntryPoints []string
|
EntryPoints []string
|
||||||
Certificate *Certificate
|
Certificate *Certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set is the method to set the flag value, part of the flag.Value interface.
|
|
||||||
// Set's argument is a string to be parsed to set the flag.
|
|
||||||
// It's a comma-separated list, so we split it.
|
|
||||||
func (dc *DomainsCertificates) add(domain string, cert *tls.Certificate) error {
|
|
||||||
dc.Get().(map[string]*tls.Certificate)[domain] = cert
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get method allow getting the map stored into the DomainsCertificates
|
|
||||||
func (dc *DomainsCertificates) Get() interface{} {
|
|
||||||
return map[string]*tls.Certificate(*dc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String is the method to format the flag's value, part of the flag.Value interface.
|
// String is the method to format the flag's value, part of the flag.Value interface.
|
||||||
// The String method's output will be used in diagnostics.
|
// The String method's output will be used in diagnostics.
|
||||||
func (r *RootCAs) String() string {
|
func (r *RootCAs) String() string {
|
||||||
|
@ -94,9 +78,9 @@ func (r *RootCAs) Type() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SortTLSPerEntryPoints converts TLS configuration sorted by Certificates into TLS configuration sorted by EntryPoints
|
// SortTLSPerEntryPoints converts TLS configuration sorted by Certificates into TLS configuration sorted by EntryPoints
|
||||||
func SortTLSPerEntryPoints(configurations []*Configuration, epConfiguration map[string]*DomainsCertificates, defaultEntryPoints []string) error {
|
func SortTLSPerEntryPoints(configurations []*Configuration, epConfiguration map[string]map[string]*tls.Certificate, defaultEntryPoints []string) error {
|
||||||
if epConfiguration == nil {
|
if epConfiguration == nil {
|
||||||
epConfiguration = make(map[string]*DomainsCertificates)
|
epConfiguration = make(map[string]map[string]*tls.Certificate)
|
||||||
}
|
}
|
||||||
for _, conf := range configurations {
|
for _, conf := range configurations {
|
||||||
if conf.EntryPoints == nil || len(conf.EntryPoints) == 0 {
|
if conf.EntryPoints == nil || len(conf.EntryPoints) == 0 {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"github.com/containous/flaeg"
|
"github.com/containous/flaeg"
|
||||||
"github.com/containous/mux"
|
"github.com/containous/mux"
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
traefikTls "github.com/containous/traefik/tls"
|
traefiktls "github.com/containous/traefik/tls"
|
||||||
"github.com/ryanuber/go-glob"
|
"github.com/ryanuber/go-glob"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ type Configurations map[string]*Configuration
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
Backends map[string]*Backend `json:"backends,omitempty"`
|
Backends map[string]*Backend `json:"backends,omitempty"`
|
||||||
Frontends map[string]*Frontend `json:"frontends,omitempty"`
|
Frontends map[string]*Frontend `json:"frontends,omitempty"`
|
||||||
TLS []*traefikTls.Configuration `json:"tls,omitempty"`
|
TLS []*traefiktls.Configuration `json:"tls,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigMessage hold configuration information exchanged between parts of traefik.
|
// ConfigMessage hold configuration information exchanged between parts of traefik.
|
||||||
|
|
Loading…
Add table
Reference in a new issue