diff options
author | Matt Holt <mholt@users.noreply.github.com> | 2024-04-13 21:31:43 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-13 21:31:43 -0400 |
commit | 81413caea251a3ef9e3641d7b1b6e867572a2b1b (patch) | |
tree | 1a379dcf516e8d7daeae1fb00e54c1fbf1e74696 /modules/caddytls/automation.go | |
parent | dc9dd2e4b3e266cb1267f672e3bcfd50c67cc3d4 (diff) |
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 'modules/caddytls/automation.go')
-rw-r--r-- | modules/caddytls/automation.go | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/modules/caddytls/automation.go b/modules/caddytls/automation.go index a90e5ded..803cb174 100644 --- a/modules/caddytls/automation.go +++ b/modules/caddytls/automation.go @@ -24,7 +24,7 @@ import ( "strings" "github.com/caddyserver/certmagic" - "github.com/mholt/acmez" + "github.com/mholt/acmez/v2" "go.uber.org/zap" "github.com/caddyserver/caddy/v2" @@ -201,6 +201,7 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error { // store them on the policy before putting it on the config // load and provision any cert manager modules + hadExplicitManagers := len(ap.ManagersRaw) > 0 if ap.ManagersRaw != nil { vals, err := tlsApp.ctx.LoadModule(ap, "ManagersRaw") if err != nil { @@ -256,12 +257,25 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error { if ap.OnDemand || len(ap.Managers) > 0 { // permission module is now required after a number of negligence cases that allowed abuse; // but it may still be optional for explicit subjects (bounded, non-wildcard), for the - // internal issuer since it doesn't cause public PKI pressure on ACME servers - if ap.isWildcardOrDefault() && !ap.onlyInternalIssuer() && (tlsApp.Automation == nil || tlsApp.Automation.OnDemand == nil || tlsApp.Automation.OnDemand.permission == nil) { - return fmt.Errorf("on-demand TLS cannot be enabled without a permission module to prevent abuse; please refer to documentation for details") + // internal issuer since it doesn't cause public PKI pressure on ACME servers; subtly, it + // is useful to allow on-demand TLS to be enabled so Managers can be used, but to still + // prevent issuance from Issuers (when Managers don't provide a certificate) if there's no + // permission module configured + noProtections := ap.isWildcardOrDefault() && !ap.onlyInternalIssuer() && (tlsApp.Automation == nil || tlsApp.Automation.OnDemand == nil || tlsApp.Automation.OnDemand.permission == nil) + failClosed := noProtections && hadExplicitManagers // don't allow on-demand issuance (other than implicit managers) if no managers have been explicitly configured + if noProtections { + if !hadExplicitManagers { + // no managers, no explicitly-configured permission module, this is a config error + return fmt.Errorf("on-demand TLS cannot be enabled without a permission module to prevent abuse; please refer to documentation for details") + } + // allow on-demand to be enabled but only for the purpose of the Managers; issuance won't be allowed from Issuers + tlsApp.logger.Warn("on-demand TLS can only get certificates from the configured external manager(s) because no ask endpoint / permission module is specified") } ond = &certmagic.OnDemandConfig{ DecisionFunc: func(ctx context.Context, name string) error { + if failClosed { + return fmt.Errorf("no permission module configured; certificates not allowed except from external Managers") + } if tlsApp.Automation == nil || tlsApp.Automation.OnDemand == nil { return nil } @@ -344,6 +358,16 @@ func (ap *AutomationPolicy) Subjects() []string { return ap.subjects } +// AllInternalSubjects returns true if all the subjects on this policy are internal. +func (ap *AutomationPolicy) AllInternalSubjects() bool { + for _, subj := range ap.subjects { + if !certmagic.SubjectIsInternal(subj) { + return false + } + } + return true +} + func (ap *AutomationPolicy) onlyInternalIssuer() bool { if len(ap.Issuers) != 1 { return false @@ -370,17 +394,21 @@ func (ap *AutomationPolicy) isWildcardOrDefault() bool { // DefaultIssuers returns empty Issuers (not provisioned) to be used as defaults. // This function is experimental and has no compatibility promises. -func DefaultIssuers() []certmagic.Issuer { - return []certmagic.Issuer{ - new(ACMEIssuer), - &ZeroSSLIssuer{ACMEIssuer: new(ACMEIssuer)}, +func DefaultIssuers(userEmail string) []certmagic.Issuer { + issuers := []certmagic.Issuer{new(ACMEIssuer)} + if strings.TrimSpace(userEmail) != "" { + issuers = append(issuers, &ACMEIssuer{ + CA: certmagic.ZeroSSLProductionCA, + Email: userEmail, + }) } + return issuers } // DefaultIssuersProvisioned returns empty but provisioned default Issuers from // DefaultIssuers(). This function is experimental and has no compatibility promises. func DefaultIssuersProvisioned(ctx caddy.Context) ([]certmagic.Issuer, error) { - issuers := DefaultIssuers() + issuers := DefaultIssuers("") for i, iss := range issuers { if prov, ok := iss.(caddy.Provisioner); ok { err := prov.Provision(ctx) @@ -453,6 +481,7 @@ type TLSALPNChallengeConfig struct { type DNSChallengeConfig struct { // The DNS provider module to use which will manage // the DNS records relevant to the ACME challenge. + // Required. ProviderRaw json.RawMessage `json:"provider,omitempty" caddy:"namespace=dns.providers inline_key=name"` // The TTL of the TXT record used for the DNS challenge. |