diff options
author | Matt Holt <[email protected]> | 2024-04-13 21:31:43 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2024-04-13 21:31:43 -0400 |
commit | 81413caea251a3ef9e3641d7b1b6e867572a2b1b (patch) | |
tree | 1a379dcf516e8d7daeae1fb00e54c1fbf1e74696 /caddyconfig | |
parent | dc9dd2e4b3e266cb1267f672e3bcfd50c67cc3d4 (diff) | |
download | caddy-81413caea251a3ef9e3641d7b1b6e867572a2b1b.tar.gz caddy-81413caea251a3ef9e3641d7b1b6e867572a2b1b.zip |
caddytls: Upgrade ACMEz to v2; support ZeroSSL API; various fixes (#6229)
* WIP: acmez v2, CertMagic, and ZeroSSL issuer upgrades
* caddytls: ZeroSSLIssuer now uses ZeroSSL API instead of ACME
* Fix go.mod
* caddytls: Fix automation related to managers (fix #6060)
* Fix typo (appease linter)
* Fix HTTP validation with ZeroSSL API
Diffstat (limited to 'caddyconfig')
-rw-r--r-- | caddyconfig/httpcaddyfile/builtins.go | 28 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/options.go | 6 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/tlsapp.go | 31 |
3 files changed, 41 insertions, 24 deletions
diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 505885d2d..a7f4247f5 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -24,7 +24,7 @@ import ( "time" "github.com/caddyserver/certmagic" - "github.com/mholt/acmez/acme" + "github.com/mholt/acmez/v2/acme" "go.uber.org/zap/zapcore" "github.com/caddyserver/caddy/v2" @@ -107,7 +107,6 @@ func parseTLS(h Helper) ([]ConfigValue, error) { var onDemand bool var reusePrivateKeys bool - // file certificate loader firstLine := h.RemainingArgs() switch len(firstLine) { case 0: @@ -117,13 +116,13 @@ func parseTLS(h Helper) ([]ConfigValue, error) { } else if !strings.Contains(firstLine[0], "@") { return nil, h.Err("single argument must either be 'internal' or an email address") } else { - if acmeIssuer == nil { - acmeIssuer = new(caddytls.ACMEIssuer) + acmeIssuer = &caddytls.ACMEIssuer{ + Email: firstLine[0], } - acmeIssuer.Email = firstLine[0] } case 2: + // file certificate loader certFilename := firstLine[0] keyFilename := firstLine[1] @@ -488,19 +487,24 @@ func parseTLS(h Helper) ([]ConfigValue, error) { case acmeIssuer != nil: // implicit ACME issuers (from various subdirectives) - use defaults; there might be more than one - defaultIssuers := caddytls.DefaultIssuers() + defaultIssuers := caddytls.DefaultIssuers(acmeIssuer.Email) - // if a CA endpoint was set, override multiple implicit issuers since it's a specific one + // if an ACME CA endpoint was set, the user expects to use that specific one, + // not any others that may be defaults, so replace all defaults with that ACME CA if acmeIssuer.CA != "" { defaultIssuers = []certmagic.Issuer{acmeIssuer} } for _, issuer := range defaultIssuers { - switch iss := issuer.(type) { - case *caddytls.ACMEIssuer: - issuer = acmeIssuer - case *caddytls.ZeroSSLIssuer: - iss.ACMEIssuer = acmeIssuer + // apply settings from the implicitly-configured ACMEIssuer to any + // default ACMEIssuers, but preserve each default issuer's CA endpoint, + // because, for example, if you configure the DNS challenge, it should + // apply to any of the default ACMEIssuers, but you don't want to trample + // out their unique CA endpoints + if iss, ok := issuer.(*caddytls.ACMEIssuer); ok && iss != nil { + acmeCopy := *acmeIssuer + acmeCopy.CA = iss.CA + issuer = &acmeCopy } configVals = append(configVals, ConfigValue{ Class: "tls.cert_issuer", diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go index 70d475d6b..bbc63ced8 100644 --- a/caddyconfig/httpcaddyfile/options.go +++ b/caddyconfig/httpcaddyfile/options.go @@ -18,7 +18,7 @@ import ( "strconv" "github.com/caddyserver/certmagic" - "github.com/mholt/acmez/acme" + "github.com/mholt/acmez/v2/acme" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig" @@ -212,9 +212,9 @@ func parseOptACMEDNS(d *caddyfile.Dispenser, _ any) (any, error) { if err != nil { return nil, err } - prov, ok := unm.(certmagic.ACMEDNSProvider) + prov, ok := unm.(certmagic.DNSProvider) if !ok { - return nil, d.Errf("module %s (%T) is not a certmagic.ACMEDNSProvider", modID, unm) + return nil, d.Errf("module %s (%T) is not a certmagic.DNSProvider", modID, unm) } return prov, nil } diff --git a/caddyconfig/httpcaddyfile/tlsapp.go b/caddyconfig/httpcaddyfile/tlsapp.go index 1adb2b6e0..08da3a5c7 100644 --- a/caddyconfig/httpcaddyfile/tlsapp.go +++ b/caddyconfig/httpcaddyfile/tlsapp.go @@ -24,7 +24,7 @@ import ( "strings" "github.com/caddyserver/certmagic" - "github.com/mholt/acmez/acme" + "github.com/mholt/acmez/v2/acme" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig" @@ -224,7 +224,7 @@ func (st ServerType) buildTLSApp( var internal, external []string for _, s := range ap.SubjectsRaw { // do not create Issuers for Tailscale domains; they will be given a Manager instead - if strings.HasSuffix(strings.ToLower(s), ".ts.net") { + if isTailscaleDomain(s) { continue } if !certmagic.SubjectQualifiesForCert(s) { @@ -378,15 +378,12 @@ func (st ServerType) buildTLSApp( if len(ap.Issuers) == 0 && automationPolicyHasAllPublicNames(ap) { // for public names, create default issuers which will later be filled in with configured global defaults // (internal names will implicitly use the internal issuer at auto-https time) - ap.Issuers = caddytls.DefaultIssuers() + emailStr, _ := globalEmail.(string) + ap.Issuers = caddytls.DefaultIssuers(emailStr) // if a specific endpoint is configured, can't use multiple default issuers if globalACMECA != nil { - if strings.Contains(globalACMECA.(string), "zerossl") { - ap.Issuers = []certmagic.Issuer{&caddytls.ZeroSSLIssuer{ACMEIssuer: new(caddytls.ACMEIssuer)}} - } else { - ap.Issuers = []certmagic.Issuer{new(caddytls.ACMEIssuer)} - } + ap.Issuers = []certmagic.Issuer{new(caddytls.ACMEIssuer)} } } } @@ -666,17 +663,33 @@ func automationPolicyShadows(i int, aps []*caddytls.AutomationPolicy) int { // subjectQualifiesForPublicCert is like certmagic.SubjectQualifiesForPublicCert() except // that this allows domains with multiple wildcard levels like '*.*.example.com' to qualify // if the automation policy has OnDemand enabled (i.e. this function is more lenient). +// +// IP subjects are considered as non-qualifying for public certs. Technically, there are +// now public ACME CAs as well as non-ACME CAs that issue IP certificates. But this function +// is used solely for implicit automation (defaults), where it gets really complicated to +// keep track of which issuers support IP certificates in which circumstances. Currently, +// issuers that support IP certificates are very few, and all require some sort of config +// from the user anyway (such as an account credential). Since we cannot implicitly and +// automatically get public IP certs without configuration from the user, we treat IPs as +// not qualifying for public certificates. Users should expressly configure an issuer +// that supports IP certs for that purpose. func subjectQualifiesForPublicCert(ap *caddytls.AutomationPolicy, subj string) bool { return !certmagic.SubjectIsIP(subj) && !certmagic.SubjectIsInternal(subj) && (strings.Count(subj, "*.") < 2 || ap.OnDemand) } +// automationPolicyHasAllPublicNames returns true if all the names on the policy +// do NOT qualify for public certs OR are tailscale domains. func automationPolicyHasAllPublicNames(ap *caddytls.AutomationPolicy) bool { for _, subj := range ap.SubjectsRaw { - if !subjectQualifiesForPublicCert(ap, subj) { + if !subjectQualifiesForPublicCert(ap, subj) || isTailscaleDomain(subj) { return false } } return true } + +func isTailscaleDomain(name string) bool { + return strings.HasSuffix(strings.ToLower(name), ".ts.net") +} |