1
0
mirror of https://github.com/containous/traefik.git synced 2025-03-05 20:58:24 +03:00

Add options to control ACME propagation checks

This commit is contained in:
Ludovic Fernandez 2024-11-26 09:08:04 +01:00 committed by GitHub
parent 0ec12c7aa7
commit 33c1d700c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 455 additions and 28 deletions

View File

@ -496,7 +496,7 @@ certificatesResolvers:
--certificatesresolvers.myresolver.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53
```
#### `delayBeforeCheck`
#### `propagation.delayBeforeChecks`
By default, the `provider` verifies the TXT record _before_ letting ACME verify.
@ -511,7 +511,9 @@ certificatesResolvers:
# ...
dnsChallenge:
# ...
delayBeforeCheck: 2s
propagation:
# ...
delayBeforeChecks: 2s
```
```toml tab="File (TOML)"
@ -519,19 +521,21 @@ certificatesResolvers:
# ...
[certificatesResolvers.myresolver.acme.dnsChallenge]
# ...
delayBeforeCheck = "2s"
[certificatesResolvers.myresolver.acme.dnsChallenge.propagation]
# ...
delayBeforeChecks = "2s"
```
```bash tab="CLI"
# ...
--certificatesresolvers.myresolver.acme.dnschallenge.delayBeforeCheck=2s
--certificatesresolvers.myresolver.acme.dnschallenge.propagation.delayBeforeChecks=2s
```
#### `disablePropagationCheck`
#### `propagation.disableChecks`
**Not recommended**
Disables the challenge TXT record propagation checks, before notifying ACME that the DNS challenge is ready.
Disable the TXT records propagation checks before notifying ACME that the DNS challenge is ready.
Please note that disabling checks can prevent the challenge to succeed.
```yaml tab="File (YAML)"
certificatesResolvers:
@ -540,7 +544,9 @@ certificatesResolvers:
# ...
dnsChallenge:
# ...
disablePropagationCheck: true
propagation:
# ...
disableChecks: true
```
```toml tab="File (TOML)"
@ -548,12 +554,90 @@ certificatesResolvers:
# ...
[certificatesResolvers.myresolver.acme.dnsChallenge]
# ...
disablePropagationCheck = true
[certificatesResolvers.myresolver.acme.dnsChallenge.propagation]
# ...
disableChecks = true
```
```bash tab="CLI"
# ...
--certificatesresolvers.myresolver.acme.dnschallenge.disablePropagationCheck=true
--certificatesresolvers.myresolver.acme.dnschallenge.propagation.disableChecks=true
```
#### `propagation.requireAllRNS`
Requires the challenge TXT record to be propagated to all recursive nameservers.
!!! note
If you have disabled authoritative nameservers checks (with `propagation.disableANSChecks`),
it is recommended to check all recursive nameservers instead.
```yaml tab="File (YAML)"
certificatesResolvers:
myresolver:
acme:
# ...
dnsChallenge:
# ...
propagation:
# ...
requireAllRNS: true
```
```toml tab="File (TOML)"
[certificatesResolvers.myresolver.acme]
# ...
[certificatesResolvers.myresolver.acme.dnsChallenge]
# ...
[certificatesResolvers.myresolver.acme.dnsChallenge.propagation]
# ...
requireAllRNS = true
```
```bash tab="CLI"
# ...
--certificatesresolvers.myresolver.acme.dnschallenge.propagation.requireAllRNS=true
```
#### `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.
!!! note
If you have disabled authoritative nameservers checks,
it is recommended to check all recursive nameservers instead.
```yaml tab="File (YAML)"
certificatesResolvers:
myresolver:
acme:
# ...
dnsChallenge:
# ...
propagation:
# ...
disableANSChecks: true
```
```toml tab="File (TOML)"
[certificatesResolvers.myresolver.acme]
# ...
[certificatesResolvers.myresolver.acme.dnsChallenge]
# ...
[certificatesResolvers.myresolver.acme.dnsChallenge.propagation]
# ...
disableANSChecks = true
```
```bash tab="CLI"
# ...
--certificatesresolvers.myresolver.acme.dnschallenge.propagation.disableANSChecks=true
```
#### Wildcard Domains

View File

@ -160,3 +160,10 @@ the `configmaps`, `backendtlspolicies` and `backendtlspolicies/status` rights ha
In `v3.2.1`, the `X-Forwarded-Prefix` header is now handled like the other `X-Forwarded-*` headers: Traefik removes it when it's sent from an untrusted source.
Please refer to the Forwarded headers [documentation](../routing/entrypoints.md#forwarded-headers) for more details.
## v3.2 to v3.3
### ACME DNS Certificate Resolver
In `v3.3`, the `acme.dnsChallenge.delaybeforecheck` and `acme.dnsChallenge.disablepropagationcheck` options of the ACME certificate resolver are deprecated,
please use respectively `acme.dnsChallenge.propagation.delayBeforeCheck` and `acme.dnsChallenge.propagation.disableAllChecks` options instead.

View File

@ -79,10 +79,25 @@ Certificates' duration in hours. (Default: ```2160```)
Activate DNS-01 Challenge. (Default: ```false```)
`--certificatesresolvers.<name>.acme.dnschallenge.delaybeforecheck`:
Assume DNS propagates after a delay in seconds rather than finding and querying nameservers. (Default: ```0```)
(Deprecated) Assume DNS propagates after a delay in seconds rather than finding and querying nameservers. (Default: ```0```)
`--certificatesresolvers.<name>.acme.dnschallenge.disablepropagationcheck`:
Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended] (Default: ```false```)
(Deprecated) Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended] (Default: ```false```)
`--certificatesresolvers.<name>.acme.dnschallenge.propagation`:
DNS propagation checks configuration (Default: ```false```)
`--certificatesresolvers.<name>.acme.dnschallenge.propagation.delaybeforechecks`:
Defines the delay before checking the challenge TXT record propagation. (Default: ```0```)
`--certificatesresolvers.<name>.acme.dnschallenge.propagation.disableanschecks`:
Disables the challenge TXT record propagation checks against authoritative nameservers. (Default: ```false```)
`--certificatesresolvers.<name>.acme.dnschallenge.propagation.disablechecks`:
Disables the challenge TXT record propagation checks (not recommended). (Default: ```false```)
`--certificatesresolvers.<name>.acme.dnschallenge.propagation.requireallrns`:
Requires the challenge TXT record to be propagated to all recursive nameservers. (Default: ```false```)
`--certificatesresolvers.<name>.acme.dnschallenge.provider`:
Use a DNS-01 based challenge provider rather than HTTPS.

View File

@ -79,10 +79,25 @@ Certificates' duration in hours. (Default: ```2160```)
Activate DNS-01 Challenge. (Default: ```false```)
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_ACME_DNSCHALLENGE_DELAYBEFORECHECK`:
Assume DNS propagates after a delay in seconds rather than finding and querying nameservers. (Default: ```0```)
(Deprecated) Assume DNS propagates after a delay in seconds rather than finding and querying nameservers. (Default: ```0```)
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_ACME_DNSCHALLENGE_DISABLEPROPAGATIONCHECK`:
Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended] (Default: ```false```)
(Deprecated) Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended] (Default: ```false```)
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_ACME_DNSCHALLENGE_PROPAGATION`:
DNS propagation checks configuration (Default: ```false```)
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_ACME_DNSCHALLENGE_PROPAGATION_DELAYBEFORECHECKS`:
Defines the delay before checking the challenge TXT record propagation. (Default: ```0```)
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_ACME_DNSCHALLENGE_PROPAGATION_DISABLEANSCHECKS`:
Disables the challenge TXT record propagation checks against authoritative nameservers. (Default: ```false```)
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_ACME_DNSCHALLENGE_PROPAGATION_DISABLECHECKS`:
Disables the challenge TXT record propagation checks (not recommended). (Default: ```false```)
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_ACME_DNSCHALLENGE_PROPAGATION_REQUIREALLRNS`:
Requires the challenge TXT record to be propagated to all recursive nameservers. (Default: ```false```)
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>_ACME_DNSCHALLENGE_PROVIDER`:
Use a DNS-01 based challenge provider rather than HTTPS.

View File

@ -457,9 +457,14 @@
hmacEncoded = "foobar"
[certificatesResolvers.CertificateResolver0.acme.dnsChallenge]
provider = "foobar"
delayBeforeCheck = "42s"
resolvers = ["foobar", "foobar"]
delayBeforeCheck = "42s"
disablePropagationCheck = true
[certificatesResolvers.CertificateResolver0.acme.dnsChallenge.propagation]
disableChecks = true
disableANSChecks = true
requireAllRNS = true
delayBeforeChecks = "42s"
[certificatesResolvers.CertificateResolver0.acme.httpChallenge]
entryPoint = "foobar"
[certificatesResolvers.CertificateResolver0.acme.tlsChallenge]
@ -480,9 +485,14 @@
hmacEncoded = "foobar"
[certificatesResolvers.CertificateResolver1.acme.dnsChallenge]
provider = "foobar"
delayBeforeCheck = "42s"
resolvers = ["foobar", "foobar"]
delayBeforeCheck = "42s"
disablePropagationCheck = true
[certificatesResolvers.CertificateResolver1.acme.dnsChallenge.propagation]
disableChecks = true
disableANSChecks = true
requireAllRNS = true
delayBeforeChecks = "42s"
[certificatesResolvers.CertificateResolver1.acme.httpChallenge]
entryPoint = "foobar"
[certificatesResolvers.CertificateResolver1.acme.tlsChallenge]

View File

@ -500,10 +500,15 @@ certificatesResolvers:
caServerName: foobar
dnsChallenge:
provider: foobar
delayBeforeCheck: 42s
resolvers:
- foobar
- foobar
propagation:
disableChecks: true
disableANSChecks: true
requireAllRNS: true
delayBeforeChecks: 42s
delayBeforeCheck: 42s
disablePropagationCheck: true
httpChallenge:
entryPoint: foobar
@ -527,10 +532,15 @@ certificatesResolvers:
caServerName: foobar
dnsChallenge:
provider: foobar
delayBeforeCheck: 42s
resolvers:
- foobar
- foobar
propagation:
disableChecks: true
disableANSChecks: true
requireAllRNS: true
delayBeforeChecks: 42s
delayBeforeCheck: 42s
disablePropagationCheck: true
httpChallenge:
entryPoint: foobar

View File

@ -306,6 +306,36 @@ func (c *Configuration) SetEffectiveConfiguration() {
c.Providers.KubernetesIngress.DefaultRuleSyntax = c.Core.DefaultRuleSyntax
}
for _, resolver := range c.CertificatesResolvers {
if resolver.ACME == nil {
continue
}
if resolver.ACME.DNSChallenge == nil {
continue
}
if resolver.ACME.DNSChallenge.DisablePropagationCheck {
log.Warn().Msgf("disablePropagationCheck is now deprecated, please use propagation.disableAllChecks instead.")
if resolver.ACME.DNSChallenge.Propagation == nil {
resolver.ACME.DNSChallenge.Propagation = &acmeprovider.Propagation{}
}
resolver.ACME.DNSChallenge.Propagation.DisableChecks = true
}
if resolver.ACME.DNSChallenge.DelayBeforeCheck > 0 {
log.Warn().Msgf("delayBeforeCheck is now deprecated, please use propagation.delayBeforeCheck instead.")
if resolver.ACME.DNSChallenge.Propagation == nil {
resolver.ACME.DNSChallenge.Propagation = &acmeprovider.Propagation{}
}
resolver.ACME.DNSChallenge.Propagation.DelayBeforeChecks = resolver.ACME.DNSChallenge.DelayBeforeCheck
}
}
c.initACMEProvider()
}

View File

@ -4,6 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/traefik/traefik/v3/pkg/provider/acme"
)
func TestHasEntrypoint(t *testing.T) {
@ -37,3 +38,233 @@ func TestHasEntrypoint(t *testing.T) {
})
}
}
func TestConfiguration_SetEffectiveConfiguration(t *testing.T) {
testCases := []struct {
desc string
conf *Configuration
expected *Configuration
}{
{
desc: "empty",
conf: &Configuration{
Providers: &Providers{},
},
expected: &Configuration{
EntryPoints: EntryPoints{"http": &EntryPoint{
Address: ":80",
AllowACMEByPass: false,
ReusePort: false,
AsDefault: false,
Transport: &EntryPointsTransport{
LifeCycle: &LifeCycle{
GraceTimeOut: 10000000000,
},
RespondingTimeouts: &RespondingTimeouts{
ReadTimeout: 60000000000,
IdleTimeout: 180000000000,
},
},
ProxyProtocol: nil,
ForwardedHeaders: &ForwardedHeaders{},
HTTP: HTTPConfig{
MaxHeaderBytes: 1048576,
},
HTTP2: &HTTP2Config{
MaxConcurrentStreams: 250,
},
HTTP3: nil,
UDP: &UDPConfig{
Timeout: 3000000000,
},
}},
Providers: &Providers{},
},
},
{
desc: "ACME simple",
conf: &Configuration{
Providers: &Providers{},
CertificatesResolvers: map[string]CertificateResolver{
"foo": {
ACME: &acme.Configuration{
DNSChallenge: &acme.DNSChallenge{
Provider: "bar",
},
},
},
},
},
expected: &Configuration{
EntryPoints: EntryPoints{"http": &EntryPoint{
Address: ":80",
AllowACMEByPass: false,
ReusePort: false,
AsDefault: false,
Transport: &EntryPointsTransport{
LifeCycle: &LifeCycle{
GraceTimeOut: 10000000000,
},
RespondingTimeouts: &RespondingTimeouts{
ReadTimeout: 60000000000,
IdleTimeout: 180000000000,
},
},
ProxyProtocol: nil,
ForwardedHeaders: &ForwardedHeaders{},
HTTP: HTTPConfig{
MaxHeaderBytes: 1048576,
},
HTTP2: &HTTP2Config{
MaxConcurrentStreams: 250,
},
HTTP3: nil,
UDP: &UDPConfig{
Timeout: 3000000000,
},
}},
Providers: &Providers{},
CertificatesResolvers: map[string]CertificateResolver{
"foo": {
ACME: &acme.Configuration{
CAServer: "https://acme-v02.api.letsencrypt.org/directory",
DNSChallenge: &acme.DNSChallenge{
Provider: "bar",
},
},
},
},
},
},
{
desc: "ACME deprecation DelayBeforeCheck",
conf: &Configuration{
Providers: &Providers{},
CertificatesResolvers: map[string]CertificateResolver{
"foo": {
ACME: &acme.Configuration{
DNSChallenge: &acme.DNSChallenge{
Provider: "bar",
DelayBeforeCheck: 123,
},
},
},
},
},
expected: &Configuration{
EntryPoints: EntryPoints{"http": &EntryPoint{
Address: ":80",
AllowACMEByPass: false,
ReusePort: false,
AsDefault: false,
Transport: &EntryPointsTransport{
LifeCycle: &LifeCycle{
GraceTimeOut: 10000000000,
},
RespondingTimeouts: &RespondingTimeouts{
ReadTimeout: 60000000000,
IdleTimeout: 180000000000,
},
},
ProxyProtocol: nil,
ForwardedHeaders: &ForwardedHeaders{},
HTTP: HTTPConfig{
MaxHeaderBytes: 1048576,
},
HTTP2: &HTTP2Config{
MaxConcurrentStreams: 250,
},
HTTP3: nil,
UDP: &UDPConfig{
Timeout: 3000000000,
},
}},
Providers: &Providers{},
CertificatesResolvers: map[string]CertificateResolver{
"foo": {
ACME: &acme.Configuration{
CAServer: "https://acme-v02.api.letsencrypt.org/directory",
DNSChallenge: &acme.DNSChallenge{
Provider: "bar",
DelayBeforeCheck: 123,
Propagation: &acme.Propagation{
DelayBeforeChecks: 123,
},
},
},
},
},
},
},
{
desc: "ACME deprecation DisablePropagationCheck",
conf: &Configuration{
Providers: &Providers{},
CertificatesResolvers: map[string]CertificateResolver{
"foo": {
ACME: &acme.Configuration{
DNSChallenge: &acme.DNSChallenge{
Provider: "bar",
DisablePropagationCheck: true,
},
},
},
},
},
expected: &Configuration{
EntryPoints: EntryPoints{"http": &EntryPoint{
Address: ":80",
AllowACMEByPass: false,
ReusePort: false,
AsDefault: false,
Transport: &EntryPointsTransport{
LifeCycle: &LifeCycle{
GraceTimeOut: 10000000000,
},
RespondingTimeouts: &RespondingTimeouts{
ReadTimeout: 60000000000,
IdleTimeout: 180000000000,
},
},
ProxyProtocol: nil,
ForwardedHeaders: &ForwardedHeaders{},
HTTP: HTTPConfig{
MaxHeaderBytes: 1048576,
},
HTTP2: &HTTP2Config{
MaxConcurrentStreams: 250,
},
HTTP3: nil,
UDP: &UDPConfig{
Timeout: 3000000000,
},
}},
Providers: &Providers{},
CertificatesResolvers: map[string]CertificateResolver{
"foo": {
ACME: &acme.Configuration{
CAServer: "https://acme-v02.api.letsencrypt.org/directory",
DNSChallenge: &acme.DNSChallenge{
Provider: "bar",
DisablePropagationCheck: true,
Propagation: &acme.Propagation{
DisableChecks: true,
},
},
},
},
},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
test.conf.SetEffectiveConfiguration()
assert.Equal(t, test.expected, test.conf)
})
}
}

View File

@ -85,10 +85,21 @@ type EAB struct {
// DNSChallenge contains DNS challenge configuration.
type DNSChallenge struct {
Provider string `description:"Use a DNS-01 based challenge provider rather than HTTPS." json:"provider,omitempty" toml:"provider,omitempty" yaml:"provider,omitempty" export:"true"`
DelayBeforeCheck ptypes.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers." json:"delayBeforeCheck,omitempty" toml:"delayBeforeCheck,omitempty" yaml:"delayBeforeCheck,omitempty" export:"true"`
Resolvers []string `description:"Use following DNS servers to resolve the FQDN authority." json:"resolvers,omitempty" toml:"resolvers,omitempty" yaml:"resolvers,omitempty"`
DisablePropagationCheck bool `description:"Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended]" json:"disablePropagationCheck,omitempty" toml:"disablePropagationCheck,omitempty" yaml:"disablePropagationCheck,omitempty" export:"true"`
Provider string `description:"Use a DNS-01 based challenge provider rather than HTTPS." json:"provider,omitempty" toml:"provider,omitempty" yaml:"provider,omitempty" export:"true"`
Resolvers []string `description:"Use following DNS servers to resolve the FQDN authority." json:"resolvers,omitempty" toml:"resolvers,omitempty" yaml:"resolvers,omitempty"`
Propagation *Propagation `description:"DNS propagation checks configuration" json:"propagation,omitempty" toml:"propagation,omitempty" yaml:"propagation,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
// Deprecated: please use Propagation.DelayBeforeCheck instead.
DelayBeforeCheck ptypes.Duration `description:"(Deprecated) Assume DNS propagates after a delay in seconds rather than finding and querying nameservers." json:"delayBeforeCheck,omitempty" toml:"delayBeforeCheck,omitempty" yaml:"delayBeforeCheck,omitempty" export:"true"`
// Deprecated: please use Propagation.DisableAllChecks instead.
DisablePropagationCheck bool `description:"(Deprecated) Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended]" json:"disablePropagationCheck,omitempty" toml:"disablePropagationCheck,omitempty" yaml:"disablePropagationCheck,omitempty" export:"true"`
}
type Propagation struct {
DisableChecks bool `description:"Disables the challenge TXT record propagation checks (not recommended)." json:"disableChecks,omitempty" toml:"disableChecks,omitempty" yaml:"disableChecks,omitempty" export:"true"`
DisableANSChecks bool `description:"Disables the challenge TXT record propagation checks against authoritative nameservers." json:"disableANSChecks,omitempty" toml:"disableANSChecks,omitempty" yaml:"disableANSChecks,omitempty" export:"true"`
RequireAllRNS bool `description:"Requires the challenge TXT record to be propagated to all recursive nameservers." json:"requireAllRNS,omitempty" toml:"requireAllRNS,omitempty" yaml:"requireAllRNS,omitempty" export:"true"`
DelayBeforeChecks ptypes.Duration `description:"Defines the delay before checking the challenge TXT record propagation." json:"delayBeforeChecks,omitempty" toml:"delayBeforeChecks,omitempty" yaml:"delayBeforeChecks,omitempty" export:"true"`
}
// HTTPChallenge contains HTTP challenge configuration.
@ -137,7 +148,7 @@ func (p *Provider) ListenConfiguration(config dynamic.Configuration) {
p.configFromListenerChan <- config
}
// Init for compatibility reason the BaseProvider implements an empty Init.
// Init inits the provider.
func (p *Provider) Init() error {
logger := log.With().Str(logs.ProviderName, p.ResolverName+resolverSuffix).Logger()
@ -311,11 +322,25 @@ func (p *Provider) getClient() (*lego.Client, error) {
return nil, err
}
err = client.Challenge.SetDNS01Provider(provider,
dns01.CondOption(len(p.DNSChallenge.Resolvers) > 0,
dns01.AddRecursiveNameservers(p.DNSChallenge.Resolvers)),
dns01.PropagationWait(time.Duration(p.DNSChallenge.DelayBeforeCheck), p.DNSChallenge.DisablePropagationCheck),
)
var opts []dns01.ChallengeOption
if len(p.DNSChallenge.Resolvers) > 0 {
opts = append(opts, dns01.AddRecursiveNameservers(p.DNSChallenge.Resolvers))
}
if p.DNSChallenge.Propagation != nil {
if p.DNSChallenge.Propagation.RequireAllRNS {
opts = append(opts, dns01.RecursiveNSsPropagationRequirement())
}
if p.DNSChallenge.Propagation.DisableANSChecks {
opts = append(opts, dns01.DisableAuthoritativeNssPropagationRequirement())
}
opts = append(opts, dns01.PropagationWait(time.Duration(p.DNSChallenge.Propagation.DelayBeforeChecks), p.DNSChallenge.Propagation.DisableChecks))
}
err = client.Challenge.SetDNS01Provider(provider, opts...)
if err != nil {
return nil, err
}