caddytls: Regularly reload static certificates

This commit is contained in:
Pascal 2025-04-07 16:37:09 +02:00
parent b06a9496d1
commit b36a7ab9a1

View File

@ -122,13 +122,15 @@ type TLS struct {
DNSRaw json.RawMessage `json:"dns,omitempty" caddy:"namespace=dns.providers inline_key=name"`
dns any // technically, it should be any/all of the libdns interfaces (RecordSetter, RecordAppender, etc.)
certificateLoaders []CertificateLoader
automateNames []string
ctx caddy.Context
storageCleanTicker *time.Ticker
storageCleanStop chan struct{}
logger *zap.Logger
events *caddyevents.App
magic *certmagic.Config
certificateLoaders []CertificateLoader
unmanagedCertsTicker *time.Ticker
automateNames []string
ctx caddy.Context
storageCleanTicker *time.Ticker
storageCleanStop chan struct{}
logger *zap.Logger
events *caddyevents.App
serverNames map[string]struct{}
serverNamesMu *sync.Mutex
@ -238,7 +240,7 @@ func (t *TLS) Provision(ctx caddy.Context) error {
// certificates have been manually loaded, and also so that
// commands like validate can be a better test
certCacheMu.RLock()
magic := certmagic.New(certCache, certmagic.Config{
t.magic = certmagic.New(certCache, certmagic.Config{
Storage: ctx.Storage(),
Logger: t.logger,
OnEvent: t.onEvent,
@ -248,18 +250,14 @@ func (t *TLS) Provision(ctx caddy.Context) error {
DisableStorageCheck: t.DisableStorageCheck,
})
certCacheMu.RUnlock()
for _, loader := range t.certificateLoaders {
certs, err := loader.LoadCertificates()
if err != nil {
return fmt.Errorf("loading certificates: %v", err)
}
for _, cert := range certs {
hash, err := magic.CacheUnmanagedTLSCertificate(ctx, cert.Certificate, cert.Tags)
if err != nil {
return fmt.Errorf("caching unmanaged certificate: %v", err)
}
t.loaded[hash] = ""
}
unmanaged, err := t.loadUnmanagedCertificates(ctx)
if err != nil {
return err
}
if unmanaged > 0 {
t.regularlyReloadUnmanagedCertificates()
}
// on-demand permission module
@ -720,6 +718,61 @@ func (t *TLS) HasCertificateForSubject(subject string) bool {
return false
}
func (t *TLS) loadUnmanagedCertificates(ctx caddy.Context) (int, error) {
cached := 0
for _, loader := range t.certificateLoaders {
certs, err := loader.LoadCertificates()
if err != nil {
return 0, fmt.Errorf("loading certificates: %v", err)
}
for _, cert := range certs {
hash, err := t.magic.CacheUnmanagedTLSCertificate(ctx, cert.Certificate, cert.Tags)
if err != nil {
return 0, fmt.Errorf("caching unmanaged certificate: %v", err)
}
t.loaded[hash] = ""
}
}
return cached, nil
}
func (t *TLS) regularlyReloadUnmanagedCertificates() {
t.unmanagedCertsTicker = time.NewTicker(2 * time.Hour)
go func() {
defer func() {
if err := recover(); err != nil {
log.Printf("[PANIC] unmanaged certificates reloader: %v\n%s", err, debug.Stack())
}
}()
t.reloadUnmanagedCertificates()
for {
select {
case <-t.storageCleanStop:
return
case <-t.storageCleanTicker.C:
t.cleanStorageUnits()
}
}
}()
}
func (t *TLS) reloadUnmanagedCertificates() error {
for _, loader := range t.certificateLoaders {
certs, err := loader.LoadCertificates()
if err != nil {
return fmt.Errorf("loading certificates: %v", err)
}
for _, cert := range certs {
hash, err := t.magic.CacheUnmanagedTLSCertificate(t.ctx, cert.Certificate, cert.Tags)
if err != nil {
return fmt.Errorf("caching unmanaged certificate: %v", err)
}
t.loaded[hash] = ""
}
}
return nil
}
// keepStorageClean starts a goroutine that immediately cleans up all
// known storage units if it was not recently done, and then runs the
// operation at every tick from t.storageCleanTicker.