@marcel91200 / caddy Mirror · read-only / commits / 90284e80
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

httpcaddyfile: Fix default issuers when email provided

If `tls <email>` is used, we should apply that to all applicable default issuers, not drop them. This refactoring applies implicit ACME issuer settings from the tls directive to all default ACME issuers, like ZeroSSL. We also consolidate some annoying logic and improve config validity checks. Ref: https://caddy.community/t/error-obtaining-certificate-after-caddy-restart/11335/8

Matthew Holt committed Feb 2, 2021 at 16:17 UTC 90284e8017fedeb6eeb9f4183660a679b8a5e15e
4 files changed +72 -50
caddyconfig/httpcaddyfile/builtins.go
+41 -15
@@ -369,31 +369,57 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
369 })
370 }
371
372 + // some tls subdirectives are shortcuts that implicitly configure issuers, and the
373 + // user can also configure issuers explicitly using the issuer subdirective; the
374 + // logic to support both would likely be complex, or at least unintuitive
375 if len(issuers) > 0 && (acmeIssuer != nil || internalIssuer != nil) {
373 - // some tls subdirectives are shortcuts that implicitly configure issuers, and the
374 - // user can also configure issuers explicitly using the issuer subdirective; the
375 - // logic to support both would likely be complex, or at least unintuitive
376 return nil, h.Err("cannot mix issuer subdirective (explicit issuers) with other issuer-specific subdirectives (implicit issuers)")
377 }
378 - for _, issuer := range issuers {
379 - configVals = append(configVals, ConfigValue{
380 - Class: "tls.cert_issuer",
381 - Value: issuer,
382 - })
383 - }
384 - if acmeIssuer != nil {
385 - configVals = append(configVals, ConfigValue{
386 - Class: "tls.cert_issuer",
387 - Value: disambiguateACMEIssuer(acmeIssuer),
388 - })
378 + if acmeIssuer != nil && internalIssuer != nil {
379 + return nil, h.Err("cannot create both ACME and internal certificate issuers")
380 }
390 - if internalIssuer != nil {
381 +
382 + // now we should either have: explicitly-created issuers, or an implicitly-created
383 + // ACME or internal issuer, or no issuers at all
384 + switch {
385 + case len(issuers) > 0:
386 + for _, issuer := range issuers {
387 + configVals = append(configVals, ConfigValue{
388 + Class: "tls.cert_issuer",
389 + Value: issuer,
390 + })
391 + }
392 +
393 + case acmeIssuer != nil:
394 + // implicit ACME issuers (from various subdirectives) - use defaults; there might be more than one
395 + defaultIssuers := caddytls.DefaultIssuers()
396 +
397 + // if a CA endpoint was set, override multiple implicit issuers since it's a specific one
398 + if acmeIssuer.CA != "" {
399 + defaultIssuers = []certmagic.Issuer{acmeIssuer}
400 + }
401 +
402 + for _, issuer := range defaultIssuers {
403 + switch iss := issuer.(type) {
404 + case *caddytls.ACMEIssuer:
405 + issuer = acmeIssuer
406 + case *caddytls.ZeroSSLIssuer:
407 + iss.ACMEIssuer = acmeIssuer
408 + }
409 + configVals = append(configVals, ConfigValue{
410 + Class: "tls.cert_issuer",
411 + Value: issuer,
412 + })
413 + }
414 +
415 + case internalIssuer != nil:
416 configVals = append(configVals, ConfigValue{
417 Class: "tls.cert_issuer",
418 Value: internalIssuer,
419 })
420 }
421
422 + // certificate key type
423 if keyType != "" {
424 configVals = append(configVals, ConfigValue{
425 Class: "tls.key_type",
caddyconfig/httpcaddyfile/tlsapp.go
+9 -20
@@ -316,13 +316,15 @@ func (st ServerType) buildTLSApp(
316 if hasGlobalACMEDefaults {
317 for _, ap := range tlsApp.Automation.Policies {
318 if len(ap.Issuers) == 0 {
319 - acme, zerosslACME := new(caddytls.ACMEIssuer), new(caddytls.ACMEIssuer)
320 - zerossl := &caddytls.ZeroSSLIssuer{ACMEIssuer: zerosslACME}
321 - ap.Issuers = []certmagic.Issuer{acme, zerossl} // TODO: keep this in sync with Caddy's other issuer defaults elsewhere, like in caddytls/automation.go (DefaultIssuers).
322 -
323 - // if a non-ZeroSSL endpoint is specified, we assume we can't use the ZeroSSL issuer successfully
324 - if globalACMECA != nil && !strings.Contains(globalACMECA.(string), "zerossl") {
325 - ap.Issuers = []certmagic.Issuer{acme}
319 + ap.Issuers = caddytls.DefaultIssuers()
320 +
321 + // if a specific endpoint is configured, can't use multiple default issuers
322 + if globalACMECA != nil {
323 + if strings.Contains(globalACMECA.(string), "zerossl") {
324 + ap.Issuers = []certmagic.Issuer{&caddytls.ZeroSSLIssuer{ACMEIssuer: new(caddytls.ACMEIssuer)}}
325 + } else {
326 + ap.Issuers = []certmagic.Issuer{new(caddytls.ACMEIssuer)}
327 + }
328 }
329 }
330 }
@@ -463,19 +465,6 @@ func newBaseAutomationPolicy(options map[string]interface{}, warnings []caddycon
465 return ap, nil
466 }
467
466 -// disambiguateACMEIssuer returns an issuer based on the properties of acmeIssuer.
467 -// If acmeIssuer implicitly configures a certain kind of ACMEIssuer (for example,
468 -// ZeroSSL), the proper wrapper over acmeIssuer will be returned instead.
469 -func disambiguateACMEIssuer(acmeIssuer *caddytls.ACMEIssuer) certmagic.Issuer {
470 - // as a special case, we integrate with ZeroSSL's ACME endpoint if it looks like an
471 - // implicit ZeroSSL configuration (this requires a wrapper type over ACMEIssuer
472 - // because of the EAB generation; if EAB is provided, we can use plain ACMEIssuer)
473 - if strings.Contains(acmeIssuer.CA, "acme.zerossl.com") && acmeIssuer.ExternalAccount == nil {
474 - return &caddytls.ZeroSSLIssuer{ACMEIssuer: acmeIssuer}
475 - }
476 - return acmeIssuer
477 -}
478 -
468 // consolidateAutomationPolicies combines automation policies that are the same,
469 // for a cleaner overall output.
470 func consolidateAutomationPolicies(aps []*caddytls.AutomationPolicy) []*caddytls.AutomationPolicy {
modules/caddyhttp/autohttps.go
+2 -2
@@ -444,7 +444,7 @@ func (app *App) createAutomationPolicies(ctx caddy.Context, internalNames []stri
444 // what the HTTP and HTTPS ports are)
445 if ap.Issuers == nil {
446 var err error
447 - ap.Issuers, err = caddytls.DefaultIssuers(ctx)
447 + ap.Issuers, err = caddytls.DefaultIssuersProvisioned(ctx)
448 if err != nil {
449 return err
450 }
@@ -499,7 +499,7 @@ func (app *App) createAutomationPolicies(ctx caddy.Context, internalNames []stri
499 // never overwrite any other issuer that might already be configured
500 if basePolicy.Issuers == nil {
501 var err error
502 - basePolicy.Issuers, err = caddytls.DefaultIssuers(ctx)
502 + basePolicy.Issuers, err = caddytls.DefaultIssuersProvisioned(ctx)
503 if err != nil {
504 return err
505 }
modules/caddytls/automation.go
+20 -13
@@ -187,7 +187,7 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
187 issuers := ap.Issuers
188 if len(issuers) == 0 {
189 var err error
190 - issuers, err = DefaultIssuers(tlsApp.ctx)
190 + issuers, err = DefaultIssuersProvisioned(tlsApp.ctx)
191 if err != nil {
192 return err
193 }
@@ -242,21 +242,28 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
242 return nil
243 }
244
245 -// DefaultIssuers returns empty but provisioned default Issuers.
245 +// DefaultIssuers returns empty Issuers (not provisioned) to be used as defaults.
246 // This function is experimental and has no compatibility promises.
247 -func DefaultIssuers(ctx caddy.Context) ([]certmagic.Issuer, error) {
248 - acme := new(ACMEIssuer)
249 - err := acme.Provision(ctx)
250 - if err != nil {
251 - return nil, err
247 +func DefaultIssuers() []certmagic.Issuer {
248 + return []certmagic.Issuer{
249 + new(ACMEIssuer),
250 + &ZeroSSLIssuer{ACMEIssuer: new(ACMEIssuer)},
251 }
253 - zerossl := new(ZeroSSLIssuer)
254 - err = zerossl.Provision(ctx)
255 - if err != nil {
256 - return nil, err
252 +}
253 +
254 +// DefaultIssuersProvisioned returns empty but provisioned default Issuers from
255 +// DefaultIssuers(). This function is experimental and has no compatibility promises.
256 +func DefaultIssuersProvisioned(ctx caddy.Context) ([]certmagic.Issuer, error) {
257 + issuers := DefaultIssuers()
258 + for i, iss := range issuers {
259 + if prov, ok := iss.(caddy.Provisioner); ok {
260 + err := prov.Provision(ctx)
261 + if err != nil {
262 + return nil, fmt.Errorf("provisioning default issuer %d: %T: %v", i, iss, err)
263 + }
264 + }
265 }
258 - // TODO: eventually, insert ZeroSSL into first position in the slice -- see also httpcaddyfile/tlsapp.go for where similar defaults are configured
259 - return []certmagic.Issuer{acme, zerossl}, nil
266 + return issuers, nil
267 }
268
269 // ChallengesConfig configures the ACME challenges.