Add options to control ACME propagation checks
This commit is contained in:
parent
0ec12c7aa7
commit
33c1d700c0
9 changed files with 455 additions and 28 deletions
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue