]> git.proxmox.com Git - proxmox-acme.git/blob - src/PVE/ACME/DNSChallenge.pm
dns plugin: reset environment
[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 push @$cmd, $txtvalue, $plugin_conf_string;
174
175 PVE::Tools::run_command($cmd);
176
177 $data->{url} = $challenge->{url};
178
179 return $domain;
180 };
181
182 sub setup {
183 my ($self, $acme, $auth, $data) = @_;
184
185 my $domain = $proxmox_acme_command->($self, $acme, $auth, $data, 'setup');
186 print "Add TXT record: _acme-challenge.$domain\n";
187 }
188
189 sub teardown {
190 my ($self, $acme, $auth, $data) = @_;
191
192 my $domain = $proxmox_acme_command->($self, $acme, $auth, $data, 'teardown');
193 print "Remove TXT record: _acme-challenge.$domain\n";
194 }
195
196 1;