Skip to content

Commit a874bb3

Browse files
committed
caddytls: Regularly reload static certificates
1 parent b36a7ab commit a874bb3

File tree

2 files changed

+31
-75
lines changed

2 files changed

+31
-75
lines changed

modules/caddytls/storageloader.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,16 @@ func (sl *StorageLoader) Provision(ctx caddy.Context) error {
7272
return nil
7373
}
7474

75-
// LoadCertificates returns the certificates to be loaded by sl.
76-
func (sl StorageLoader) LoadCertificates() ([]Certificate, error) {
75+
func (sl StorageLoader) Initialize(updateCertificates func(add []Certificate, remove []string) error) error {
7776
certs := make([]Certificate, 0, len(sl.Pairs))
7877
for _, pair := range sl.Pairs {
7978
certData, err := sl.storage.Load(sl.ctx, pair.Certificate)
8079
if err != nil {
81-
return nil, err
80+
return err
8281
}
8382
keyData, err := sl.storage.Load(sl.ctx, pair.Key)
8483
if err != nil {
85-
return nil, err
84+
return err
8685
}
8786

8887
var cert tls.Certificate
@@ -94,21 +93,21 @@ func (sl StorageLoader) LoadCertificates() ([]Certificate, error) {
9493
// if the start of the key file looks like an encrypted private key,
9594
// reject it with a helpful error message
9695
if strings.Contains(string(keyData[:40]), "ENCRYPTED") {
97-
return nil, fmt.Errorf("encrypted private keys are not supported; please decrypt the key first")
96+
return fmt.Errorf("encrypted private keys are not supported; please decrypt the key first")
9897
}
9998

10099
cert, err = tls.X509KeyPair(certData, keyData)
101100

102101
default:
103-
return nil, fmt.Errorf("unrecognized certificate/key encoding format: %s", pair.Format)
102+
return fmt.Errorf("unrecognized certificate/key encoding format: %s", pair.Format)
104103
}
105104
if err != nil {
106-
return nil, err
105+
return err
107106
}
108107

109108
certs = append(certs, Certificate{Certificate: cert, Tags: pair.Tags})
110109
}
111-
return certs, nil
110+
return updateCertificates(certs, []string{})
112111
}
113112

114113
// Interface guard

modules/caddytls/tls.go

Lines changed: 24 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,13 @@ type TLS struct {
122122
DNSRaw json.RawMessage `json:"dns,omitempty" caddy:"namespace=dns.providers inline_key=name"`
123123
dns any // technically, it should be any/all of the libdns interfaces (RecordSetter, RecordAppender, etc.)
124124

125-
magic *certmagic.Config
126-
certificateLoaders []CertificateLoader
127-
unmanagedCertsTicker *time.Ticker
128-
automateNames []string
129-
ctx caddy.Context
130-
storageCleanTicker *time.Ticker
131-
storageCleanStop chan struct{}
132-
logger *zap.Logger
133-
events *caddyevents.App
125+
certificateLoaders []CertificateLoader
126+
automateNames []string
127+
ctx caddy.Context
128+
storageCleanTicker *time.Ticker
129+
storageCleanStop chan struct{}
130+
logger *zap.Logger
131+
events *caddyevents.App
134132

135133
serverNames map[string]struct{}
136134
serverNamesMu *sync.Mutex
@@ -240,7 +238,7 @@ func (t *TLS) Provision(ctx caddy.Context) error {
240238
// certificates have been manually loaded, and also so that
241239
// commands like validate can be a better test
242240
certCacheMu.RLock()
243-
t.magic = certmagic.New(certCache, certmagic.Config{
241+
magic := certmagic.New(certCache, certmagic.Config{
244242
Storage: ctx.Storage(),
245243
Logger: t.logger,
246244
OnEvent: t.onEvent,
@@ -251,13 +249,13 @@ func (t *TLS) Provision(ctx caddy.Context) error {
251249
})
252250
certCacheMu.RUnlock()
253251

254-
unmanaged, err := t.loadUnmanagedCertificates(ctx)
255-
if err != nil {
256-
return err
257-
}
258-
259-
if unmanaged > 0 {
260-
t.regularlyReloadUnmanagedCertificates()
252+
for _, loader := range t.certificateLoaders {
253+
err := loader.Initialize(func(add []Certificate, remove []string) error {
254+
return t.updateCertificates(ctx, magic, add, remove)
255+
})
256+
if err != nil {
257+
return fmt.Errorf("loading certificates: %v", err)
258+
}
261259
}
262260

263261
// on-demand permission module
@@ -718,58 +716,17 @@ func (t *TLS) HasCertificateForSubject(subject string) bool {
718716
return false
719717
}
720718

721-
func (t *TLS) loadUnmanagedCertificates(ctx caddy.Context) (int, error) {
722-
cached := 0
723-
for _, loader := range t.certificateLoaders {
724-
certs, err := loader.LoadCertificates()
725-
if err != nil {
726-
return 0, fmt.Errorf("loading certificates: %v", err)
727-
}
728-
for _, cert := range certs {
729-
hash, err := t.magic.CacheUnmanagedTLSCertificate(ctx, cert.Certificate, cert.Tags)
730-
if err != nil {
731-
return 0, fmt.Errorf("caching unmanaged certificate: %v", err)
732-
}
733-
t.loaded[hash] = ""
734-
}
735-
}
736-
return cached, nil
737-
}
738-
739-
func (t *TLS) regularlyReloadUnmanagedCertificates() {
740-
t.unmanagedCertsTicker = time.NewTicker(2 * time.Hour)
741-
go func() {
742-
defer func() {
743-
if err := recover(); err != nil {
744-
log.Printf("[PANIC] unmanaged certificates reloader: %v\n%s", err, debug.Stack())
745-
}
746-
}()
747-
t.reloadUnmanagedCertificates()
748-
for {
749-
select {
750-
case <-t.storageCleanStop:
751-
return
752-
case <-t.storageCleanTicker.C:
753-
t.cleanStorageUnits()
754-
}
755-
}
756-
}()
757-
}
758-
759-
func (t *TLS) reloadUnmanagedCertificates() error {
760-
for _, loader := range t.certificateLoaders {
761-
certs, err := loader.LoadCertificates()
719+
func (t *TLS) updateCertificates(ctx caddy.Context, magic *certmagic.Config, add []Certificate, remove []string) error {
720+
for _, cert := range add {
721+
hash, err := magic.CacheUnmanagedTLSCertificate(ctx, cert.Certificate, cert.Tags)
762722
if err != nil {
763-
return fmt.Errorf("loading certificates: %v", err)
764-
}
765-
for _, cert := range certs {
766-
hash, err := t.magic.CacheUnmanagedTLSCertificate(t.ctx, cert.Certificate, cert.Tags)
767-
if err != nil {
768-
return fmt.Errorf("caching unmanaged certificate: %v", err)
769-
}
770-
t.loaded[hash] = ""
723+
return fmt.Errorf("caching unmanaged certificate: %v", err)
771724
}
725+
t.loaded[hash] = ""
772726
}
727+
certCacheMu.Lock()
728+
certCache.Remove(remove)
729+
certCacheMu.Unlock()
773730
return nil
774731
}
775732

@@ -878,7 +835,7 @@ func (t *TLS) onEvent(ctx context.Context, eventName string, data map[string]any
878835
// CertificateLoader is a type that can load certificates.
879836
// Certificates can optionally be associated with tags.
880837
type CertificateLoader interface {
881-
LoadCertificates() ([]Certificate, error)
838+
Initialize(updateCertificates func(add []Certificate, remove []string) error) error
882839
}
883840

884841
// Certificate is a TLS certificate, optionally

0 commit comments

Comments
 (0)