Skip to content

Commit b33c08c

Browse files
committed
autohttps: Ensure CertMagic config is recreated after autohttps runs
1 parent 6610e2f commit b33c08c

File tree

2 files changed

+77
-6
lines changed

2 files changed

+77
-6
lines changed

modules/caddyhttp/autohttps.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,27 @@ func (app *App) createAutomationPolicies(ctx caddy.Context, internalNames, tails
580580
}
581581
}
582582

583+
// Ensure automation policies' CertMagic configs are rebuilt when
584+
// ACME issuer templates may have been modified above (for example,
585+
// alternate ports filled in by the HTTP app). If a policy is already
586+
// provisioned, perform a lightweight rebuild of the CertMagic config
587+
// so issuers receive SetConfig with the updated templates; otherwise
588+
// run a normal Provision to initialize the policy.
589+
for i, ap := range app.tlsApp.Automation.Policies {
590+
// If the policy is already provisioned, rebuild only the CertMagic
591+
// config so issuers get SetConfig with updated templates. Otherwise
592+
// provision the policy normally (which may load modules).
593+
if ap.IsProvisioned() {
594+
if err := ap.RebuildCertMagic(app.tlsApp); err != nil {
595+
return fmt.Errorf("rebuilding certmagic config for automation policy %d: %v", i, err)
596+
}
597+
} else {
598+
if err := ap.Provision(app.tlsApp); err != nil {
599+
return fmt.Errorf("provisioning automation policy %d after auto-HTTPS defaults: %v", i, err)
600+
}
601+
}
602+
}
603+
583604
if basePolicy == nil {
584605
// no base policy found; we will make one
585606
basePolicy = new(caddytls.AutomationPolicy)

modules/caddytls/automation.go

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,22 +243,49 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
243243
}
244244
}
245245

246+
// build certmagic.Config and attach it to the policy
247+
storage := ap.storage
248+
if storage == nil {
249+
storage = tlsApp.ctx.Storage()
250+
}
251+
cfg, err := ap.makeCertMagicConfig(tlsApp, issuers, storage)
252+
if err != nil {
253+
return err
254+
}
255+
certCacheMu.RLock()
256+
ap.magic = certmagic.New(certCache, cfg)
257+
certCacheMu.RUnlock()
258+
259+
// give issuers a chance to see the config pointer
260+
for _, issuer := range ap.magic.Issuers {
261+
if annoying, ok := issuer.(ConfigSetter); ok {
262+
annoying.SetConfig(ap.magic)
263+
}
264+
}
265+
266+
return nil
267+
}
268+
269+
// makeCertMagicConfig constructs a certmagic.Config for this policy using the
270+
// provided issuers and storage. It encapsulates common logic shared between
271+
// Provision and RebuildCertMagic so we don't duplicate code.
272+
func (ap *AutomationPolicy) makeCertMagicConfig(tlsApp *TLS, issuers []certmagic.Issuer, storage certmagic.Storage) (certmagic.Config, error) {
273+
// key source
246274
keyType := ap.KeyType
247275
if keyType != "" {
248276
var err error
249277
keyType, err = caddy.NewReplacer().ReplaceOrErr(ap.KeyType, true, true)
250278
if err != nil {
251-
return fmt.Errorf("invalid key type %s: %s", ap.KeyType, err)
279+
return certmagic.Config{}, fmt.Errorf("invalid key type %s: %s", ap.KeyType, err)
252280
}
253281
if _, ok := supportedCertKeyTypes[keyType]; !ok {
254-
return fmt.Errorf("unrecognized key type: %s", keyType)
282+
return certmagic.Config{}, fmt.Errorf("unrecognized key type: %s", keyType)
255283
}
256284
}
257285
keySource := certmagic.StandardKeyGenerator{
258286
KeyType: supportedCertKeyTypes[keyType],
259287
}
260288

261-
storage := ap.storage
262289
if storage == nil {
263290
storage = tlsApp.ctx.Storage()
264291
}
@@ -277,7 +304,7 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
277304
if noProtections {
278305
if !ap.hadExplicitManagers {
279306
// no managers, no explicitly-configured permission module, this is a config error
280-
return fmt.Errorf("on-demand TLS cannot be enabled without a permission module to prevent abuse; please refer to documentation for details")
307+
return certmagic.Config{}, fmt.Errorf("on-demand TLS cannot be enabled without a permission module to prevent abuse; please refer to documentation for details")
281308
}
282309
// allow on-demand to be enabled but only for the purpose of the Managers; issuance won't be allowed from Issuers
283310
tlsApp.logger.Warn("on-demand TLS can only get certificates from the configured external manager(s) because no ask endpoint / permission module is specified")
@@ -334,7 +361,7 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
334361
}
335362
}
336363

337-
template := certmagic.Config{
364+
cfg := certmagic.Config{
338365
MustStaple: ap.MustStaple,
339366
RenewalWindowRatio: ap.RenewalWindowRatio,
340367
KeySource: keySource,
@@ -349,8 +376,31 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
349376
Issuers: issuers,
350377
Logger: tlsApp.logger,
351378
}
379+
380+
return cfg, nil
381+
}
382+
383+
// IsProvisioned reports whether the automation policy has been
384+
// provisioned. A provisioned policy has an initialized CertMagic
385+
// instance (i.e. ap.magic != nil).
386+
func (ap *AutomationPolicy) IsProvisioned() bool { return ap.magic != nil }
387+
388+
// RebuildCertMagic rebuilds the policy's CertMagic configuration from the
389+
// policy's already-populated fields (Issuers, Managers, storage, etc.) and
390+
// replaces the internal CertMagic instance. This is a lightweight
391+
// alternative to calling Provision because it does not re-provision
392+
// modules or re-run module Provision; instead, it constructs a new
393+
// certmagic.Config and calls SetConfig on issuers so they receive updated
394+
// templates (for example, alternate HTTP/TLS ports supplied by the HTTP
395+
// app). RebuildCertMagic should only be called when the policy's required
396+
// fields are already populated.
397+
func (ap *AutomationPolicy) RebuildCertMagic(tlsApp *TLS) error {
398+
cfg, err := ap.makeCertMagicConfig(tlsApp, ap.Issuers, ap.storage)
399+
if err != nil {
400+
return err
401+
}
352402
certCacheMu.RLock()
353-
ap.magic = certmagic.New(certCache, template)
403+
ap.magic = certmagic.New(certCache, cfg)
354404
certCacheMu.RUnlock()
355405

356406
// sometimes issuers may need the parent certmagic.Config in

0 commit comments

Comments
 (0)