]> git.proxmox.com Git - proxmox-acme.git/blob - src/PVE/ACME/DNSChallenge.pm
041bc791b5cd13434784e56b3b0ac8eedbb229c9
[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' => 1 };
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 sub extract_challenge {
147 my ($self, $challenge) = @_;
148
149 return PVE::ACME::Challenge->extract_challenge($challenge, 'dns-01');
150 }
151
152 sub get_subplugins {
153 return $api_name_list;
154 }
155
156 my $proxmox_acme_command = sub {
157 my ($self, $acme, $auth, $data, $action) = @_;
158
159 die "No plugin data for DNSChallenge\n" if !defined($data->{plugin});
160
161 my $alias = $data->{alias};
162 my $domain = $auth->{identifier}->{value};
163
164 my $challenge = $self->extract_challenge($auth->{challenges});
165 my $key_auth = $acme->key_authorization($challenge->{token});
166
167 my $txtvalue = PVE::ACME::encode(sha256($key_auth));
168 my $dnsplugin = $data->{plugin}->{api};
169 my $plugin_conf_string = $data->{plugin}->{data};
170
171 # for security reasons, we execute the command as nobody
172 # we can't verify that the code of the DNSPlugins are harmless.
173 my $cmd = ["setpriv", "--reuid", "nobody", "--regid", "nogroup", "--clear-groups", "--"];
174
175 # The order of the parameters passed to proxmox-acme is important
176 # proxmox-acme <setup|teardown> $plugin <$domain|$alias> $txtvalue [$plugin_conf_string]
177 push @$cmd, "/bin/bash", $ACME_PATH, $action, $dnsplugin;
178 if ($alias) {
179 push @$cmd, $alias;
180 } else {
181 push @$cmd, $domain;
182 }
183 push @$cmd, $txtvalue, $plugin_conf_string;
184
185 PVE::Tools::run_command($cmd);
186
187 $data->{url} = $challenge->{url};
188
189 return $domain;
190 };
191
192 sub setup {
193 my ($self, $acme, $auth, $data) = @_;
194
195 my $domain = $proxmox_acme_command->($self, $acme, $auth, $data, 'setup');
196 print "Add TXT record: _acme-challenge.$domain\n";
197 }
198
199 sub teardown {
200 my ($self, $acme, $auth, $data) = @_;
201
202 my $domain = $proxmox_acme_command->($self, $acme, $auth, $data, 'teardown');
203 print "Remove TXT record: _acme-challenge.$domain\n";
204 }
205
206 1;