Wire DNS config into ACME DNS-01
- commit
- 0537081edee3216f48eae0936d5240f5beb095a4
- author
- brice · · 2026-05-01 13:51 UTC
- parent
- 68f340d
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +114 -9
M internal/adapters/out/acmelego/issuer.go +30 -4
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | 15 | "github.com/go-acme/lego/v4/acme" | |
| 16 | 16 | "github.com/go-acme/lego/v4/certcrypto" | |
| 17 | 17 | "github.com/go-acme/lego/v4/certificate" | |
| 18 | + | "github.com/go-acme/lego/v4/challenge/dns01" | |
| 18 | 19 | "github.com/go-acme/lego/v4/lego" | |
| 19 | 20 | "github.com/go-acme/lego/v4/providers/dns/cloudflare" | |
| 20 | 21 | "github.com/go-acme/lego/v4/registration" | |
| @@ -34,6 +35,15 @@ type Config struct { | |||
| 34 | 35 | // Token is the Cloudflare API token (required for DNS-01 challenge). | |
| 35 | 36 | Token string | |
| 36 | 37 | ||
| 38 | + | // DNSResolvers are recursive resolvers used for DNS-01 propagation checks. | |
| 39 | + | DNSResolvers []string | |
| 40 | + | ||
| 41 | + | // DNSPropagationTimeout is the maximum wait for DNS-01 TXT propagation. | |
| 42 | + | DNSPropagationTimeout time.Duration | |
| 43 | + | ||
| 44 | + | // DNSPollingInterval is the interval between DNS-01 propagation checks. | |
| 45 | + | DNSPollingInterval time.Duration | |
| 46 | + | ||
| 37 | 47 | // Store persists ACME accounts and certificates. | |
| 38 | 48 | Store out.CertificateStore | |
| 39 | 49 | ||
| @@ -81,6 +91,15 @@ func NewIssuer(cfg Config) (*Issuer, error) { | |||
| 81 | 91 | if cfg.Token == "" { | |
| 82 | 92 | return nil, fmt.Errorf("acmelego: %w", domain.ErrCloudflareTokenMissing) | |
| 83 | 93 | } | |
| 94 | + | if len(cfg.DNSResolvers) == 0 { | |
| 95 | + | return nil, fmt.Errorf("acmelego: DNSResolvers must contain at least one resolver") | |
| 96 | + | } | |
| 97 | + | if cfg.DNSPropagationTimeout <= 0 { | |
| 98 | + | return nil, fmt.Errorf("acmelego: DNSPropagationTimeout must be positive") | |
| 99 | + | } | |
| 100 | + | if cfg.DNSPollingInterval <= 0 { | |
| 101 | + | return nil, fmt.Errorf("acmelego: DNSPollingInterval must be positive") | |
| 102 | + | } | |
| 84 | 103 | default: | |
| 85 | 104 | return nil, fmt.Errorf("acmelego: %w: %s", domain.ErrACMEChallengeInvalid, cfg.Challenge) | |
| 86 | 105 | } | |
| @@ -208,13 +227,11 @@ func (i *Issuer) buildClient(ctx context.Context) (*AccountUser, *lego.Client, e | |||
| 208 | 227 | return nil, nil, fmt.Errorf("set http-01 provider: %w", err) | |
| 209 | 228 | } | |
| 210 | 229 | case domain.ACMEChallengeCloudflareDNS01: | |
| 211 | - | cfCfg := cloudflare.NewDefaultConfig() | |
| 212 | - | cfCfg.AuthToken = i.cfg.Token | |
| 213 | - | cfProvider, err := cloudflare.NewDNSProviderConfig(cfCfg) | |
| 230 | + | cfProvider, err := cloudflare.NewDNSProviderConfig(newCloudflareDNSProviderConfig(i.cfg)) | |
| 214 | 231 | if err != nil { | |
| 215 | 232 | return nil, nil, fmt.Errorf("create cloudflare dns provider: %w", err) | |
| 216 | 233 | } | |
| 217 | - | if err := client.Challenge.SetDNS01Provider(cfProvider); err != nil { | |
| 234 | + | if err := client.Challenge.SetDNS01Provider(cfProvider, dns01.AddRecursiveNameservers(i.cfg.DNSResolvers)); err != nil { | |
| 218 | 235 | return nil, nil, fmt.Errorf("set dns-01 provider: %w", err) | |
| 219 | 236 | } | |
| 220 | 237 | } | |
| @@ -312,6 +329,15 @@ func (i *Issuer) newLegoConfig(user *AccountUser) *lego.Config { | |||
| 312 | 329 | return legoCfg | |
| 313 | 330 | } | |
| 314 | 331 | ||
| 332 | + | // newCloudflareDNSProviderConfig creates a cloudflare DNS provider config from the issuer config. | |
| 333 | + | func newCloudflareDNSProviderConfig(cfg Config) *cloudflare.Config { | |
| 334 | + | cfCfg := cloudflare.NewDefaultConfig() | |
| 335 | + | cfCfg.AuthToken = cfg.Token | |
| 336 | + | cfCfg.PropagationTimeout = cfg.DNSPropagationTimeout | |
| 337 | + | cfCfg.PollingInterval = cfg.DNSPollingInterval | |
| 338 | + | return cfCfg | |
| 339 | + | } | |
| 340 | + | ||
| 315 | 341 | // resourceToStored converts a lego certificate.Resource to out.StoredCertificate. | |
| 316 | 342 | func resourceToStored(order out.CertificateOrder, res *certificate.Resource) (*out.StoredCertificate, error) { | |
| 317 | 343 | var fullchainPEM []byte | |
| @@ -15,6 +15,7 @@ import ( | |||||
| 15 | "github.com/go-acme/lego/v4/acme" | 15 | "github.com/go-acme/lego/v4/acme" | ||
| 16 | "github.com/go-acme/lego/v4/certcrypto" | 16 | "github.com/go-acme/lego/v4/certcrypto" | ||
| 17 | "github.com/go-acme/lego/v4/certificate" | 17 | "github.com/go-acme/lego/v4/certificate" | ||
| 18 | + | "github.com/go-acme/lego/v4/challenge/dns01" | |||
| 18 | "github.com/go-acme/lego/v4/lego" | 19 | "github.com/go-acme/lego/v4/lego" | ||
| 19 | "github.com/go-acme/lego/v4/providers/dns/cloudflare" | 20 | "github.com/go-acme/lego/v4/providers/dns/cloudflare" | ||
| 20 | "github.com/go-acme/lego/v4/registration" | 21 | "github.com/go-acme/lego/v4/registration" | ||
| @@ -34,6 +35,15 @@ type Config struct { | |||||
| 34 | // Token is the Cloudflare API token (required for DNS-01 challenge). | 35 | // Token is the Cloudflare API token (required for DNS-01 challenge). | ||
| 35 | Token string | 36 | Token string | ||
| 36 | 37 | ||||
| 38 | + | // DNSResolvers are recursive resolvers used for DNS-01 propagation checks. | |||
| 39 | + | DNSResolvers []string | |||
| 40 | + | ||||
| 41 | + | // DNSPropagationTimeout is the maximum wait for DNS-01 TXT propagation. | |||
| 42 | + | DNSPropagationTimeout time.Duration | |||
| 43 | + | ||||
| 44 | + | // DNSPollingInterval is the interval between DNS-01 propagation checks. | |||
| 45 | + | DNSPollingInterval time.Duration | |||
| 46 | + | ||||
| 37 | // Store persists ACME accounts and certificates. | 47 | // Store persists ACME accounts and certificates. | ||
| 38 | Store out.CertificateStore | 48 | Store out.CertificateStore | ||
| 39 | 49 | ||||
| @@ -81,6 +91,15 @@ func NewIssuer(cfg Config) (*Issuer, error) { | |||||
| 81 | if cfg.Token == "" { | 91 | if cfg.Token == "" { | ||
| 82 | return nil, fmt.Errorf("acmelego: %w", domain.ErrCloudflareTokenMissing) | 92 | return nil, fmt.Errorf("acmelego: %w", domain.ErrCloudflareTokenMissing) | ||
| 83 | } | 93 | } | ||
| 94 | + | if len(cfg.DNSResolvers) == 0 { | |||
| 95 | + | return nil, fmt.Errorf("acmelego: DNSResolvers must contain at least one resolver") | |||
| 96 | + | } | |||
| 97 | + | if cfg.DNSPropagationTimeout <= 0 { | |||
| 98 | + | return nil, fmt.Errorf("acmelego: DNSPropagationTimeout must be positive") | |||
| 99 | + | } | |||
| 100 | + | if cfg.DNSPollingInterval <= 0 { | |||
| 101 | + | return nil, fmt.Errorf("acmelego: DNSPollingInterval must be positive") | |||
| 102 | + | } | |||
| 84 | default: | 103 | default: | ||
| 85 | return nil, fmt.Errorf("acmelego: %w: %s", domain.ErrACMEChallengeInvalid, cfg.Challenge) | 104 | return nil, fmt.Errorf("acmelego: %w: %s", domain.ErrACMEChallengeInvalid, cfg.Challenge) | ||
| 86 | } | 105 | } | ||
| @@ -208,13 +227,11 @@ func (i *Issuer) buildClient(ctx context.Context) (*AccountUser, *lego.Client, e | |||||
| 208 | return nil, nil, fmt.Errorf("set http-01 provider: %w", err) | 227 | return nil, nil, fmt.Errorf("set http-01 provider: %w", err) | ||
| 209 | } | 228 | } | ||
| 210 | case domain.ACMEChallengeCloudflareDNS01: | 229 | case domain.ACMEChallengeCloudflareDNS01: | ||
| 211 | - | cfCfg := cloudflare.NewDefaultConfig() | 230 | + | cfProvider, err := cloudflare.NewDNSProviderConfig(newCloudflareDNSProviderConfig(i.cfg)) |
| 212 | - | cfCfg.AuthToken = i.cfg.Token | |||
| 213 | - | cfProvider, err := cloudflare.NewDNSProviderConfig(cfCfg) | |||
| 214 | if err != nil { | 231 | if err != nil { | ||
| 215 | return nil, nil, fmt.Errorf("create cloudflare dns provider: %w", err) | 232 | return nil, nil, fmt.Errorf("create cloudflare dns provider: %w", err) | ||
| 216 | } | 233 | } | ||
| 217 | - | if err := client.Challenge.SetDNS01Provider(cfProvider); err != nil { | 234 | + | if err := client.Challenge.SetDNS01Provider(cfProvider, dns01.AddRecursiveNameservers(i.cfg.DNSResolvers)); err != nil { |
| 218 | return nil, nil, fmt.Errorf("set dns-01 provider: %w", err) | 235 | return nil, nil, fmt.Errorf("set dns-01 provider: %w", err) | ||
| 219 | } | 236 | } | ||
| 220 | } | 237 | } | ||
| @@ -312,6 +329,15 @@ func (i *Issuer) newLegoConfig(user *AccountUser) *lego.Config { | |||||
| 312 | return legoCfg | 329 | return legoCfg | ||
| 313 | } | 330 | } | ||
| 314 | 331 | ||||
| 332 | + | // newCloudflareDNSProviderConfig creates a cloudflare DNS provider config from the issuer config. | |||
| 333 | + | func newCloudflareDNSProviderConfig(cfg Config) *cloudflare.Config { | |||
| 334 | + | cfCfg := cloudflare.NewDefaultConfig() | |||
| 335 | + | cfCfg.AuthToken = cfg.Token | |||
| 336 | + | cfCfg.PropagationTimeout = cfg.DNSPropagationTimeout | |||
| 337 | + | cfCfg.PollingInterval = cfg.DNSPollingInterval | |||
| 338 | + | return cfCfg | |||
| 339 | + | } | |||
| 340 | + | ||||
| 315 | // resourceToStored converts a lego certificate.Resource to out.StoredCertificate. | 341 | // resourceToStored converts a lego certificate.Resource to out.StoredCertificate. | ||
| 316 | func resourceToStored(order out.CertificateOrder, res *certificate.Resource) (*out.StoredCertificate, error) { | 342 | func resourceToStored(order out.CertificateOrder, res *certificate.Resource) (*out.StoredCertificate, error) { | ||
| 317 | var fullchainPEM []byte | 343 | var fullchainPEM []byte | ||
M internal/adapters/out/acmelego/issuer_test.go +39 -0
| @@ -69,6 +69,31 @@ func TestNewIssuerValidatesCloudflareToken(t *testing.T) { | |||
| 69 | 69 | assert.ErrorIs(t, err, domain.ErrCloudflareTokenMissing) | |
| 70 | 70 | } | |
| 71 | 71 | ||
| 72 | + | func TestNewIssuerValidatesCloudflareDNSConfig(t *testing.T) { | |
| 73 | + | _, err := NewIssuer(Config{ | |
| 74 | + | Email: "test@example.com", | |
| 75 | + | Challenge: domain.ACMEChallengeCloudflareDNS01, | |
| 76 | + | Token: "token", | |
| 77 | + | Store: outmocks.NewMockCertificateStore(t), | |
| 78 | + | DNSResolvers: nil, | |
| 79 | + | DNSPropagationTimeout: 5 * time.Minute, | |
| 80 | + | DNSPollingInterval: 5 * time.Second, | |
| 81 | + | }) | |
| 82 | + | require.Error(t, err) | |
| 83 | + | assert.Contains(t, err.Error(), "DNSResolvers") | |
| 84 | + | ||
| 85 | + | _, err = NewIssuer(Config{ | |
| 86 | + | Email: "test@example.com", | |
| 87 | + | Challenge: domain.ACMEChallengeCloudflareDNS01, | |
| 88 | + | Token: "token", | |
| 89 | + | Store: outmocks.NewMockCertificateStore(t), | |
| 90 | + | DNSResolvers: []string{"1.1.1.1:53"}, | |
| 91 | + | DNSPropagationTimeout: 5 * time.Minute, | |
| 92 | + | DNSPollingInterval: 5 * time.Second, | |
| 93 | + | }) | |
| 94 | + | require.NoError(t, err) | |
| 95 | + | } | |
| 96 | + | ||
| 72 | 97 | func TestNewIssuerRejectsNonHTTPSURL(t *testing.T) { | |
| 73 | 98 | _, err := NewIssuer(Config{ | |
| 74 | 99 | Email: "test@example.com", | |
| @@ -102,6 +127,20 @@ func TestNewIssuerValidWithDefaults(t *testing.T) { | |||
| 102 | 127 | assert.Equal(t, domain.ACMEChallengeHTTP01, issuer.cfg.Challenge) | |
| 103 | 128 | } | |
| 104 | 129 | ||
| 130 | + | func TestCloudflareDNSProviderConfigUsesDNSSettings(t *testing.T) { | |
| 131 | + | cfg := Config{ | |
| 132 | + | Token: "token", | |
| 133 | + | DNSPropagationTimeout: 7 * time.Minute, | |
| 134 | + | DNSPollingInterval: 11 * time.Second, | |
| 135 | + | } | |
| 136 | + | ||
| 137 | + | cfCfg := newCloudflareDNSProviderConfig(cfg) | |
| 138 | + | ||
| 139 | + | assert.Equal(t, "token", cfCfg.AuthToken) | |
| 140 | + | assert.Equal(t, 7*time.Minute, cfCfg.PropagationTimeout) | |
| 141 | + | assert.Equal(t, 11*time.Second, cfCfg.PollingInterval) | |
| 142 | + | } | |
| 143 | + | ||
| 105 | 144 | func TestPrivateKeyRoundTrip(t *testing.T) { | |
| 106 | 145 | // Generate an ECDSA P-256 private key | |
| 107 | 146 | privateKey, err := certcrypto.GeneratePrivateKey(certcrypto.EC256) | |
| @@ -69,6 +69,31 @@ func TestNewIssuerValidatesCloudflareToken(t *testing.T) { | |||||
| 69 | assert.ErrorIs(t, err, domain.ErrCloudflareTokenMissing) | 69 | assert.ErrorIs(t, err, domain.ErrCloudflareTokenMissing) | ||
| 70 | } | 70 | } | ||
| 71 | 71 | ||||
| 72 | + | func TestNewIssuerValidatesCloudflareDNSConfig(t *testing.T) { | |||
| 73 | + | _, err := NewIssuer(Config{ | |||
| 74 | + | Email: "test@example.com", | |||
| 75 | + | Challenge: domain.ACMEChallengeCloudflareDNS01, | |||
| 76 | + | Token: "token", | |||
| 77 | + | Store: outmocks.NewMockCertificateStore(t), | |||
| 78 | + | DNSResolvers: nil, | |||
| 79 | + | DNSPropagationTimeout: 5 * time.Minute, | |||
| 80 | + | DNSPollingInterval: 5 * time.Second, | |||
| 81 | + | }) | |||
| 82 | + | require.Error(t, err) | |||
| 83 | + | assert.Contains(t, err.Error(), "DNSResolvers") | |||
| 84 | + | ||||
| 85 | + | _, err = NewIssuer(Config{ | |||
| 86 | + | Email: "test@example.com", | |||
| 87 | + | Challenge: domain.ACMEChallengeCloudflareDNS01, | |||
| 88 | + | Token: "token", | |||
| 89 | + | Store: outmocks.NewMockCertificateStore(t), | |||
| 90 | + | DNSResolvers: []string{"1.1.1.1:53"}, | |||
| 91 | + | DNSPropagationTimeout: 5 * time.Minute, | |||
| 92 | + | DNSPollingInterval: 5 * time.Second, | |||
| 93 | + | }) | |||
| 94 | + | require.NoError(t, err) | |||
| 95 | + | } | |||
| 96 | + | ||||
| 72 | func TestNewIssuerRejectsNonHTTPSURL(t *testing.T) { | 97 | func TestNewIssuerRejectsNonHTTPSURL(t *testing.T) { | ||
| 73 | _, err := NewIssuer(Config{ | 98 | _, err := NewIssuer(Config{ | ||
| 74 | Email: "test@example.com", | 99 | Email: "test@example.com", | ||
| @@ -102,6 +127,20 @@ func TestNewIssuerValidWithDefaults(t *testing.T) { | |||||
| 102 | assert.Equal(t, domain.ACMEChallengeHTTP01, issuer.cfg.Challenge) | 127 | assert.Equal(t, domain.ACMEChallengeHTTP01, issuer.cfg.Challenge) | ||
| 103 | } | 128 | } | ||
| 104 | 129 | ||||
| 130 | + | func TestCloudflareDNSProviderConfigUsesDNSSettings(t *testing.T) { | |||
| 131 | + | cfg := Config{ | |||
| 132 | + | Token: "token", | |||
| 133 | + | DNSPropagationTimeout: 7 * time.Minute, | |||
| 134 | + | DNSPollingInterval: 11 * time.Second, | |||
| 135 | + | } | |||
| 136 | + | ||||
| 137 | + | cfCfg := newCloudflareDNSProviderConfig(cfg) | |||
| 138 | + | ||||
| 139 | + | assert.Equal(t, "token", cfCfg.AuthToken) | |||
| 140 | + | assert.Equal(t, 7*time.Minute, cfCfg.PropagationTimeout) | |||
| 141 | + | assert.Equal(t, 11*time.Second, cfCfg.PollingInterval) | |||
| 142 | + | } | |||
| 143 | + | ||||
| 105 | func TestPrivateKeyRoundTrip(t *testing.T) { | 144 | func TestPrivateKeyRoundTrip(t *testing.T) { | ||
| 106 | // Generate an ECDSA P-256 private key | 145 | // Generate an ECDSA P-256 private key | ||
| 107 | privateKey, err := certcrypto.GeneratePrivateKey(certcrypto.EC256) | 146 | privateKey, err := certcrypto.GeneratePrivateKey(certcrypto.EC256) | ||
A internal/app/dns_config_test.go +31 -0
| @@ -0,0 +1,31 @@ | |||
| 1 | + | package app | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "testing" | |
| 5 | + | "time" | |
| 6 | + | ||
| 7 | + | "github.com/stretchr/testify/assert" | |
| 8 | + | "github.com/stretchr/testify/require" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | func TestBuildDNSConfigFromConfig(t *testing.T) { | |
| 12 | + | cfg := Config{} | |
| 13 | + | cfg.DNS.Resolvers = []string{"9.9.9.9:53", "1.1.1.1:53"} | |
| 14 | + | cfg.DNS.PropagationTimeout = "10m" | |
| 15 | + | cfg.DNS.PollingInterval = "10s" | |
| 16 | + | ||
| 17 | + | dnsCfg, err := buildDNSConfig(cfg) | |
| 18 | + | require.NoError(t, err) | |
| 19 | + | assert.Equal(t, []string{"9.9.9.9:53", "1.1.1.1:53"}, dnsCfg.Resolvers) | |
| 20 | + | assert.Equal(t, 10*time.Minute, dnsCfg.PropagationTimeout) | |
| 21 | + | assert.Equal(t, 10*time.Second, dnsCfg.PollingInterval) | |
| 22 | + | } | |
| 23 | + | ||
| 24 | + | func TestBuildDNSConfigRejectsInvalidDuration(t *testing.T) { | |
| 25 | + | cfg := Config{} | |
| 26 | + | cfg.DNS.PropagationTimeout = "not-a-duration" | |
| 27 | + | ||
| 28 | + | _, err := buildDNSConfig(cfg) | |
| 29 | + | require.Error(t, err) | |
| 30 | + | assert.Contains(t, err.Error(), "dns.propagation_timeout") | |
| 31 | + | } | |
| @@ -0,0 +1,31 @@ | |||||
| 1 | + | package app | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "testing" | |||
| 5 | + | "time" | |||
| 6 | + | ||||
| 7 | + | "github.com/stretchr/testify/assert" | |||
| 8 | + | "github.com/stretchr/testify/require" | |||
| 9 | + | ) | |||
| 10 | + | ||||
| 11 | + | func TestBuildDNSConfigFromConfig(t *testing.T) { | |||
| 12 | + | cfg := Config{} | |||
| 13 | + | cfg.DNS.Resolvers = []string{"9.9.9.9:53", "1.1.1.1:53"} | |||
| 14 | + | cfg.DNS.PropagationTimeout = "10m" | |||
| 15 | + | cfg.DNS.PollingInterval = "10s" | |||
| 16 | + | ||||
| 17 | + | dnsCfg, err := buildDNSConfig(cfg) | |||
| 18 | + | require.NoError(t, err) | |||
| 19 | + | assert.Equal(t, []string{"9.9.9.9:53", "1.1.1.1:53"}, dnsCfg.Resolvers) | |||
| 20 | + | assert.Equal(t, 10*time.Minute, dnsCfg.PropagationTimeout) | |||
| 21 | + | assert.Equal(t, 10*time.Second, dnsCfg.PollingInterval) | |||
| 22 | + | } | |||
| 23 | + | ||||
| 24 | + | func TestBuildDNSConfigRejectsInvalidDuration(t *testing.T) { | |||
| 25 | + | cfg := Config{} | |||
| 26 | + | cfg.DNS.PropagationTimeout = "not-a-duration" | |||
| 27 | + | ||||
| 28 | + | _, err := buildDNSConfig(cfg) | |||
| 29 | + | require.Error(t, err) | |||
| 30 | + | assert.Contains(t, err.Error(), "dns.propagation_timeout") | |||
| 31 | + | } | |||
M internal/app/run.go +14 -5
| @@ -553,6 +553,11 @@ func (si *serviceInit) initPublicTLS() error { | |||
| 553 | 553 | ctx := si.ctx | |
| 554 | 554 | log := si.log | |
| 555 | 555 | ||
| 556 | + | dnsCfg, err := buildDNSConfig(si.cfg) | |
| 557 | + | if err != nil { | |
| 558 | + | return log.WrapErr(err, "invalid DNS configuration") | |
| 559 | + | } | |
| 560 | + | ||
| 556 | 561 | publicTLSCfg := publictls.Config{ | |
| 557 | 562 | Enabled: si.cfg.TLS.ACME.Enabled, | |
| 558 | 563 | Email: si.cfg.TLS.ACME.Email, | |
| @@ -561,6 +566,7 @@ func (si *serviceInit) initPublicTLS() error { | |||
| 561 | 566 | TLSPort: si.cfg.Server.TLSPort, | |
| 562 | 567 | DataDir: resolveDataDir(si.cfg.Server.DataDir), | |
| 563 | 568 | ObtainBatchSize: si.cfg.TLS.ACME.ObtainBatchSize, | |
| 569 | + | DNS: dnsCfg, | |
| 564 | 570 | } | |
| 565 | 571 | ||
| 566 | 572 | tokenResolver := secrets.NewPublicTLSResolver(secrets.PublicTLSResolverConfig{}) | |
| @@ -583,11 +589,14 @@ func (si *serviceInit) initPublicTLS() error { | |||
| 583 | 589 | } | |
| 584 | 590 | ||
| 585 | 591 | issuer, err := acmelego.NewIssuer(acmelego.Config{ | |
| 586 | - | Email: si.cfg.TLS.ACME.Email, | |
| 587 | - | Challenge: effective.Mode, | |
| 588 | - | Token: effective.Token, | |
| 589 | - | Store: store, | |
| 590 | - | HTTPChallengeSink: challenges, | |
| 592 | + | Email: si.cfg.TLS.ACME.Email, | |
| 593 | + | Challenge: effective.Mode, | |
| 594 | + | Token: effective.Token, | |
| 595 | + | Store: store, | |
| 596 | + | HTTPChallengeSink: challenges, | |
| 597 | + | DNSResolvers: publicTLSCfg.DNS.Resolvers, | |
| 598 | + | DNSPropagationTimeout: publicTLSCfg.DNS.PropagationTimeout, | |
| 599 | + | DNSPollingInterval: publicTLSCfg.DNS.PollingInterval, | |
| 591 | 600 | }) | |
| 592 | 601 | if err != nil { | |
| 593 | 602 | return log.WrapErr(err, "create ACME issuer") | |
| @@ -553,6 +553,11 @@ func (si *serviceInit) initPublicTLS() error { | |||||
| 553 | ctx := si.ctx | 553 | ctx := si.ctx | ||
| 554 | log := si.log | 554 | log := si.log | ||
| 555 | 555 | ||||
| 556 | + | dnsCfg, err := buildDNSConfig(si.cfg) | |||
| 557 | + | if err != nil { | |||
| 558 | + | return log.WrapErr(err, "invalid DNS configuration") | |||
| 559 | + | } | |||
| 560 | + | ||||
| 556 | publicTLSCfg := publictls.Config{ | 561 | publicTLSCfg := publictls.Config{ | ||
| 557 | Enabled: si.cfg.TLS.ACME.Enabled, | 562 | Enabled: si.cfg.TLS.ACME.Enabled, | ||
| 558 | Email: si.cfg.TLS.ACME.Email, | 563 | Email: si.cfg.TLS.ACME.Email, | ||
| @@ -561,6 +566,7 @@ func (si *serviceInit) initPublicTLS() error { | |||||
| 561 | TLSPort: si.cfg.Server.TLSPort, | 566 | TLSPort: si.cfg.Server.TLSPort, | ||
| 562 | DataDir: resolveDataDir(si.cfg.Server.DataDir), | 567 | DataDir: resolveDataDir(si.cfg.Server.DataDir), | ||
| 563 | ObtainBatchSize: si.cfg.TLS.ACME.ObtainBatchSize, | 568 | ObtainBatchSize: si.cfg.TLS.ACME.ObtainBatchSize, | ||
| 569 | + | DNS: dnsCfg, | |||
| 564 | } | 570 | } | ||
| 565 | 571 | ||||
| 566 | tokenResolver := secrets.NewPublicTLSResolver(secrets.PublicTLSResolverConfig{}) | 572 | tokenResolver := secrets.NewPublicTLSResolver(secrets.PublicTLSResolverConfig{}) | ||
| @@ -583,11 +589,14 @@ func (si *serviceInit) initPublicTLS() error { | |||||
| 583 | } | 589 | } | ||
| 584 | 590 | ||||
| 585 | issuer, err := acmelego.NewIssuer(acmelego.Config{ | 591 | issuer, err := acmelego.NewIssuer(acmelego.Config{ | ||
| 586 | - | Email: si.cfg.TLS.ACME.Email, | 592 | + | Email: si.cfg.TLS.ACME.Email, |
| 587 | - | Challenge: effective.Mode, | 593 | + | Challenge: effective.Mode, |
| 588 | - | Token: effective.Token, | 594 | + | Token: effective.Token, |
| 589 | - | Store: store, | 595 | + | Store: store, |
| 590 | - | HTTPChallengeSink: challenges, | 596 | + | HTTPChallengeSink: challenges, |
| 597 | + | DNSResolvers: publicTLSCfg.DNS.Resolvers, | |||
| 598 | + | DNSPropagationTimeout: publicTLSCfg.DNS.PropagationTimeout, | |||
| 599 | + | DNSPollingInterval: publicTLSCfg.DNS.PollingInterval, | |||
| 591 | }) | 600 | }) | ||
| 592 | if err != nil { | 601 | if err != nil { | ||
| 593 | return log.WrapErr(err, "create ACME issuer") | 602 | return log.WrapErr(err, "create ACME issuer") | ||