pdns: optional custom API version (#2019)
Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
This commit is contained in:
parent
d263a28c64
commit
9c1a856b73
8 changed files with 45 additions and 25 deletions
|
@ -2078,6 +2078,7 @@ func displayDNSHelp(w io.Writer, name string) error {
|
||||||
ew.writeln()
|
ew.writeln()
|
||||||
|
|
||||||
ew.writeln(`Additional Configuration:`)
|
ew.writeln(`Additional Configuration:`)
|
||||||
|
ew.writeln(` - "PDNS_API_VERSION": Skip API version autodetection and use the provided version number.`)
|
||||||
ew.writeln(` - "PDNS_HTTP_TIMEOUT": API request timeout`)
|
ew.writeln(` - "PDNS_HTTP_TIMEOUT": API request timeout`)
|
||||||
ew.writeln(` - "PDNS_POLLING_INTERVAL": Time between DNS propagation check`)
|
ew.writeln(` - "PDNS_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||||
ew.writeln(` - "PDNS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
ew.writeln(` - "PDNS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||||
|
|
|
@ -49,6 +49,7 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
||||||
|
|
||||||
| Environment Variable Name | Description |
|
| Environment Variable Name | Description |
|
||||||
|--------------------------------|-------------|
|
|--------------------------------|-------------|
|
||||||
|
| `PDNS_API_VERSION` | Skip API version autodetection and use the provided version number. |
|
||||||
| `PDNS_HTTP_TIMEOUT` | API request timeout |
|
| `PDNS_HTTP_TIMEOUT` | API request timeout |
|
||||||
| `PDNS_POLLING_INTERVAL` | Time between DNS propagation check |
|
| `PDNS_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||||
| `PDNS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
| `PDNS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||||
|
@ -65,6 +66,7 @@ Tested and confirmed to work with PowerDNS authoritative server 3.4.8 and 4.0.1.
|
||||||
PowerDNS Notes:
|
PowerDNS Notes:
|
||||||
- PowerDNS API does not currently support SSL, therefore you should take care to ensure that traffic between lego and the PowerDNS API is over a trusted network, VPN etc.
|
- PowerDNS API does not currently support SSL, therefore you should take care to ensure that traffic between lego and the PowerDNS API is over a trusted network, VPN etc.
|
||||||
- In order to have the SOA serial automatically increment each time the `_acme-challenge` record is added/modified via the API, set `SOA-EDIT-API` to `INCEPTION-INCREMENT` for the zone in the `domainmetadata` table
|
- In order to have the SOA serial automatically increment each time the `_acme-challenge` record is added/modified via the API, set `SOA-EDIT-API` to `INCEPTION-INCREMENT` for the zone in the `domainmetadata` table
|
||||||
|
- Some PowerDNS servers doesn't have root API endpoints enabled and API version autodetection will not work. In that case version number can be defined using `PDNS_API_VERSION`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ USAGE:
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
--days value The number of days left on a certificate to renew it. (default: 0)
|
--days value The number of days left on a certificate to renew it. (default: 0)
|
||||||
--ari-enable Use the renewalInfo endpoint (draft-ietf-acme-ari-02) to check if a certificate should be renewed. (default: false)
|
--ari-enable Use the renewalInfo endpoint (draft-ietf-acme-ari) to check if a certificate should be renewed. (default: false)
|
||||||
--ari-wait-to-renew-duration value The maximum duration you're willing to sleep for a renewal time returned by the renewalInfo endpoint. (default: 0s)
|
--ari-wait-to-renew-duration value The maximum duration you're willing to sleep for a renewal time returned by the renewalInfo endpoint. (default: 0s)
|
||||||
--reuse-key Used to indicate you want to reuse your current private key for the new certificate. (default: false)
|
--reuse-key Used to indicate you want to reuse your current private key for the new certificate. (default: false)
|
||||||
--no-bundle Do not create a certificate bundle by adding the issuers certificate to the new certificate. (default: false)
|
--no-bundle Do not create a certificate bundle by adding the issuers certificate to the new certificate. (default: false)
|
||||||
|
|
|
@ -30,10 +30,11 @@ type Client struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a new Client.
|
// NewClient creates a new Client.
|
||||||
func NewClient(host *url.URL, serverName string, apiKey string) *Client {
|
func NewClient(host *url.URL, serverName string, apiVersion int, apiKey string) *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
serverName: serverName,
|
serverName: serverName,
|
||||||
apiKey: apiKey,
|
apiKey: apiKey,
|
||||||
|
apiVersion: apiVersion,
|
||||||
Host: host,
|
Host: host,
|
||||||
HTTPClient: &http.Client{Timeout: 5 * time.Second},
|
HTTPClient: &http.Client{Timeout: 5 * time.Second},
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ func setupTest(t *testing.T, method, pattern string, status int, file string) *C
|
||||||
|
|
||||||
serverURL, _ := url.Parse(server.URL)
|
serverURL, _ := url.Parse(server.URL)
|
||||||
|
|
||||||
client := NewClient(serverURL, "server", "secret")
|
client := NewClient(serverURL, "server", 0, "secret")
|
||||||
client.HTTPClient = server.Client()
|
client.HTTPClient = server.Client()
|
||||||
|
|
||||||
return client
|
return client
|
||||||
|
@ -151,8 +151,7 @@ func TestClient_joinPath(t *testing.T) {
|
||||||
host, err := url.Parse(test.baseURL)
|
host, err := url.Parse(test.baseURL)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client := NewClient(host, "test", "secret")
|
client := NewClient(host, "test", test.apiVersion, "secret")
|
||||||
client.apiVersion = test.apiVersion
|
|
||||||
|
|
||||||
endpoint := client.joinPath(test.uri)
|
endpoint := client.joinPath(test.uri)
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ const (
|
||||||
EnvAPIURL = envNamespace + "API_URL"
|
EnvAPIURL = envNamespace + "API_URL"
|
||||||
|
|
||||||
EnvTTL = envNamespace + "TTL"
|
EnvTTL = envNamespace + "TTL"
|
||||||
|
EnvAPIVersion = envNamespace + "API_VERSION"
|
||||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||||
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||||
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
||||||
|
@ -34,6 +35,7 @@ type Config struct {
|
||||||
APIKey string
|
APIKey string
|
||||||
Host *url.URL
|
Host *url.URL
|
||||||
ServerName string
|
ServerName string
|
||||||
|
APIVersion int
|
||||||
PropagationTimeout time.Duration
|
PropagationTimeout time.Duration
|
||||||
PollingInterval time.Duration
|
PollingInterval time.Duration
|
||||||
TTL int
|
TTL int
|
||||||
|
@ -43,10 +45,11 @@ type Config struct {
|
||||||
// NewDefaultConfig returns a default configuration for the DNSProvider.
|
// NewDefaultConfig returns a default configuration for the DNSProvider.
|
||||||
func NewDefaultConfig() *Config {
|
func NewDefaultConfig() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
|
ServerName: env.GetOrDefaultString(EnvServerName, "localhost"),
|
||||||
|
APIVersion: env.GetOrDefaultInt(EnvAPIVersion, 0),
|
||||||
TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
|
TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
|
||||||
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
|
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
|
||||||
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 2*time.Second),
|
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 2*time.Second),
|
||||||
ServerName: env.GetOrDefaultString(EnvServerName, "localhost"),
|
|
||||||
HTTPClient: &http.Client{
|
HTTPClient: &http.Client{
|
||||||
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
|
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
|
||||||
},
|
},
|
||||||
|
@ -94,11 +97,13 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
return nil, errors.New("pdns: API URL missing")
|
return nil, errors.New("pdns: API URL missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := internal.NewClient(config.Host, config.ServerName, config.APIKey)
|
client := internal.NewClient(config.Host, config.ServerName, config.APIVersion, config.APIKey)
|
||||||
|
|
||||||
err := client.SetAPIVersion(context.Background())
|
if config.APIVersion <= 0 {
|
||||||
if err != nil {
|
err := client.SetAPIVersion(context.Background())
|
||||||
log.Warnf("pdns: failed to get API version %v", err)
|
if err != nil {
|
||||||
|
log.Warnf("pdns: failed to get API version %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &DNSProvider{config: config, client: client}, nil
|
return &DNSProvider{config: config, client: client}, nil
|
||||||
|
|
|
@ -18,6 +18,7 @@ Tested and confirmed to work with PowerDNS authoritative server 3.4.8 and 4.0.1.
|
||||||
PowerDNS Notes:
|
PowerDNS Notes:
|
||||||
- PowerDNS API does not currently support SSL, therefore you should take care to ensure that traffic between lego and the PowerDNS API is over a trusted network, VPN etc.
|
- PowerDNS API does not currently support SSL, therefore you should take care to ensure that traffic between lego and the PowerDNS API is over a trusted network, VPN etc.
|
||||||
- In order to have the SOA serial automatically increment each time the `_acme-challenge` record is added/modified via the API, set `SOA-EDIT-API` to `INCEPTION-INCREMENT` for the zone in the `domainmetadata` table
|
- In order to have the SOA serial automatically increment each time the `_acme-challenge` record is added/modified via the API, set `SOA-EDIT-API` to `INCEPTION-INCREMENT` for the zone in the `domainmetadata` table
|
||||||
|
- Some PowerDNS servers doesn't have root API endpoints enabled and API version autodetection will not work. In that case version number can be defined using `PDNS_API_VERSION`.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
[Configuration]
|
[Configuration]
|
||||||
|
@ -25,11 +26,12 @@ PowerDNS Notes:
|
||||||
PDNS_API_KEY = "API key"
|
PDNS_API_KEY = "API key"
|
||||||
PDNS_API_URL = "API URL"
|
PDNS_API_URL = "API URL"
|
||||||
[Configuration.Additional]
|
[Configuration.Additional]
|
||||||
|
PDNS_SERVER_NAME = "Name of the server in the URL, 'localhost' by default"
|
||||||
|
PDNS_API_VERSION = "Skip API version autodetection and use the provided version number."
|
||||||
PDNS_POLLING_INTERVAL = "Time between DNS propagation check"
|
PDNS_POLLING_INTERVAL = "Time between DNS propagation check"
|
||||||
PDNS_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
PDNS_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
||||||
PDNS_TTL = "The TTL of the TXT record used for the DNS challenge"
|
PDNS_TTL = "The TTL of the TXT record used for the DNS challenge"
|
||||||
PDNS_HTTP_TIMEOUT = "API request timeout"
|
PDNS_HTTP_TIMEOUT = "API request timeout"
|
||||||
PDNS_SERVER_NAME = "Name of the server in the URL, 'localhost' by default"
|
|
||||||
|
|
||||||
[Links]
|
[Links]
|
||||||
API = "https://doc.powerdns.com/md/httpapi/README/"
|
API = "https://doc.powerdns.com/md/httpapi/README/"
|
||||||
|
|
|
@ -76,30 +76,31 @@ func TestNewDNSProvider(t *testing.T) {
|
||||||
|
|
||||||
func TestNewDNSProviderConfig(t *testing.T) {
|
func TestNewDNSProviderConfig(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
apiKey string
|
apiKey string
|
||||||
host *url.URL
|
customAPIVersion int
|
||||||
expected string
|
host *url.URL
|
||||||
|
expected string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "success",
|
desc: "success",
|
||||||
apiKey: "123",
|
apiKey: "123",
|
||||||
host: func() *url.URL {
|
host: mustParse("http://example.com"),
|
||||||
u, _ := url.Parse("http://example.com")
|
},
|
||||||
return u
|
{
|
||||||
}(),
|
desc: "success custom API version",
|
||||||
|
apiKey: "123",
|
||||||
|
customAPIVersion: 1,
|
||||||
|
host: mustParse("http://example.com"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "missing credentials",
|
desc: "missing credentials",
|
||||||
expected: "pdns: API key missing",
|
expected: "pdns: API key missing",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "missing API key",
|
desc: "missing API key",
|
||||||
apiKey: "",
|
apiKey: "",
|
||||||
host: func() *url.URL {
|
host: mustParse("http://example.com"),
|
||||||
u, _ := url.Parse("http://example.com")
|
|
||||||
return u
|
|
||||||
}(),
|
|
||||||
expected: "pdns: API key missing",
|
expected: "pdns: API key missing",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -114,6 +115,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
|
||||||
config := NewDefaultConfig()
|
config := NewDefaultConfig()
|
||||||
config.APIKey = test.apiKey
|
config.APIKey = test.apiKey
|
||||||
config.Host = test.host
|
config.Host = test.host
|
||||||
|
config.APIVersion = test.customAPIVersion
|
||||||
|
|
||||||
p, err := NewDNSProviderConfig(config)
|
p, err := NewDNSProviderConfig(config)
|
||||||
|
|
||||||
|
@ -143,3 +145,11 @@ func TestLivePresentAndCleanup(t *testing.T) {
|
||||||
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
|
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustParse(rawURL string) *url.URL {
|
||||||
|
u, err := url.Parse(rawURL)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue