aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatthew Holt <[email protected]>2024-04-26 18:51:56 -0600
committerMatthew Holt <[email protected]>2024-04-26 18:51:56 -0600
commitb4a4ddd3231fec193a3331c7ff936cc124c6c96c (patch)
tree179dc31c3afaa3d2371d519aa4077d3dbf222825
parentf8cafb901bbcd2c11ebff6c93804c675941d4cc4 (diff)
downloadcaddy-b4a4ddd3231fec193a3331c7ff936cc124c6c96c.tar.gz
caddy-b4a4ddd3231fec193a3331c7ff936cc124c6c96c.zip
Actually make it worktls-cert-cache-internal-reload
-rw-r--r--modules/caddytls/tls.go46
1 files changed, 30 insertions, 16 deletions
diff --git a/modules/caddytls/tls.go b/modules/caddytls/tls.go
index 095571ae6..14965533e 100644
--- a/modules/caddytls/tls.go
+++ b/modules/caddytls/tls.go
@@ -22,7 +22,6 @@ import (
"log"
"net/http"
"runtime/debug"
- "strings"
"sync"
"time"
@@ -92,7 +91,8 @@ type TLS struct {
// set of subjects with managed certificates,
// and hashes of manually-loaded certificates
- managing, loaded map[string]struct{}
+ // (managing's value is an optional issuer key, for distinction)
+ managing, loaded map[string]string
}
// CaddyModule returns the Caddy module information.
@@ -113,7 +113,7 @@ func (t *TLS) Provision(ctx caddy.Context) error {
t.ctx = ctx
t.logger = ctx.Logger()
repl := caddy.NewReplacer()
- t.managing, t.loaded = make(map[string]struct{}), make(map[string]struct{})
+ t.managing, t.loaded = make(map[string]string), make(map[string]string)
// set up a new certificate cache; this (re)loads all certificates
cacheOpts := certmagic.CacheOptions{
@@ -267,7 +267,7 @@ func (t *TLS) Provision(ctx caddy.Context) error {
if err != nil {
return fmt.Errorf("caching unmanaged certificate: %v", err)
}
- t.loaded[hash] = struct{}{}
+ t.loaded[hash] = ""
}
}
@@ -361,14 +361,24 @@ func (t *TLS) Cleanup() error {
// new app instance (which just started), and remove them from the cache
var noLongerManaged []certmagic.SubjectIssuer
var reManage, noLongerLoaded []string
- for subj := range t.managing {
- if _, ok := nextTLSApp.managing[subj]; !ok {
- name, issuerKey, _ := strings.Cut(subj, "~")
- noLongerManaged = append(noLongerManaged, certmagic.SubjectIssuer{Subject: name, IssuerKey: issuerKey})
- // if the new TLS app is managing a cert for the same subject we are evicting,
- // make sure it obtains or loads the cert using that config afterwards
- if _, ok := nextTLSApp.managing[name]; ok {
- reManage = append(reManage, name)
+ for subj, currentIssuerKey := range t.managing {
+ // It's a bit nuanced: managed certs can sometimes be different enough that we have to
+ // swap them out for a different one, even if they are for the same subject/domain.
+ // We consider "private" certs (internal CA/locally-trusted/etc) to be significantly
+ // distinct from "public" certs (production CAs/globally-trusted/etc) because of the
+ // implications when it comes to actual deployments: switching between an internal CA
+ // and a production CA, for example, is quite significant. Switching from one public CA
+ // to another, however, is not, and for our purposes we consider those to be the same.
+ // Anyway, if the next TLS app does not manage a cert for this name at all, definitely
+ // remove it from the cache. But if it does, and it's not the same kind of issuer/CA
+ // as we have, also remove it, so that it can swap it out for the right one.
+ if nextIssuerKey, ok := nextTLSApp.managing[subj]; !ok || nextIssuerKey != currentIssuerKey {
+ // next app is not managing a cert for this domain at all or is using a different issuer, so remove it
+ noLongerManaged = append(noLongerManaged, certmagic.SubjectIssuer{Subject: subj, IssuerKey: currentIssuerKey})
+
+ // then, if the next app is managing a cert for this name, but with a different issuer, re-manage it
+ if ok && nextIssuerKey != currentIssuerKey {
+ reManage = append(reManage, subj)
}
}
}
@@ -378,6 +388,7 @@ func (t *TLS) Cleanup() error {
}
}
+ // remove the certs
certCacheMu.RLock()
certCache.RemoveManaged(noLongerManaged)
certCache.Remove(noLongerLoaded)
@@ -427,13 +438,16 @@ func (t *TLS) Manage(names []string) error {
// a special case: if you have an initial config that manages example.com
// using internal CA, then after testing it you switch to a production CA,
// you wouldn't want to keep using the same self-signed cert, obviously;
- // so we differentiate these in the list
+ // so we differentiate these by associating the subject with its issuer key;
+ // we do this because CertMagic has no notion of "InternalIssuer" like we
+ // do, so we have to do this logic ourselves
+ var issuerKey string
if len(ap.Issuers) == 1 {
- if _, ok := ap.Issuers[0].(*InternalIssuer); ok {
- name += "~" + ap.Issuers[0].IssuerKey()
+ if intIss, ok := ap.Issuers[0].(*InternalIssuer); ok && intIss != nil {
+ issuerKey = intIss.IssuerKey()
}
}
- t.managing[name] = struct{}{}
+ t.managing[name] = issuerKey
}
}