diff --git a/modules/caddytls/acmeissuer.go b/modules/caddytls/acmeissuer.go index 9552d6f60..2fe4004fa 100644 --- a/modules/caddytls/acmeissuer.go +++ b/modules/caddytls/acmeissuer.go @@ -17,6 +17,7 @@ package caddytls import ( "context" "crypto/x509" + "errors" "fmt" "net/url" "os" @@ -250,28 +251,27 @@ func (iss *ACMEIssuer) GetACMEIssuer() *ACMEIssuer { return iss } // UnmarshalCaddyfile deserializes Caddyfile tokens into iss. // -// ... acme [] { -// dir -// test_dir -// email -// timeout -// disable_http_challenge -// disable_tlsalpn_challenge -// alt_http_port -// alt_tlsalpn_port -// eab -// trusted_roots -// dns [] -// propagation_delay -// propagation_timeout -// resolvers -// dns_challenge_override_domain -// preferred_chains [smallest] { -// root_common_name -// any_common_name -// } -// } -// +// ... acme [] { +// dir +// test_dir +// email +// timeout +// disable_http_challenge +// disable_tlsalpn_challenge +// alt_http_port +// alt_tlsalpn_port +// eab +// trusted_roots +// dns [] +// propagation_delay +// propagation_timeout +// resolvers +// dns_challenge_override_domain +// preferred_chains [smallest] { +// root_common_name +// any_common_name +// } +// } func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { for d.Next() { if d.NextArg() { @@ -494,8 +494,7 @@ func onDemandAskRequest(ask string, name string) error { resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode > 299 { - return fmt.Errorf("certificate for hostname '%s' not allowed; non-2xx status code %d returned from %v", - name, resp.StatusCode, ask) + return fmt.Errorf("%s: %w %s - non-2xx status code %d", name, errAskDenied, ask, resp.StatusCode) } return nil @@ -568,6 +567,11 @@ type ChainPreference struct { AnyCommonName []string `json:"any_common_name,omitempty"` } +// errAskDenied is an error that should be wrapped or returned when the +// configured "ask" endpoint does not allow a certificate to be issued, +// to distinguish that from other errors such as connection failure. +var errAskDenied = errors.New("certificate not allowed by ask endpoint") + // Interface guards var ( _ certmagic.PreChecker = (*ACMEIssuer)(nil) diff --git a/modules/caddytls/automation.go b/modules/caddytls/automation.go index ee168b432..0a732b8df 100644 --- a/modules/caddytls/automation.go +++ b/modules/caddytls/automation.go @@ -16,6 +16,7 @@ package caddytls import ( "encoding/json" + "errors" "fmt" "net/http" "time" @@ -23,6 +24,7 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/certmagic" "github.com/mholt/acmez" + "go.uber.org/zap" ) // AutomationConfig governs the automated management of TLS certificates. @@ -174,6 +176,13 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error { tlsApp.Automation.OnDemand.Ask != "" { err := onDemandAskRequest(tlsApp.Automation.OnDemand.Ask, name) if err != nil { + // distinguish true errors from denials, because it's important to log actual errors + if !errors.Is(err, errAskDenied) { + tlsApp.logger.Error("request to 'ask' endpoint failed", + zap.Error(err), + zap.String("endpoint", tlsApp.Automation.OnDemand.Ask), + zap.String("domain", name)) + } return err } }