.PHONY: install
install:
install -D -m 0744 proxmox-acme ${DESTDIR}${ACMEDIR}/proxmox-acme
+ install -D -m 0644 dns-challenge-schema.json ${DESTDIR}${ACMEDIR}/dns-challenge-schema.json
for f in ${ACME_SOURCES}; do install -D -m 0644 acme.sh/$$f ${DESTDIR}${ACMEDIR}/$$f; done
install -d -m 0755 ${DESTDIR}${PERLDIR}/PVE
install -d -m 0755 ${DESTDIR}${PERLDIR}/PVE/ACME
use warnings;
use Digest::SHA qw(sha256);
+use JSON;
+
use PVE::Tools;
use PVE::ACME;
return 'dns';
}
-# 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' => {
- name => 'acme-dns',
- fields => {
- 'ACMEDNS_UPDATE_URL' => {
- description => 'The API update endpoint',
- type => 'string',
- },
- 'ACMEDNS_USERNAME' => {
- description => 'The acme-dns user',
- type => 'string',
- },
- 'ACMEDNS_PASSWORD' => {
- description => 'The acme-dns password',
- type => 'string',
- },
- 'ACMEDNS_SUBDOMAIN' => {
- description => 'The subdomain you got from acme-dns registration',
- type => 'string',
- },
- },
- },
- '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' => {},
- 'aurora' => {
- name => 'AuroraDNS',
- fields => {
- 'AURORA_Key' => {
- description => 'The API Key',
- type => 'string',
- },
- 'AURORA_Secret' => {
- description => 'The API Secret',
- type => 'string',
- },
- },
- },
- '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',
- },
- },
- },
- 'ionos' => {},
- 'ispconfig' => {},
- 'jd' => {},
- 'joker' => {},
- 'kappernet' => {
- name => 'kapper.net',
- fields => {
- 'KAPPERNETDNS_Key' => {
- description => 'Your kapper.net API key',
- type => 'string',
- },
- 'KAPPERNETDNS_Secret' => {
- description => 'Your kapper.net API secret',
- type => 'string',
- },
- },
- },
- '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' => {},
- 'porkbun' => {
- name => 'Porkbun',
- fields => {
- 'PORKBUN_API_KEY' => {
- description => 'The API Key',
- type => 'string',
- },
- 'PORKBUN_SECRET_API_KEY' => {
- description => 'The API Secret',
- type => 'string',
- },
- },
- },
- 'rackcorp' => {},
- 'rackspace' => {},
- 'rcode0' => {},
- 'regru' => {},
- 'scaleway' => {},
- 'schlundtech' => {},
- 'selectel' => {},
- 'servercow' => {},
- 'simply' => {},
- 'tele3' => {},
- 'transip' => {},
- 'ultra' => {},
- 'unoeuro' => {},
- 'variomedia' => {},
- 'vscale' => {},
- 'vultr' => {},
- 'world4you' => {
- name => 'World4You',
- fields => {
- 'WORLD4YOU_USERNAME' => {
- description => "The World4You customer id or package id",
- type => 'string',
- },
- 'WORLD4YOU_PASSWORD' => {
- description => "The World4You password",
- type => 'string',
- },
- },
- },
- 'websupport' => {},
- 'yandex' => {},
- 'zilore' => {},
- 'zone' => {},
- 'zonomi' => {},
-};
+my $DNS_API_CHALLENGE_SCHEMA_FN = '/usr/share/proxmox-acme/dns-challenge-schema.json';
+my $plugins = from_json(PVE::Tools::file_get_contents($DNS_API_CHALLENGE_SCHEMA_FN));
sub get_supported_plugins {
return $plugins;
--- /dev/null
+Introduction
+------------
+
+Promxox projects (PVE, PMG, PBS) all support ACME with DNS challenges.
+As there are many DNS providers we re-use the plugins for the great [acme.sh]
+project.
+
+As a user interface needs to know which plugins there are supported we need to
+provide at least the list of known ones.
+But, we extend that and return a full JSON-Schema oriented Object Schema, so
+that any user-interface can use that to show UX hints and create the respective
+inputs for each plugin.
+
+Note, we do not define a full schema for all plugins, but accept patches for
+adding one. See the [developer-documentation] about how to do so.
+
+We use JSON as format as we need this schema in both, perl and rust based
+projects.
+
+Schema Example
+--------------
+
+A entry describing the data schema of a supported plugin could look like:
+
+```
+'dnsprovider' => {
+ name => 'Full name of Plugin',
+ fields => {
+ 'FOO_API_KEY' => {
+ description => "The API key",
+ default => "none",
+ optional => 1,
+ type => 'string',
+ },
+ ...
+ },
+},
+```
+
+References
+----------
+
+[acme.sh]: https://acme.sh/
+[developer-documentation]: https://pve.proxmox.com/wiki/Developer_Documentation
--- /dev/null
+{
+ "1984hosting" : {},
+ "acmedns" : {
+ "fields" : {
+ "ACMEDNS_PASSWORD" : {
+ "description" : "The acme-dns password",
+ "type" : "string"
+ },
+ "ACMEDNS_SUBDOMAIN" : {
+ "description" : "The subdomain you got from acme-dns registration",
+ "type" : "string"
+ },
+ "ACMEDNS_UPDATE_URL" : {
+ "description" : "The API update endpoint",
+ "type" : "string"
+ },
+ "ACMEDNS_USERNAME" : {
+ "description" : "The acme-dns user",
+ "type" : "string"
+ }
+ },
+ "name" : "acme-dns"
+ },
+ "acmeproxy" : {},
+ "active24" : {
+ "fields" : {
+ "ACTIVE24_Token" : {
+ "description" : "The API key",
+ "type" : "string"
+ }
+ },
+ "name" : "Active24"
+ },
+ "ad" : {
+ "fields" : {
+ "AD_API_KEY" : {
+ "description" : "The API key",
+ "type" : "string"
+ }
+ },
+ "name" : "Alwaysdata"
+ },
+ "ali" : {
+ "fields" : {
+ "Ali_API" : {
+ "default" : "https://alidns.aliyuncs.com/",
+ "description" : "The API endpoint",
+ "optional" : 1,
+ "type" : "string"
+ },
+ "Ali_Key" : {
+ "description" : "The API Key",
+ "type" : "string"
+ },
+ "Ali_Secret" : {
+ "description" : "The API Secret",
+ "type" : "string"
+ }
+ },
+ "name" : "Alibaba Cloud DNS"
+ },
+ "anx" : {},
+ "arvan" : {},
+ "aurora" : {
+ "fields" : {
+ "AURORA_Key" : {
+ "description" : "The API Key",
+ "type" : "string"
+ },
+ "AURORA_Secret" : {
+ "description" : "The API Secret",
+ "type" : "string"
+ }
+ },
+ "name" : "AuroraDNS"
+ },
+ "autodns" : {},
+ "aws" : {
+ "fields" : {
+ "AWS_ACCESS_KEY_ID" : {
+ "description" : "The AWS access-key ID",
+ "name" : "ACCESS_KEY_ID",
+ "type" : "string"
+ },
+ "AWS_SECRET_ACCESS_KEY" : {
+ "description" : "The AWS access-key secret",
+ "name" : "SECRET_ACCESS_KEY",
+ "type" : "string"
+ }
+ },
+ "name" : "Amazon Route53 (AWS)"
+ },
+ "azure" : {},
+ "cf" : {
+ "description" : "Either provide global account key and email, or CF API token and Account ID.",
+ "fields" : {
+ "CF_Account_ID" : {
+ "description" : "The new Cloudflare API Account ID",
+ "type" : "string"
+ },
+ "CF_Email" : {
+ "description" : "The Cloudflare Account EMail-Address",
+ "type" : "string"
+ },
+ "CF_Key" : {
+ "description" : "The Cloudflare Global API Key",
+ "type" : "string"
+ },
+ "CF_Token" : {
+ "description" : "The new Cloudflare API Token",
+ "type" : "string"
+ },
+ "CF_Zone_ID" : {
+ "description" : "For Zone restricted API Token",
+ "type" : "string"
+ }
+ },
+ "name" : "Cloudflare Managed DNS"
+ },
+ "clouddns" : {},
+ "cloudns" : {},
+ "cn" : {},
+ "conoha" : {},
+ "constellix" : {},
+ "cx" : {},
+ "cyon" : {},
+ "da" : {},
+ "ddnss" : {},
+ "desec" : {},
+ "df" : {},
+ "dgon" : {
+ "fields" : {
+ "DO_API_KEY" : {
+ "description" : "The DigitalOcean API Key",
+ "type" : "string"
+ }
+ },
+ "name" : "DigitalOcean DNS"
+ },
+ "dnsimple" : {},
+ "do" : {},
+ "doapi" : {},
+ "domeneshop" : {},
+ "dp" : {},
+ "dpi" : {},
+ "dreamhost" : {},
+ "duckdns" : {},
+ "durabledns" : {},
+ "dyn" : {},
+ "dynu" : {},
+ "dynv6" : {},
+ "easydns" : {},
+ "edgedns" : {},
+ "euserv" : {},
+ "exoscale" : {},
+ "freedns" : {},
+ "gandi_livedns" : {},
+ "gcloud" : {},
+ "gd" : {
+ "fields" : {
+ "GD_Key" : {
+ "description" : "The GoDaddy API Key",
+ "type" : "string"
+ },
+ "GD_Secret" : {
+ "description" : "The GoDaddy API Secret",
+ "type" : "string"
+ }
+ },
+ "name" : "GoDaddy"
+ },
+ "gdnsdk" : {},
+ "he" : {},
+ "hetzner" : {},
+ "hexonet" : {},
+ "hostingde" : {},
+ "huaweicloud" : {},
+ "infoblox" : {},
+ "infomaniak" : {},
+ "internetbs" : {},
+ "inwx" : {
+ "fields" : {
+ "INWX_Password" : {
+ "description" : "The INWX password",
+ "type" : "string"
+ },
+ "INWX_User" : {
+ "description" : "The INWX username",
+ "type" : "string"
+ }
+ },
+ "name" : "INWX"
+ },
+ "ionos" : {},
+ "ispconfig" : {},
+ "jd" : {},
+ "joker" : {},
+ "kappernet" : {
+ "fields" : {
+ "KAPPERNETDNS_Key" : {
+ "description" : "Your kapper.net API key",
+ "type" : "string"
+ },
+ "KAPPERNETDNS_Secret" : {
+ "description" : "Your kapper.net API secret",
+ "type" : "string"
+ }
+ },
+ "name" : "kapper.net"
+ },
+ "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" : {
+ "fields" : {
+ "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"
+ },
+ "OVH_END_POINT" : {
+ "default" : "ovh-eu",
+ "description" : "The OVH endpoint",
+ "optional" : 1,
+ "type" : "string"
+ }
+ },
+ "name" : "OVH"
+ },
+ "pdns" : {
+ "fields" : {
+ "PDNS_ServerId" : {
+ "type" : "string"
+ },
+ "PDNS_Token" : {
+ "type" : "string"
+ },
+ "PDNS_Ttl" : {
+ "type" : "integer"
+ },
+ "PDNS_Url" : {
+ "description" : "The PowerDNS API endpoint.",
+ "type" : "string"
+ }
+ },
+ "name" : "PowerDNS server"
+ },
+ "pleskxml" : {},
+ "pointhq" : {},
+ "porkbun" : {
+ "fields" : {
+ "PORKBUN_API_KEY" : {
+ "description" : "The API Key",
+ "type" : "string"
+ },
+ "PORKBUN_SECRET_API_KEY" : {
+ "description" : "The API Secret",
+ "type" : "string"
+ }
+ },
+ "name" : "Porkbun"
+ },
+ "rackcorp" : {},
+ "rackspace" : {},
+ "rcode0" : {},
+ "regru" : {},
+ "scaleway" : {},
+ "schlundtech" : {},
+ "selectel" : {},
+ "servercow" : {},
+ "simply" : {},
+ "tele3" : {},
+ "transip" : {},
+ "ultra" : {},
+ "unoeuro" : {},
+ "variomedia" : {},
+ "vscale" : {},
+ "vultr" : {},
+ "websupport" : {},
+ "world4you" : {
+ "fields" : {
+ "WORLD4YOU_PASSWORD" : {
+ "description" : "The World4You password",
+ "type" : "string"
+ },
+ "WORLD4YOU_USERNAME" : {
+ "description" : "The World4You customer id or package id",
+ "type" : "string"
+ }
+ },
+ "name" : "World4You"
+ },
+ "yandex" : {},
+ "zilore" : {},
+ "zone" : {},
+ "zonomi" : {}
+}
use lib '../';
-use PVE::Tools qw(dir_glob_foreach);
-use PVE::ACME::DNSChallenge;
+use JSON;
+
+use PVE::Tools qw(dir_glob_foreach file_get_contents);
my $dnsapi_path = '../acme.sh/dnsapi';
push @$acmesh_plugins, $provider;
});
-my $ok = 1;
-my $defined_plugins = PVE::ACME::DNSChallenge::get_supported_plugins();
+my $DNS_API_CHALLENGE_SCHEMA_FN = '../dns-challenge-schema.json';
+my $defined_plugins = from_json(PVE::Tools::file_get_contents($DNS_API_CHALLENGE_SCHEMA_FN));
+my $ok = 1;
# first check for missing ones, delete from hash so we can easily see if a plug got removed/renamed
my $printed_missing = 0;
for my $provider (sort @$acmesh_plugins) {