1
0
Fork 0

Add a new protocol

Co-authored-by: Gérald Croës <gerald@containo.us>
This commit is contained in:
Julien Salleyron 2019-03-14 09:30:04 +01:00 committed by Traefiker Bot
parent 0ca2149408
commit 4a68d29ce2
231 changed files with 6895 additions and 4395 deletions

View file

@ -47,7 +47,6 @@ type Configuration struct {
EntryPoint string `description:"EntryPoint to use."`
KeyType string `description:"KeyType used for generating certificate private key. Allow value 'EC256', 'EC384', 'RSA2048', 'RSA4096', 'RSA8192'. Default to 'RSA4096'"`
OnHostRule bool `description:"Enable certificate generation on frontends Host rules."`
OnDemand bool `description:"Enable on demand certificate generation. This will request a certificate from Let's Encrypt during the first TLS handshake for a hostname that does not yet have a certificate."` // Deprecated
DNSChallenge *DNSChallenge `description:"Activate DNS-01 Challenge"`
HTTPChallenge *HTTPChallenge `description:"Activate HTTP-01 Challenge"`
TLSChallenge *TLSChallenge `description:"Activate TLS-ALPN-01 Challenge"`
@ -89,7 +88,7 @@ type Provider struct {
client *lego.Client
certsChan chan *Certificate
configurationChan chan<- config.Message
certificateStore *traefiktls.CertificateStore
tlsManager *traefiktls.Manager
clientMutex sync.Mutex
configFromListenerChan chan config.Configuration
pool *safe.Pool
@ -97,16 +96,16 @@ type Provider struct {
resolvingDomainsMutex sync.RWMutex
}
// SetTLSManager sets the tls manager to use
func (p *Provider) SetTLSManager(tlsManager *traefiktls.Manager) {
p.tlsManager = tlsManager
}
// SetConfigListenerChan initializes the configFromListenerChan
func (p *Provider) SetConfigListenerChan(configFromListenerChan chan config.Configuration) {
p.configFromListenerChan = configFromListenerChan
}
// SetCertificateStore allow to initialize certificate store
func (p *Provider) SetCertificateStore(certificateStore *traefiktls.CertificateStore) {
p.certificateStore = certificateStore
}
// ListenConfiguration sets a new Configuration into the configFromListenerChan
func (p *Provider) ListenConfiguration(config config.Configuration) {
p.configFromListenerChan <- config
@ -128,6 +127,7 @@ func (p *Provider) ListenRequest(domain string) (*tls.Certificate, error) {
// Init for compatibility reason the BaseProvider implements an empty Init
func (p *Provider) Init() error {
ctx := log.With(context.Background(), log.Str(log.ProviderName, "acme"))
logger := log.FromContext(ctx)
@ -137,9 +137,10 @@ func (p *Provider) Init() error {
legolog.Logger = fmtlog.New(ioutil.Discard, "", 0)
}
if p.Store == nil {
return errors.New("no store found for the ACME provider")
if len(p.Configuration.Storage) == 0 {
return errors.New("unable to initialize ACME provider with no storage location for the certificates")
}
p.Store = NewLocalStore(p.Configuration.Storage)
var err error
p.account, err = p.Store.GetAccount()
@ -352,40 +353,56 @@ func (p *Provider) initAccount(ctx context.Context) (*Account, error) {
return p.account, nil
}
func (p *Provider) resolveDomains(ctx context.Context, domains []string) {
if len(domains) == 0 {
log.FromContext(ctx).Debug("No domain parsed in provider ACME")
return
}
log.FromContext(ctx).Debugf("Try to challenge certificate for domain %v founded in HostSNI rule", domains)
var domain types.Domain
if len(domains) > 0 {
domain = types.Domain{Main: domains[0]}
if len(domains) > 1 {
domain.SANs = domains[1:]
}
safe.Go(func() {
if _, err := p.resolveCertificate(ctx, domain, false); err != nil {
log.FromContext(ctx).Errorf("Unable to obtain ACME certificate for domains %q: %v", strings.Join(domains, ","), err)
}
})
}
}
func (p *Provider) watchNewDomains(ctx context.Context) {
p.pool.Go(func(stop chan bool) {
for {
select {
case config := <-p.configFromListenerChan:
for routerName, route := range config.Routers {
logger := log.FromContext(ctx).WithField(log.RouterName, routerName)
if config.TCP != nil {
for routerName, route := range config.TCP.Routers {
ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule))
domains, err := rules.ParseHostSNI(route.Rule)
if err != nil {
log.FromContext(ctxRouter).Errorf("Error parsing domains in provider ACME: %v", err)
continue
}
p.resolveDomains(ctxRouter, domains)
}
}
for routerName, route := range config.HTTP.Routers {
ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule))
domains, err := rules.ParseDomains(route.Rule)
if err != nil {
logger.Errorf("Error parsing domains in provider ACME: %v", err)
log.FromContext(ctxRouter).Errorf("Error parsing domains in provider ACME: %v", err)
continue
}
if len(domains) == 0 {
logger.Debugf("No domain parsed in rule %q in provider ACME", route.Rule)
continue
}
logger.Debugf("Try to challenge certificate for domain %v founded in Host rule", domains)
var domain types.Domain
if len(domains) > 0 {
domain = types.Domain{Main: domains[0]}
if len(domains) > 1 {
domain.SANs = domains[1:]
}
safe.Go(func() {
if _, err := p.resolveCertificate(ctx, domain, false); err != nil {
logger.Errorf("Unable to obtain ACME certificate for domains %q detected thanks to rule %q : %v", strings.Join(domains, ","), route.Rule, err)
}
})
}
p.resolveDomains(ctxRouter, domains)
}
case <-stop:
return
@ -635,16 +652,18 @@ func (p *Provider) refreshCertificates() {
conf := config.Message{
ProviderName: "ACME",
Configuration: &config.Configuration{
Routers: map[string]*config.Router{},
Middlewares: map[string]*config.Middleware{},
Services: map[string]*config.Service{},
TLS: []*traefiktls.Configuration{},
HTTP: &config.HTTPConfiguration{
Routers: map[string]*config.Router{},
Middlewares: map[string]*config.Middleware{},
Services: map[string]*config.Service{},
},
TLS: []*traefiktls.Configuration{},
},
}
for _, cert := range p.certificates {
cert := &traefiktls.Certificate{CertFile: traefiktls.FileOrContent(cert.Certificate), KeyFile: traefiktls.FileOrContent(cert.Key)}
conf.Configuration.TLS = append(conf.Configuration.TLS, &traefiktls.Configuration{Certificate: cert, EntryPoints: []string{p.EntryPoint}})
conf.Configuration.TLS = append(conf.Configuration.TLS, &traefiktls.Configuration{Certificate: cert})
}
p.configurationChan <- conf
}
@ -695,7 +714,7 @@ func (p *Provider) getUncheckedDomains(ctx context.Context, domainsToCheck []str
log.FromContext(ctx).Debugf("Looking for provided certificate(s) to validate %q...", domainsToCheck)
allDomains := p.certificateStore.GetAllDomains()
allDomains := p.tlsManager.GetStore("default").GetAllDomains()
// Get ACME certificates
for _, cert := range p.certificates {