From 6c3b099c25661e9517c9d0d2e3a5aa37dd380d1a Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 1 Apr 2025 17:08:05 +0200 Subject: [PATCH] Add acme.httpChallenge.delay option --- docs/content/https/acme.md | 28 ++++++++++++ .../tls/certificate-resolvers/acme.md | 43 ++++++++++--------- .../reference/static-configuration/cli-ref.md | 3 ++ .../reference/static-configuration/env-ref.md | 3 ++ .../reference/static-configuration/file.toml | 2 + .../reference/static-configuration/file.yaml | 2 + pkg/provider/acme/provider.go | 6 ++- 7 files changed, 64 insertions(+), 23 deletions(-) diff --git a/docs/content/https/acme.md b/docs/content/https/acme.md index 0a662e373..f8c8d996b 100644 --- a/docs/content/https/acme.md +++ b/docs/content/https/acme.md @@ -250,6 +250,34 @@ when using the `HTTP-01` challenge, `certificatesresolvers.myresolver.acme.httpc !!! info "" Redirection is fully compatible with the `HTTP-01` challenge. +#### `Delay` + +The delay between the creation of the challenge and the validation. +A value lower than or equal to zero means no delay. + +```yaml tab="File (YAML)" +certificatesResolvers: + myresolver: + acme: + # ... + httpChallenge: + # ... + delay: 12 +``` + +```toml tab="File (TOML)" +[certificatesResolvers.myresolver.acme] + # ... + [certificatesResolvers.myresolver.acme.httpChallenge] + # ... + delay = 12 +``` + +```bash tab="CLI" +# ... +--certificatesresolvers.myresolver.acme.httpchallenge.delay=12 +``` + ### `dnsChallenge` Use the `DNS-01` challenge to generate and renew ACME certificates by provisioning a DNS record. diff --git a/docs/content/reference/install-configuration/tls/certificate-resolvers/acme.md b/docs/content/reference/install-configuration/tls/certificate-resolvers/acme.md index 1b05bde5a..ec425f38a 100644 --- a/docs/content/reference/install-configuration/tls/certificate-resolvers/acme.md +++ b/docs/content/reference/install-configuration/tls/certificate-resolvers/acme.md @@ -73,27 +73,28 @@ certificatesResolvers: ACME certificate resolvers have the following configuration options: -| Field | Description | Default | Required | -|:------------------|:--------------------|:-----------------------------------------------|:---------| -| `acme.email` | Email address used for registration. | "" | Yes | -| `acme.caServer` | CA server to use. | https://acme-v02.api.letsencrypt.org/directory | No | -| `acme.preferredChain` | Preferred chain to use. If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. If no match, the default offered chain will be used. | "" | No | -| `acme.keyType` | KeyType to use. | "RSA4096" | No | -| `acme.eab` | Enable external account binding.| | No | -| `acme.eab.kid` | Key identifier from External CA. | "" | No | -| `acme.eab.hmacEncoded` | HMAC key from External CA, should be in Base64 URL Encoding without padding format. | "" | No | -| `acme.certificatesDuration` | The certificates' duration in hours, exclusively used to determine renewal dates. | 2160 | No | -| `acme.dnsChallenge` | Enable DNS-01 challenge. More information [here](#dnschallenge). | - | No | -| `acme.dnsChallenge.provider` | DNS provider to use. | "" | No | -| `acme.dnsChallenge.resolvers` | DNS servers to resolve the FQDN authority. | [] | No | -| `acme.dnsChallenge.propagation.delayBeforeChecks` | By default, the provider will verify the TXT DNS challenge record before letting ACME verify. If `delayBeforeCheck` is greater than zero, this check is delayed for the configured duration in seconds. This is Useful if internal networks block external DNS queries. | 0s | No | -| `acme.dnsChallenge.propagation.disableChecks` | Disables the challenge TXT record propagation checks, before notifying ACME that the DNS challenge is ready. Please note that disabling checks can prevent the challenge from succeeding. | false | No | -| `acme.dnsChallenge.propagation.requireAllRNS` | Enables the challenge TXT record to be propagated to all recursive nameservers. If you have disabled authoritative nameservers checks (with `propagation.disableANSChecks`), it is recommended to check all recursive nameservers instead. | false | No | -| `acme.dnsChallenge.propagation.disableANSChecks` | Disables the challenge TXT record propagation checks against authoritative nameservers. This option will skip the propagation check against the nameservers of the authority (SOA). It should be used only if the nameservers of the authority are not reachable. | false | No | -| `acme.httpChallenge` | Enable HTTP-01 challenge. More information [here](#httpchallenge). | | No | -| `acme.httpChallenge.entryPoint` | EntryPoint to use for the HTTP-01 challenges. Must be reachable by Let's Encrypt through port 80 | "" | Yes | -| `acme.tlsChallenge` | Enable TLS-ALPN-01 challenge. Traefik must be reachable by Let's Encrypt through port 443. More information [here](#tlschallenge). | - | No | -| `acme.storage` | File path used for certificates storage. | "acme.json" | Yes | +| Field | Description | Default | Required | +|:--------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------|:---------| +| `acme.email` | Email address used for registration. | "" | Yes | +| `acme.caServer` | CA server to use. | https://acme-v02.api.letsencrypt.org/directory | No | +| `acme.preferredChain` | Preferred chain to use. If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. If no match, the default offered chain will be used. | "" | No | +| `acme.keyType` | KeyType to use. | "RSA4096" | No | +| `acme.eab` | Enable external account binding. | | No | +| `acme.eab.kid` | Key identifier from External CA. | "" | No | +| `acme.eab.hmacEncoded` | HMAC key from External CA, should be in Base64 URL Encoding without padding format. | "" | No | +| `acme.certificatesDuration` | The certificates' duration in hours, exclusively used to determine renewal dates. | 2160 | No | +| `acme.dnsChallenge` | Enable DNS-01 challenge. More information [here](#dnschallenge). | - | No | +| `acme.dnsChallenge.provider` | DNS provider to use. | "" | No | +| `acme.dnsChallenge.resolvers` | DNS servers to resolve the FQDN authority. | [] | No | +| `acme.dnsChallenge.propagation.delayBeforeChecks` | By default, the provider will verify the TXT DNS challenge record before letting ACME verify. If `delayBeforeCheck` is greater than zero, this check is delayed for the configured duration in seconds. This is Useful if internal networks block external DNS queries. | 0s | No | +| `acme.dnsChallenge.propagation.disableChecks` | Disables the challenge TXT record propagation checks, before notifying ACME that the DNS challenge is ready. Please note that disabling checks can prevent the challenge from succeeding. | false | No | +| `acme.dnsChallenge.propagation.requireAllRNS` | Enables the challenge TXT record to be propagated to all recursive nameservers. If you have disabled authoritative nameservers checks (with `propagation.disableANSChecks`), it is recommended to check all recursive nameservers instead. | false | No | +| `acme.dnsChallenge.propagation.disableANSChecks` | Disables the challenge TXT record propagation checks against authoritative nameservers. This option will skip the propagation check against the nameservers of the authority (SOA). It should be used only if the nameservers of the authority are not reachable. | false | No | +| `acme.httpChallenge` | Enable HTTP-01 challenge. More information [here](#httpchallenge). | | No | +| `acme.httpChallenge.entryPoint` | EntryPoint to use for the HTTP-01 challenges. Must be reachable by Let's Encrypt through port 80 | "" | Yes | +| `acme.httpChallenge.delay` | The delay between the creation of the challenge and the validation. A value lower than or equal to zero means no delay. | 0 | No | +| `acme.tlsChallenge` | Enable TLS-ALPN-01 challenge. Traefik must be reachable by Let's Encrypt through port 443. More information [here](#tlschallenge). | - | No | +| `acme.storage` | File path used for certificates storage. | "acme.json" | Yes | ## Automatic Certificate Renewal diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md index dac410d21..b31e7db7d 100644 --- a/docs/content/reference/static-configuration/cli-ref.md +++ b/docs/content/reference/static-configuration/cli-ref.md @@ -174,6 +174,9 @@ CSR email addresses to use. `--certificatesresolvers..acme.httpchallenge`: Activate HTTP-01 Challenge. (Default: ```false```) +`--certificatesresolvers..acme.httpchallenge.delay`: +Delay between the creation of the challenge and the validation. (Default: ```0```) + `--certificatesresolvers..acme.httpchallenge.entrypoint`: HTTP challenge EntryPoint diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md index b67909baa..159af8c16 100644 --- a/docs/content/reference/static-configuration/env-ref.md +++ b/docs/content/reference/static-configuration/env-ref.md @@ -174,6 +174,9 @@ CSR email addresses to use. `TRAEFIK_CERTIFICATESRESOLVERS__ACME_HTTPCHALLENGE`: Activate HTTP-01 Challenge. (Default: ```false```) +`TRAEFIK_CERTIFICATESRESOLVERS__ACME_HTTPCHALLENGE_DELAY`: +Delay between the creation of the challenge and the validation. (Default: ```0```) + `TRAEFIK_CERTIFICATESRESOLVERS__ACME_HTTPCHALLENGE_ENTRYPOINT`: HTTP challenge EntryPoint diff --git a/docs/content/reference/static-configuration/file.toml b/docs/content/reference/static-configuration/file.toml index d35cf897d..cee1df4b5 100644 --- a/docs/content/reference/static-configuration/file.toml +++ b/docs/content/reference/static-configuration/file.toml @@ -528,6 +528,7 @@ delayBeforeChecks = "42s" [certificatesResolvers.CertificateResolver0.acme.httpChallenge] entryPoint = "foobar" + delay = "42s" [certificatesResolvers.CertificateResolver0.acme.tlsChallenge] [certificatesResolvers.CertificateResolver0.tailscale] [certificatesResolvers.CertificateResolver1] @@ -558,6 +559,7 @@ delayBeforeChecks = "42s" [certificatesResolvers.CertificateResolver1.acme.httpChallenge] entryPoint = "foobar" + delay = "42s" [certificatesResolvers.CertificateResolver1.acme.tlsChallenge] [certificatesResolvers.CertificateResolver1.tailscale] diff --git a/docs/content/reference/static-configuration/file.yaml b/docs/content/reference/static-configuration/file.yaml index 5b8361e08..e218b43e4 100644 --- a/docs/content/reference/static-configuration/file.yaml +++ b/docs/content/reference/static-configuration/file.yaml @@ -575,6 +575,7 @@ certificatesResolvers: disablePropagationCheck: true httpChallenge: entryPoint: foobar + delay: 42s tlsChallenge: {} tailscale: {} CertificateResolver1: @@ -611,6 +612,7 @@ certificatesResolvers: disablePropagationCheck: true httpChallenge: entryPoint: foobar + delay: 42s tlsChallenge: {} tailscale: {} experimental: diff --git a/pkg/provider/acme/provider.go b/pkg/provider/acme/provider.go index 9120ead27..2ff220100 100644 --- a/pkg/provider/acme/provider.go +++ b/pkg/provider/acme/provider.go @@ -20,6 +20,7 @@ import ( "github.com/go-acme/lego/v4/certificate" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/challenge/dns01" + "github.com/go-acme/lego/v4/challenge/http01" "github.com/go-acme/lego/v4/lego" "github.com/go-acme/lego/v4/providers/dns" "github.com/go-acme/lego/v4/registration" @@ -106,7 +107,8 @@ type Propagation struct { // HTTPChallenge contains HTTP challenge configuration. type HTTPChallenge struct { - EntryPoint string `description:"HTTP challenge EntryPoint" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty" export:"true"` + EntryPoint string `description:"HTTP challenge EntryPoint" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty" export:"true"` + Delay ptypes.Duration `description:"Delay between the creation of the challenge and the validation." json:"delay,omitempty" toml:"delay,omitempty" yaml:"delay,omitempty" export:"true"` } // TLSChallenge contains TLS challenge configuration. @@ -351,7 +353,7 @@ func (p *Provider) getClient() (*lego.Client, error) { if p.HTTPChallenge != nil && len(p.HTTPChallenge.EntryPoint) > 0 { logger.Debug().Msg("Using HTTP Challenge provider.") - err = client.Challenge.SetHTTP01Provider(p.HTTPChallengeProvider) + err = client.Challenge.SetHTTP01Provider(p.HTTPChallengeProvider, http01.SetDelay(time.Duration(p.HTTPChallenge.Delay))) if err != nil { return nil, err }