]> git.proxmox.com Git - proxmox-acme.git/blob - src/PVE/ACME/DNSChallenge.pm
dns plugin: improve 'data' string encoding/passing
[proxmox-acme.git] / src / PVE / ACME / DNSChallenge.pm
1 package PVE::ACME::DNSChallenge;
2
3 use strict;
4 use warnings;
5
6 use Digest::SHA qw(sha256);
7 use PVE::Tools;
8
9 use base qw(PVE::ACME::Challenge);
10
11 my $ACME_PATH = '/usr/share/proxmox-acme/proxmox-acme';
12
13 sub supported_challenge_types {
14 return ["dns-01"];
15 }
16
17 sub type {
18 return 'dns';
19 }
20
21 my $api_name_list = [
22 'acmedns',
23 'acmeproxy',
24 'active24',
25 'ad',
26 'ali',
27 'autodns',
28 'aws',
29 'azure',
30 'cf',
31 'clouddns',
32 'cloudns',
33 'cn',
34 'conoha',
35 'constellix',
36 'cx',
37 'cyon',
38 'da',
39 'ddnss',
40 'desec',
41 'dgon',
42 'dnsimple',
43 'do',
44 'doapi',
45 'domeneshop',
46 'dp',
47 'dpi',
48 'dreamhost',
49 'duckdns',
50 'durabledns',
51 'dyn',
52 'dynu',
53 'dynv6',
54 'easydns',
55 'euserv',
56 'exoscale',
57 'freedns',
58 'gandi_livedns',
59 'gcloud',
60 'gd',
61 'gdnsdk',
62 'he',
63 'hexonet',
64 'hostingde',
65 'infoblox',
66 'internetbs',
67 'inwx',
68 'ispconfig',
69 'jd',
70 'kas',
71 'kinghost',
72 'knot',
73 'leaseweb',
74 'lexicon',
75 'linode',
76 'linode_v4',
77 'loopia',
78 'lua',
79 'maradns',
80 'me',
81 'miab',
82 'misaka',
83 'myapi',
84 'mydevil',
85 'mydnsjp',
86 'namecheap',
87 'namecom',
88 'namesilo',
89 'nederhost',
90 'neodigit',
91 'netcup',
92 'nic',
93 'nsd',
94 'nsone',
95 'nsupdate',
96 'nw',
97 'one',
98 'online',
99 'openprovider',
100 'opnsense',
101 'ovh',
102 'pdns',
103 'pleskxml',
104 'pointhq',
105 'rackspace',
106 'rcode0',
107 'regru',
108 'schlundtech',
109 'selectel',
110 'servercow',
111 'tele3',
112 'ultra',
113 'unoeuro',
114 'variomedia',
115 'vscale',
116 'vultr',
117 'yandex',
118 'zilore',
119 'zone',
120 'zonomi',
121 ];
122
123 sub properties {
124 return {
125 api => {
126 description => "API plugin name",
127 type => 'string',
128 enum => $api_name_list,
129 },
130 data => {
131 type => 'string',
132 description => 'DNS plugin data.',
133 },
134 };
135 }
136
137 sub options {
138 return {
139 api => {},
140 data => { optional => 1 },
141 nodes => { optional => 1 },
142 disable => { optional => 1 },
143 };
144 }
145
146 my $proxmox_acme_command = sub {
147 my ($self, $acme, $auth, $data, $action) = @_;
148
149 die "No plugin data for DNSChallenge\n" if !defined($data->{plugin});
150
151 my $alias = $data->{alias};
152 my $domain = $auth->{identifier}->{value};
153
154 my $challenge = $self->extract_challenge($auth->{challenges});
155 my $key_auth = $acme->key_authorization($challenge->{token});
156
157 my $txtvalue = PVE::ACME::encode(sha256($key_auth));
158 my $dnsplugin = $data->{plugin}->{api};
159 my $plugin_conf_string = $data->{plugin}->{data};
160
161 # for security reasons, we execute the command as nobody
162 # we can't verify that the code of the DNSPlugins are harmless.
163 my $cmd = ["setpriv", "--reuid", "nobody", "--regid", "nogroup", "--clear-groups", "--reset-env", "--"];
164
165 # The order of the parameters passed to proxmox-acme is important
166 # proxmox-acme <setup|teardown> $plugin <$domain|$alias> $txtvalue [$plugin_conf_string]
167 push @$cmd, "/bin/bash", $ACME_PATH, $action, $dnsplugin;
168 if ($alias) {
169 push @$cmd, $alias;
170 } else {
171 push @$cmd, $domain;
172 }
173 my $input = "$txtvalue\n";
174 $input .= "$plugin_conf_string\n" if $plugin_conf_string;
175
176 PVE::Tools::run_command($cmd, input => $input);
177
178 $data->{url} = $challenge->{url};
179
180 return $domain;
181 };
182
183 sub setup {
184 my ($self, $acme, $auth, $data) = @_;
185
186 my $domain = $proxmox_acme_command->($self, $acme, $auth, $data, 'setup');
187 print "Add TXT record: _acme-challenge.$domain\n";
188 }
189
190 sub teardown {
191 my ($self, $acme, $auth, $data) = @_;
192
193 my $domain = $proxmox_acme_command->($self, $acme, $auth, $data, 'teardown');
194 print "Remove TXT record: _acme-challenge.$domain\n";
195 }
196
197 1;