[pve-devel] [Patch V2 acme 11/12] Add DNSChallenge Plugin

Fabian Grünbichler f.gruenbichler at proxmox.com
Wed Apr 1 15:29:06 CEST 2020


On March 31, 2020 12:08 pm, Wolfgang Link wrote:
> This plugin calls the custom script acme.sh and uses the implementation of the DNS API.
> 
> Signed-off-by: Wolfgang Link <w.link at proxmox.com>
> ---
>  debian/control               |   3 +-
>  src/Makefile                 |   1 +
>  src/PVE/ACME.pm              |   1 +
>  src/PVE/ACME/DNSChallenge.pm | 197 +++++++++++++++++++++++++++++++++++
>  4 files changed, 201 insertions(+), 1 deletion(-)
>  create mode 100644 src/PVE/ACME/DNSChallenge.pm
> 
> diff --git a/debian/control b/debian/control
> index 87ba731..bb85c98 100644
> --- a/debian/control
> +++ b/debian/control
> @@ -13,5 +13,6 @@ Description: easy and small shell script to automatically issue
>   and renew the free certificates from Let's Encrypt.
>  Depends: curl (>= 7.64.0-1),
>  	 coreutils (>= 8.30-1),
> -	 sed (>= 4.7-1)
> +	 sed (>= 4.7-1),
> +	 libpve-common-perl,

needs proper version after bump, since this takes over files and 
breaks+replaces the old one

>  Recommends: idn
> diff --git a/src/Makefile b/src/Makefile
> index c56a354..11b35ff 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -107,6 +107,7 @@ LIB_SOURCES = \
>  	ACME.pm \
>  	ACME/Challenge.pm \
>  	ACME/StandAlone.pm \
> +	ACME/DNSChallenge.pm \
>  
>  all:
>  
> diff --git a/src/PVE/ACME.pm b/src/PVE/ACME.pm
> index 7c0794a..86fb9b0 100644
> --- a/src/PVE/ACME.pm
> +++ b/src/PVE/ACME.pm
> @@ -25,6 +25,7 @@ file_get_contents
>  
>  use PVE::ACME::Challenge;
>  use PVE::ACME::StandAlone;
> +use PVE::ACME::DNSChallenge;
>  
>  Crypt::OpenSSL::RSA->import_random_seed();
>  
> diff --git a/src/PVE/ACME/DNSChallenge.pm b/src/PVE/ACME/DNSChallenge.pm
> new file mode 100644
> index 0000000..77d143f
> --- /dev/null
> +++ b/src/PVE/ACME/DNSChallenge.pm
> @@ -0,0 +1,197 @@
> +package PVE::ACME::DNSChallenge;
> +
> +use strict;
> +use warnings;
> +
> +use Digest::SHA qw(sha256);
> +use PVE::Tools;
> +
> +use base qw(PVE::ACME::Challenge);
> +
> +my $ACME_PATH = '/usr/share/proxmox-ve/proxmox-acme/proxmox-acme';
> +
> +sub supported_challenge_types {
> +    return { 'dns-01' => 1 };
> +}
> +
> +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',
> +];
> +
> +sub properties {
> +    return {
> +	api => {
> +	    description => "API plugin name",
> +	    type => 'string',
> +	    enum => $api_name_list,
> +	},
> +	data => {
> +	    type => 'string',
> +	    description => 'DNS plugin data.',
> +	},
> +    };
> +}
> +
> +sub options {
> +    return {
> +	api => {},
> +	data => {},
> +	nodes => { optional => 1 },
> +	disable => { optional => 1 },
> +    };
> +}
> +
> +my $outfunc = sub {
> +    my $line = shift;
> +    print "$line\n";
> +};
> +
> +# The order of the parameters passed to proxmox-acme is important
> +# proxmox-acme setup $plugin [$domain|$alias] $txtvalue $plugin_conf_string
> +sub setup {
> +    my ($class, $acme, $authorization, $plugin) = @_;
> +
> +    my $plugin_conf_string = PVE::Tools::decode_text($plugin->{data});
> +
> +    my $dns_challenge =
> +	PVE::ACME::extract_challenge($authorization->{'challenges'}, "dns-01");
> +    my $url = $dns_challenge->{'url'};
> +
> +    my $domain = $plugin->{alias} ?
> +	$plugin->{'alias'} : $authorization->{'identifier'}->{'value'};
> +
> +    my $key_auth = $acme->key_authorization($dns_challenge->{'token'});
> +    my $txtvalue = PVE::ACME::encode(sha256($key_auth));
> +
> +    my $dns_plugin = $plugin->{api};
> +    my $cmd = ["bash", $ACME_PATH, "setup", $dns_plugin, $domain];
> +    push @$cmd, $txtvalue, $plugin_conf_string;
> +
> +    PVE::Tools::run_command($cmd, outfunc => $outfunc);

we probably want to run this with dropped privileges at least. it does 
not need access to anything in /etc/pve, just execute some general 
purpose binaries that are available to anyone.

> +    print "Add TXT record: _acme-challenge.$domain\n";
> +    my $self = {
> +	dnsplugin => $dns_plugin,
> +	domain => $domain,
> +	txtvalue => $txtvalue,
> +	plugin_conf_string => $plugin_conf_string,
> +	url => $url,
> +    };
> +
> +    return bless $self, $class;
> +}
> +
> +# The order of the parameters passed to proxmox-acme is important
> +# proxmox-acme teardown $plugin [$domain|$alias] $txtvalue $plugin_conf_string
> +sub teardown {
> +    my ($class) = @_;

this is not $class, but $self now since we need to call this on an 
instance returned by setup().

> +
> +    my $domain = $class->{domain};
> +    my $cmd = ["bash", "$ACME_PATH", "teardown",  $class->{dnsplugin}];
> +    push @$cmd, $domain, $class->{txtvalue}, $class->{plugin_conf_string};
> +    PVE::Tools::run_command($cmd, outfunc => $outfunc);

same as above applies here as well - we should really drop privileges 
here

> +    print "Remove TXT record: _acme-challenge.$domain\n";
> +}
> +
> +1;
> -- 
> 2.20.1
> 
> 
> _______________________________________________
> pve-devel mailing list
> pve-devel at pve.proxmox.com
> https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
> 
> 




More information about the pve-devel mailing list