Skip to content

Commit e1aa980

Browse files
committed
caddytls: Regularly reload static certificates
1 parent 5a6b2f8 commit e1aa980

File tree

1 file changed

+73
-20
lines changed

1 file changed

+73
-20
lines changed

modules/caddytls/tls.go

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,15 @@ 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-
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
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
132134

133135
serverNames map[string]struct{}
134136
serverNamesMu *sync.Mutex
@@ -238,7 +240,7 @@ func (t *TLS) Provision(ctx caddy.Context) error {
238240
// certificates have been manually loaded, and also so that
239241
// commands like validate can be a better test
240242
certCacheMu.RLock()
241-
magic := certmagic.New(certCache, certmagic.Config{
243+
t.magic = certmagic.New(certCache, certmagic.Config{
242244
Storage: ctx.Storage(),
243245
Logger: t.logger,
244246
OnEvent: t.onEvent,
@@ -248,18 +250,14 @@ func (t *TLS) Provision(ctx caddy.Context) error {
248250
DisableStorageCheck: t.DisableStorageCheck,
249251
})
250252
certCacheMu.RUnlock()
251-
for _, loader := range t.certificateLoaders {
252-
certs, err := loader.LoadCertificates()
253-
if err != nil {
254-
return fmt.Errorf("loading certificates: %v", err)
255-
}
256-
for _, cert := range certs {
257-
hash, err := magic.CacheUnmanagedTLSCertificate(ctx, cert.Certificate, cert.Tags)
258-
if err != nil {
259-
return fmt.Errorf("caching unmanaged certificate: %v", err)
260-
}
261-
t.loaded[hash] = ""
262-
}
253+
254+
unmanaged, err := t.loadUnmanagedCertificates(ctx)
255+
if err != nil {
256+
return err
257+
}
258+
259+
if unmanaged > 0 {
260+
t.regularlyReloadUnmanagedCertificates()
263261
}
264262

265263
// on-demand permission module
@@ -720,6 +718,61 @@ func (t *TLS) HasCertificateForSubject(subject string) bool {
720718
return false
721719
}
722720

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()
762+
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] = ""
771+
}
772+
}
773+
return nil
774+
}
775+
723776
// keepStorageClean starts a goroutine that immediately cleans up all
724777
// known storage units if it was not recently done, and then runs the
725778
// operation at every tick from t.storageCleanTicker.

0 commit comments

Comments
 (0)