summaryrefslogtreecommitdiff
path: root/modules/caddytls/automation.go
diff options
context:
space:
mode:
authorMatt Holt <mholt@users.noreply.github.com>2024-04-13 21:31:43 -0400
committerGitHub <noreply@github.com>2024-04-13 21:31:43 -0400
commit81413caea251a3ef9e3641d7b1b6e867572a2b1b (patch)
tree1a379dcf516e8d7daeae1fb00e54c1fbf1e74696 /modules/caddytls/automation.go
parentdc9dd2e4b3e266cb1267f672e3bcfd50c67cc3d4 (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.go47
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.