From fefb0e817cff1b8f53eec9e1a552a234b76374cf Mon Sep 17 00:00:00 2001 From: Corentin Lauverjat Date: Fri, 15 Dec 2023 13:32:51 +0000 Subject: [PATCH 1/4] Add option to configure certificate lifetime --- caddyconfig/httpcaddyfile/options.go | 1 + caddyconfig/httpcaddyfile/tlsapp.go | 5 +++++ go.mod | 2 +- go.sum | 2 ++ modules/caddytls/acmeissuer.go | 22 ++++++++++++++++++++++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go index bbc63ced8e0..4ad3c731d66 100644 --- a/caddyconfig/httpcaddyfile/options.go +++ b/caddyconfig/httpcaddyfile/options.go @@ -54,6 +54,7 @@ func init() { RegisterGlobalOption("auto_https", parseOptAutoHTTPS) RegisterGlobalOption("servers", parseServerOptions) RegisterGlobalOption("ocsp_stapling", parseOCSPStaplingOptions) + RegisterGlobalOption("cert_lifetime", parseOptDuration) RegisterGlobalOption("log", parseLogOptions) RegisterGlobalOption("preferred_chains", parseOptPreferredChains) RegisterGlobalOption("persist_config", parseOptPersistConfig) diff --git a/caddyconfig/httpcaddyfile/tlsapp.go b/caddyconfig/httpcaddyfile/tlsapp.go index bf3bed41ad6..f1ee1e863eb 100644 --- a/caddyconfig/httpcaddyfile/tlsapp.go +++ b/caddyconfig/httpcaddyfile/tlsapp.go @@ -456,6 +456,7 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]any) e globalACMEDNS := options["acme_dns"] globalACMEEAB := options["acme_eab"] globalPreferredChains := options["preferred_chains"] + globalCertLifetime := options["cert_lifetime"] if globalEmail != nil && acmeIssuer.Email == "" { acmeIssuer.Email = globalEmail.(string) @@ -479,6 +480,10 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]any) e if globalPreferredChains != nil && acmeIssuer.PreferredChains == nil { acmeIssuer.PreferredChains = globalPreferredChains.(*caddytls.ChainPreference) } + + if globalCertLifetime != nil && acmeIssuer.CertificateLifetime == 0 { + acmeIssuer.CertificateLifetime = globalCertLifetime.(caddy.Duration) + } return nil } diff --git a/go.mod b/go.mod index c3dc1568ff6..ddcbd76fd4f 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 github.com/alecthomas/chroma/v2 v2.13.0 github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b - github.com/caddyserver/certmagic v0.20.1-0.20240412214119-167015dd6570 + github.com/caddyserver/certmagic v0.20.1-0.20240418194233-27ab129028e1 github.com/caddyserver/zerossl v0.1.2 github.com/dustin/go-humanize v1.0.1 github.com/go-chi/chi/v5 v5.0.12 diff --git a/go.sum b/go.sum index bd298867ec7..947f00f55d4 100644 --- a/go.sum +++ b/go.sum @@ -70,6 +70,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/caddyserver/certmagic v0.20.1-0.20240412214119-167015dd6570 h1:SsAXjoQx2wOmLl6mEwJEwh7wwys2hb/l/mhtmxA3wts= github.com/caddyserver/certmagic v0.20.1-0.20240412214119-167015dd6570/go.mod h1:e1NhB1rF5KZnAuAX6oSyhE7sg1Ru5bWgggw5RtauhEY= +github.com/caddyserver/certmagic v0.20.1-0.20240418194233-27ab129028e1 h1:jyf7BgZCwGqrqjv2+wOX662oZr9QqeSjzwA9bCG+paM= +github.com/caddyserver/certmagic v0.20.1-0.20240418194233-27ab129028e1/go.mod h1:e1NhB1rF5KZnAuAX6oSyhE7sg1Ru5bWgggw5RtauhEY= github.com/caddyserver/zerossl v0.1.2 h1:tlEu1VzWGoqcCpivs9liKAKhfpJWYJkHEMmlxRbVAxE= github.com/caddyserver/zerossl v0.1.2/go.mod h1:wtiJEHbdvunr40ZzhXlnIkOB8Xj4eKtBKizCcZitJiQ= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= diff --git a/modules/caddytls/acmeissuer.go b/modules/caddytls/acmeissuer.go index 547618e8ff1..800e4d98ff1 100644 --- a/modules/caddytls/acmeissuer.go +++ b/modules/caddytls/acmeissuer.go @@ -88,6 +88,16 @@ type ACMEIssuer struct { // will be selected. PreferredChains *ChainPreference `json:"preferred_chains,omitempty"` + // The validity period to ask the CA to issue a certificate for. + // Default: 0 (don't ask a custom lifetime to the CA) + // This value is used to compute the "notAfter" field of the ACME order, + // therefore the system must have a reasonably synchronized clock. + // Important : Let's Encrypt and ZeroSSL don't allow custom + // validity period and will refuse to issue a certicate if this is set. + // For CAs that support it, there are often limits + // on the allowed validity periods. Please refer to your CA documentation. + CertificateLifetime caddy.Duration `json:"certificate_lifetime,omitempty"` + rootPool *x509.CertPool logger *zap.Logger @@ -178,6 +188,7 @@ func (iss *ACMEIssuer) makeIssuerTemplate() (certmagic.ACMEIssuer, error) { CertObtainTimeout: time.Duration(iss.ACMETimeout), TrustedRoots: iss.rootPool, ExternalAccount: iss.ExternalAccount, + NotAfter: time.Duration(iss.CertificateLifetime), Logger: iss.logger, } @@ -349,6 +360,17 @@ func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { for d.NextBlock(0) { switch d.Val() { + case "lifetime": + var lifetimeStr string + if !d.AllArgs(&lifetimeStr) { + return d.ArgErr() + } + lifetime, err := caddy.ParseDuration(lifetimeStr) + if err != nil { + return d.Errf("invalid lifetime %s: %v", lifetimeStr, err) + } + // TODO: Add check that valid lifetime must be >= 0 + iss.CertificateLifetime = caddy.Duration(lifetime) case "dir": if iss.CA != "" { return d.Errf("directory is already specified: %s", iss.CA) From 7d3dcb2b5eedfc870671ceb0e7eb0d554cb170ef Mon Sep 17 00:00:00 2001 From: Corentin Lauverjat Date: Fri, 19 Apr 2024 19:43:29 +0000 Subject: [PATCH 2/4] Bump CertMagic dep to latest master commit --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index ddcbd76fd4f..9d085f8a30f 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 github.com/alecthomas/chroma/v2 v2.13.0 github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b - github.com/caddyserver/certmagic v0.20.1-0.20240418194233-27ab129028e1 + github.com/caddyserver/certmagic v0.20.1-0.20240419174353-855d4670a49d github.com/caddyserver/zerossl v0.1.2 github.com/dustin/go-humanize v1.0.1 github.com/go-chi/chi/v5 v5.0.12 diff --git a/go.sum b/go.sum index 947f00f55d4..68584116735 100644 --- a/go.sum +++ b/go.sum @@ -72,6 +72,8 @@ github.com/caddyserver/certmagic v0.20.1-0.20240412214119-167015dd6570 h1:SsAXjo github.com/caddyserver/certmagic v0.20.1-0.20240412214119-167015dd6570/go.mod h1:e1NhB1rF5KZnAuAX6oSyhE7sg1Ru5bWgggw5RtauhEY= github.com/caddyserver/certmagic v0.20.1-0.20240418194233-27ab129028e1 h1:jyf7BgZCwGqrqjv2+wOX662oZr9QqeSjzwA9bCG+paM= github.com/caddyserver/certmagic v0.20.1-0.20240418194233-27ab129028e1/go.mod h1:e1NhB1rF5KZnAuAX6oSyhE7sg1Ru5bWgggw5RtauhEY= +github.com/caddyserver/certmagic v0.20.1-0.20240419174353-855d4670a49d h1:fi1dMdHOoyWHXpxpCbaB+H4xdAgQcBP2AXSqpXVpIcg= +github.com/caddyserver/certmagic v0.20.1-0.20240419174353-855d4670a49d/go.mod h1:e1NhB1rF5KZnAuAX6oSyhE7sg1Ru5bWgggw5RtauhEY= github.com/caddyserver/zerossl v0.1.2 h1:tlEu1VzWGoqcCpivs9liKAKhfpJWYJkHEMmlxRbVAxE= github.com/caddyserver/zerossl v0.1.2/go.mod h1:wtiJEHbdvunr40ZzhXlnIkOB8Xj4eKtBKizCcZitJiQ= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= From b87f0b77545ef2b33a1a945878fd946b9d963ba3 Mon Sep 17 00:00:00 2001 From: Corentin Lauverjat Date: Fri, 19 Apr 2024 22:24:16 +0000 Subject: [PATCH 3/4] Apply suggestions and ran go mod tidy --- go.sum | 4 ---- modules/caddytls/acmeissuer.go | 16 +++++++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/go.sum b/go.sum index 68584116735..0edc55f2720 100644 --- a/go.sum +++ b/go.sum @@ -68,10 +68,6 @@ github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/caddyserver/certmagic v0.20.1-0.20240412214119-167015dd6570 h1:SsAXjoQx2wOmLl6mEwJEwh7wwys2hb/l/mhtmxA3wts= -github.com/caddyserver/certmagic v0.20.1-0.20240412214119-167015dd6570/go.mod h1:e1NhB1rF5KZnAuAX6oSyhE7sg1Ru5bWgggw5RtauhEY= -github.com/caddyserver/certmagic v0.20.1-0.20240418194233-27ab129028e1 h1:jyf7BgZCwGqrqjv2+wOX662oZr9QqeSjzwA9bCG+paM= -github.com/caddyserver/certmagic v0.20.1-0.20240418194233-27ab129028e1/go.mod h1:e1NhB1rF5KZnAuAX6oSyhE7sg1Ru5bWgggw5RtauhEY= github.com/caddyserver/certmagic v0.20.1-0.20240419174353-855d4670a49d h1:fi1dMdHOoyWHXpxpCbaB+H4xdAgQcBP2AXSqpXVpIcg= github.com/caddyserver/certmagic v0.20.1-0.20240419174353-855d4670a49d/go.mod h1:e1NhB1rF5KZnAuAX6oSyhE7sg1Ru5bWgggw5RtauhEY= github.com/caddyserver/zerossl v0.1.2 h1:tlEu1VzWGoqcCpivs9liKAKhfpJWYJkHEMmlxRbVAxE= diff --git a/modules/caddytls/acmeissuer.go b/modules/caddytls/acmeissuer.go index 800e4d98ff1..39133228251 100644 --- a/modules/caddytls/acmeissuer.go +++ b/modules/caddytls/acmeissuer.go @@ -89,13 +89,12 @@ type ACMEIssuer struct { PreferredChains *ChainPreference `json:"preferred_chains,omitempty"` // The validity period to ask the CA to issue a certificate for. - // Default: 0 (don't ask a custom lifetime to the CA) - // This value is used to compute the "notAfter" field of the ACME order, + // Default: 0 (CA chooses lifetime). + // This value is used to compute the "notAfter" field of the ACME order; // therefore the system must have a reasonably synchronized clock. - // Important : Let's Encrypt and ZeroSSL don't allow custom - // validity period and will refuse to issue a certicate if this is set. - // For CAs that support it, there are often limits - // on the allowed validity periods. Please refer to your CA documentation. + // NOTE: Not all CAs support this. Check with your CA's ACME + // documentation to see if this is allowed and what values may + // be used. CertificateLifetime caddy.Duration `json:"certificate_lifetime,omitempty"` rootPool *x509.CertPool @@ -369,8 +368,11 @@ func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { if err != nil { return d.Errf("invalid lifetime %s: %v", lifetimeStr, err) } - // TODO: Add check that valid lifetime must be >= 0 + if lifetime < 0 { + return d.Errf("lifetime must be >= 0: %s", lifetime) + } iss.CertificateLifetime = caddy.Duration(lifetime) + case "dir": if iss.CA != "" { return d.Errf("directory is already specified: %s", iss.CA) From 7216dcc045f40defe23f0adf4b9dc69ad4ad4dd9 Mon Sep 17 00:00:00 2001 From: clauverjat Date: Wed, 24 Apr 2024 20:59:52 +0200 Subject: [PATCH 4/4] Update modules/caddytls/acmeissuer.go Co-authored-by: Matt Holt --- modules/caddytls/acmeissuer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/caddytls/acmeissuer.go b/modules/caddytls/acmeissuer.go index 39133228251..1f57c7e3858 100644 --- a/modules/caddytls/acmeissuer.go +++ b/modules/caddytls/acmeissuer.go @@ -94,7 +94,7 @@ type ACMEIssuer struct { // therefore the system must have a reasonably synchronized clock. // NOTE: Not all CAs support this. Check with your CA's ACME // documentation to see if this is allowed and what values may - // be used. + // be used. EXPERIMENTAL: Subject to change. CertificateLifetime caddy.Duration `json:"certificate_lifetime,omitempty"` rootPool *x509.CertPool