]> git.proxmox.com Git - proxmox-acme.git/blobdiff - src/PVE/ACME/DNSChallenge.pm
dns challenge: add missing plugins to schema
[proxmox-acme.git] / src / PVE / ACME / DNSChallenge.pm
index dec57a6b461c9178a8d556b9e997b25799ec6e34..2d20ffb8c51c927b32a9b919eccbbfd84c1dcec1 100644 (file)
@@ -18,119 +18,308 @@ sub type {
     return 'dns';
 }
 
-my $api_name_list = [
-    'acmedns',
-    'acmeproxy',
-    'active24',
-    'ad',
-    'ali',
-    'autodns',
-    'aws',
-    'azure',
-    'cf',
-    'clouddns',
-    'cloudns',
-    'cn',
-    'conoha',
-    'constellix',
-    'cx',
-    'cyon',
-    'da',
-    'ddnss',
-    'desec',
-    'dgon',
-    'dnsimple',
-    'do',
-    'doapi',
-    'domeneshop',
-    'dp',
-    'dpi',
-    'dreamhost',
-    'duckdns',
-    'durabledns',
-    'dyn',
-    'dynu',
-    'dynv6',
-    'easydns',
-    'euserv',
-    'exoscale',
-    'freedns',
-    'gandi_livedns',
-    'gcloud',
-    'gd',
-    'gdnsdk',
-    'he',
-    'hexonet',
-    'hostingde',
-    'infoblox',
-    'internetbs',
-    'inwx',
-    'ispconfig',
-    'jd',
-    'kas',
-    'kinghost',
-    'knot',
-    'leaseweb',
-    'lexicon',
-    'linode',
-    'linode_v4',
-    'loopia',
-    'lua',
-    'maradns',
-    'me',
-    'miab',
-    'misaka',
-    'myapi',
-    'mydevil',
-    'mydnsjp',
-    'namecheap',
-    'namecom',
-    'namesilo',
-    'nederhost',
-    'neodigit',
-    'netcup',
-    'nic',
-    'nsd',
-    'nsone',
-    'nsupdate',
-    'nw',
-    'one',
-    'online',
-    'openprovider',
-    'opnsense',
-    'ovh',
-    'pdns',
-    'pleskxml',
-    'pointhq',
-    'rackspace',
-    'rcode0',
-    'regru',
-    'schlundtech',
-    'selectel',
-    'servercow',
-    'tele3',
-    'ultra',
-    'unoeuro',
-    'variomedia',
-    'vscale',
-    'vultr',
-    'yandex',
-    'zilore',
-    'zone',
-    'zonomi',
-];
+# describe the data schema of the supported plugins, e.g.:
+#    'dnsprovider' => {
+#      name => 'Full name of Plugin',
+#      fields => {
+#          'FOO_API_KEY' => {
+#              description => "The API key",
+#              default => "none",
+#              optional => 1,
+#              type => 'string',
+#          },
+#          # ...
+#      },
+#    },
+my $plugins = {
+    '1984hosting' => {},
+    'acmedns' => {},
+    'acmeproxy' => {},
+    'active24' => {
+       name => 'Active24',
+       fields => {
+           'ACTIVE24_Token' => {
+               description => "The API key",
+               type => 'string',
+           },
+       },
+    },
+    'ad' => {
+       name => 'Alwaysdata',
+       fields => {
+           'AD_API_KEY' => {
+               description => "The API key",
+               type => 'string',
+           },
+       },
+    },
+    'ali' => {
+       name => 'Alibaba Cloud DNS',
+       fields => {
+           'Ali_API' => {
+               description => 'The API endpoint',
+               default => "https://alidns.aliyuncs.com/",
+               type => 'string',
+               optional => 1,
+           },
+           'Ali_Key' => {
+               description => 'The API Key',
+               type => 'string',
+           },
+           'Ali_Secret' => {
+               description => 'The API Secret',
+               type => 'string',
+           },
+       },
+    },
+    'anx' => {},
+    'arvan' => {},
+    'autodns' => {},
+    'aws' => {
+       name => 'Amazon Route53 (AWS)',
+       fields => {
+           'AWS_ACCESS_KEY_ID' => {
+               name => 'ACCESS_KEY_ID',
+               description => 'The AWS access-key ID',
+               type => 'string',
+           },
+           'AWS_SECRET_ACCESS_KEY' => {
+               name => 'SECRET_ACCESS_KEY',
+               description => 'The AWS access-key secret',
+               type => 'string',
+           },
+       },
+    },
+    'azure' => {},
+    'cf' => {
+       name => 'Cloudflare Managed DNS',
+       description => 'Either provide global account key and email, or CF API token and Account ID.',
+       fields => {
+           'CF_Key' => {
+               description => 'The Cloudflare Global API Key',
+               type => 'string',
+           },
+           'CF_Email' => {
+               description => 'The Cloudflare Account EMail-Address',
+               type => 'string',
+           },
+           'CF_Token' => {
+               description => 'The new Cloudflare API Token',
+               type => 'string',
+           },
+           'CF_Account_ID' => {
+               description => 'The new Cloudflare API Account ID',
+               type => 'string',
+           },
+           'CF_Zone_ID' => {
+               description => 'For Zone restricted API Token',
+               type => 'string',
+           },
+       },
+    },
+    'clouddns' => {},
+    'cloudns' => {},
+    'cn' => {},
+    'conoha' => {},
+    'constellix' => {},
+    'cx' => {},
+    'cyon' => {},
+    'da' => {},
+    'ddnss' => {},
+    'desec' => {},
+    'df' => {},
+    'dgon' => {
+       name => 'DigitalOcean DNS',
+       fields => {
+           'DO_API_KEY' => {
+               description => 'The DigitalOcean API Key',
+               type => 'string',
+           },
+       },
+    },
+    'dnsimple' => {},
+    'do' => {},
+    'doapi' => {},
+    'domeneshop' => {},
+    'dp' => {},
+    'dpi' => {},
+    'dreamhost' => {},
+    'duckdns' => {},
+    'durabledns' => {},
+    'dyn' => {},
+    'dynu' => {},
+    'dynv6' => {},
+    'easydns' => {},
+    'edgedns' => {},
+    'euserv' => {},
+    'exoscale' => {},
+    'freedns' => {},
+    'gandi_livedns' => {},
+    'gcloud' => {},
+    'gd' => {
+       name => 'GoDaddy',
+       fields => {
+           'GD_Key' => {
+               description => 'The GoDaddy API Key',
+               type => 'string',
+           },
+           'GD_Secret' => {
+               description => 'The GoDaddy API Secret',
+               type => 'string',
+           },
+       },
+    },
+    'gdnsdk' => {},
+    'he' => {},
+    'hetzner' => {},
+    'hexonet' => {},
+    'hostingde' => {},
+    'huaweicloud' => {},
+    'infoblox' => {},
+    'infomaniak' => {},
+    'internetbs' => {},
+    'inwx' => {
+       name => 'INWX',
+       fields => {
+           'INWX_User' => {
+               description => 'The INWX username',
+               type => 'string',
+           },
+           'INWX_Password' => {
+               description => 'The INWX password',
+               type => 'string',
+           },
+       },
+    },
+    'ispconfig' => {},
+    'jd' => {},
+    'joker' => {},
+    'kappernet' => {},
+    'kas' => {},
+    'kinghost' => {},
+    'knot' => {},
+    'leaseweb' => {},
+    'lexicon' => {},
+    'linode' => {},
+    'linode_v4' => {},
+    'loopia' => {},
+    'lua' => {},
+    'maradns' => {},
+    'me' => {},
+    'miab' => {},
+    'misaka' => {},
+    'myapi' => {},
+    'mydevil' => {},
+    'mydnsjp' => {},
+    'namecheap' => {},
+    'namecom' => {},
+    'namesilo' => {},
+    'nederhost' => {},
+    'neodigit' => {},
+    'netcup' => {},
+    'netlify' => {},
+    'nic' => {},
+    'njalla' => {},
+    'nm' => {},
+    'nsd' => {},
+    'nsone' => {},
+    'nsupdate' => {},
+    'nw' => {},
+    'one' => {},
+    'online' => {},
+    'openprovider' => {},
+    'openstack' => {},
+    'opnsense' => {},
+    'ovh' => {
+       name => 'OVH',
+       fields => {
+           'OVH_END_POINT' => {
+               description => "The OVH endpoint",
+               default => "ovh-eu",
+               optional => 1,
+               type => 'string',
+           },
+           'OVH_AK' => {
+               description => "The application key.",
+               type => 'string',
+           },
+           'OVH_AS' => {
+               description => "The application secret.",
+               type => 'string',
+           },
+           'OVH_CK' => {
+               description => "The consumer key.",
+               optional => 1,
+               type => 'string',
+           },
+       },
+    },
+    'pdns' => {
+       name => 'PowerDNS server',
+       fields => {
+           'PDNS_Url' => {
+               description => "The PowerDNS API endpoint.",
+               type => 'string',
+           },
+           'PDNS_ServerId'=> {
+               type => 'string',
+           },
+           'PDNS_Token'=> {
+               type => 'string',
+           },
+           'PDNS_Ttl'=> {
+               type => 'integer',
+           },
+       },
+    },
+    'pleskxml' => {},
+    'pointhq' => {},
+    'rackspace' => {},
+    'rcode0' => {},
+    'regru' => {},
+    'schlundtech' => {},
+    'selectel' => {},
+    'servercow' => {},
+    'tele3' => {},
+    'transip' => {},
+    'ultra' => {},
+    'unoeuro' => {},
+    'variomedia' => {},
+    'vscale' => {},
+    'vultr' => {},
+    'world4you' => {},
+    'yandex' => {},
+    'zilore' => {},
+    'zone' => {},
+    'zonomi' => {},
+};
+
+sub get_supported_plugins {
+    return $plugins;
+}
 
 sub properties {
     return {
        api => {
            description => "API plugin name",
            type => 'string',
-           enum => $api_name_list,
+           enum => [sort keys %$plugins],
        },
        data => {
            type => 'string',
-           description => 'DNS plugin data.',
+           description => 'DNS plugin data. (base64 encoded)',
        },
+       'validation-delay' => {
+           type => 'integer',
+           description => 'Extra delay in seconds to wait before requesting validation.'
+               .' Allows to cope with a long TTL of DNS records.',
+           # low default, but our bet is that the acme-challenge domain isn't
+           # cached at all, so it hopefully shouldn't run into TTL issues
+           default => 30,
+           optional => 1,
+           minimum => 0,
+           maximum => 2 * 24 * 60 * 60,
+       }
     };
 }
 
@@ -140,6 +329,7 @@ sub options {
        data => { optional => 1 },
        nodes => { optional => 1 },
        disable => { optional => 1 },
+       'validation-delay' => { optional => 1 },
     };
 }
 
@@ -185,6 +375,12 @@ sub setup {
 
     my $domain = $proxmox_acme_command->($self, $acme, $auth, $data, 'setup');
     print "Add TXT record: _acme-challenge.$domain\n";
+
+    my $delay = $data->{plugin}->{'validation-delay'} // 30;
+    if ($delay > 0) {
+       print "Sleeping $delay seconds to wait for TXT record propagation\n";
+       sleep($delay); # don't care for EINTR
+    }
 }
 
 sub teardown {