]>
Commit | Line | Data |
---|---|---|
aeecd9ea SI |
1 | [[sysadmin_certificate_management]] |
2 | Certificate Management | |
3 | ---------------------- | |
4 | ifdef::wiki[] | |
5 | :pve-toplevel: | |
6 | endif::wiki[] | |
7 | ||
8 | ||
9 | Certificates for communication within the cluster | |
10 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
11 | ||
94958b8b | 12 | Each {PVE} cluster creates its own (self-signed) Certificate Authority (CA) and |
1a58a3c9 TL |
13 | generates a certificate for each node which gets signed by the aforementioned |
14 | CA. These certificates are used for encrypted communication with the cluster's | |
15 | `pveproxy` service and the Shell/Console feature if SPICE is used. | |
aeecd9ea | 16 | |
2971c735 | 17 | The CA certificate and key are stored in the xref:chapter_pmxcfs[Proxmox Cluster File System (pmxcfs)]. |
aeecd9ea | 18 | |
0a1739bd | 19 | |
aeecd9ea SI |
20 | Certificates for API and web GUI |
21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
22 | ||
0e9c6c13 FG |
23 | The REST API and web GUI are provided by the `pveproxy` service, which runs on |
24 | each node. | |
aeecd9ea SI |
25 | |
26 | You have the following options for the certificate used by `pveproxy`: | |
27 | ||
0e9c6c13 FG |
28 | 1. By default the node-specific certificate in |
29 | `/etc/pve/nodes/NODENAME/pve-ssl.pem` is used. This certificate is signed by | |
0a1739bd TL |
30 | the cluster CA and therefore not automatically trusted by browsers and |
31 | operating systems. | |
0e9c6c13 | 32 | 2. use an externally provided certificate (e.g. signed by a commercial CA). |
0a1739bd | 33 | 3. use ACME (Let's Encrypt) to get a trusted certificate with automatic |
da30f82a | 34 | renewal, this is also integrated in the {pve} API and Webinterface. |
aeecd9ea | 35 | |
0e9c6c13 | 36 | For options 2 and 3 the file `/etc/pve/local/pveproxy-ssl.pem` (and |
aeecd9ea SI |
37 | `/etc/pve/local/pveproxy-ssl.key`, which needs to be without password) is used. |
38 | ||
da30f82a TL |
39 | NOTE: Keep in mind that `/etc/pve/local` is a node specific symlink to |
40 | `/etc/pve/nodes/NODENAME`. | |
41 | ||
aeecd9ea SI |
42 | Certificates are managed with the {PVE} Node management command |
43 | (see the `pvenode(1)` manpage). | |
44 | ||
0e9c6c13 FG |
45 | WARNING: Do not replace or manually modify the automatically generated node |
46 | certificate files in `/etc/pve/local/pve-ssl.pem` and | |
47 | `/etc/pve/local/pve-ssl.key` or the cluster CA files in | |
48 | `/etc/pve/pve-root-ca.pem` and `/etc/pve/priv/pve-root-ca.key`. | |
aeecd9ea | 49 | |
0a1739bd | 50 | |
aeecd9ea | 51 | Getting trusted certificates via ACME |
0a1739bd TL |
52 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
53 | ||
aeecd9ea SI |
54 | {PVE} includes an implementation of the **A**utomatic **C**ertificate |
55 | **M**anagement **E**nvironment **ACME** protocol, allowing {pve} admins to | |
0e9c6c13 FG |
56 | interface with Let's Encrypt for easy setup of trusted TLS certificates which |
57 | are accepted out of the box on most modern operating systems and browsers. | |
aeecd9ea SI |
58 | |
59 | Currently the two ACME endpoints implemented are Let's Encrypt (LE) and its | |
0b447f1c FG |
60 | staging environment (see https://letsencrypt.org). Our ACME client supports |
61 | validation of `http-01` challenges using a built-in webserver and validation of | |
62 | `dns-01` challenges using a DNS plugin. | |
aeecd9ea SI |
63 | |
64 | Because of https://letsencrypt.org/docs/rate-limits/[rate-limits] you should use | |
65 | LE `staging` for experiments. | |
66 | ||
0b447f1c FG |
67 | ACME Plugin configuration is stored in `/etc/pve/priv/acme/plugins.cfg`. There |
68 | is always an implicitly configured `standalone` plugin for validating `http-01` | |
69 | challenges via the built-in webserver spawned on port 80. | |
70 | ||
aeecd9ea SI |
71 | There are a few prerequisites to use Let's Encrypt: |
72 | ||
0b447f1c FG |
73 | * You have to accept the ToS of Let's Encrypt to register an account. |
74 | ||
75 | For `http-01` challenges: | |
76 | ||
77 | * **Port 80** of the node needs to be reachable from the internet. | |
78 | * There **must** be no other listener on port 80. | |
79 | * The requested (sub)domain needs to resolve to a public IP of the Node. | |
80 | ||
81 | For `dns-01` challenges: | |
82 | ||
83 | * DNS needs to be handled by a server that allows automatic provisioning of | |
84 | TXT records | |
aeecd9ea SI |
85 | |
86 | At the moment the GUI uses only the default ACME account. | |
87 | ||
88 | .Example: Sample `pvenode` invocation for using Let's Encrypt certificates | |
89 | ||
b0014034 | 90 | ---- |
aeecd9ea SI |
91 | root@proxmox:~# pvenode acme account register default mail@example.invalid |
92 | Directory endpoints: | |
93 | 0) Let's Encrypt V2 (https://acme-v02.api.letsencrypt.org/directory) | |
94 | 1) Let's Encrypt V2 Staging (https://acme-staging-v02.api.letsencrypt.org/directory) | |
95 | 2) Custom | |
96 | Enter selection: | |
97 | 1 | |
98 | ||
99 | Attempting to fetch Terms of Service from 'https://acme-staging-v02.api.letsencrypt.org/directory'.. | |
100 | Terms of Service: https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf | |
101 | Do you agree to the above terms? [y|N]y | |
102 | ||
103 | Attempting to register account with 'https://acme-staging-v02.api.letsencrypt.org/directory'.. | |
104 | Generating ACME account key.. | |
105 | Registering ACME account.. | |
106 | Registration successful, account URL: 'https://acme-staging-v02.api.letsencrypt.org/acme/acct/xxxxxxx' | |
107 | Task OK | |
108 | root@proxmox:~# pvenode acme account list | |
109 | default | |
110 | root@proxmox:~# pvenode config set --acme domains=example.invalid | |
111 | root@proxmox:~# pvenode acme cert order | |
112 | Loading ACME account details | |
113 | Placing ACME order | |
114 | Order URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/xxxxxxxxxxxxxx | |
115 | ||
116 | Getting authorization details from | |
117 | 'https://acme-staging-v02.api.letsencrypt.org/acme/authz/xxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxx' | |
118 | ... pending! | |
119 | Setting up webserver | |
120 | Triggering validation | |
121 | Sleeping for 5 seconds | |
122 | Status is 'valid'! | |
123 | ||
124 | All domains validated! | |
125 | ||
126 | Creating CSR | |
127 | Finalizing order | |
128 | Checking order status | |
129 | valid! | |
130 | ||
131 | Downloading certificate | |
132 | Setting pveproxy certificate and key | |
133 | Restarting pveproxy | |
134 | Task OK | |
d75e644b | 135 | ---- |
0e9c6c13 | 136 | |
19b04e77 | 137 | Switching from the `staging` to the regular ACME directory |
b0014034 | 138 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
19b04e77 SI |
139 | |
140 | Changing the ACME directory for an account is unsupported. If you want to switch | |
141 | an account from the `staging` ACME directory to the regular, trusted, one you | |
142 | need to deactivate it and recreate it. | |
143 | ||
144 | This procedure is also needed to change the default ACME account used in the GUI. | |
145 | ||
146 | .Example: Changing the `default` ACME account from the `staging` to the regular directory | |
147 | ||
d75e644b | 148 | ---- |
19b04e77 SI |
149 | root@proxmox:~# pvenode acme account info default |
150 | Directory URL: https://acme-staging-v02.api.letsencrypt.org/directory | |
151 | Account URL: https://acme-staging-v02.api.letsencrypt.org/acme/acct/6332194 | |
152 | Terms Of Service: https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf | |
153 | ||
154 | Account information: | |
155 | ID: xxxxxxx | |
156 | Contact: | |
157 | - mailto:example@proxmox.com | |
158 | Creation date: 2018-07-31T08:41:44.54196435Z | |
159 | Initial IP: 192.0.2.1 | |
160 | Status: valid | |
161 | ||
162 | root@proxmox:~# pvenode acme account deactivate default | |
163 | Renaming account file from '/etc/pve/priv/acme/default' to '/etc/pve/priv/acme/_deactivated_default_4' | |
164 | Task OK | |
d75e644b | 165 | |
19b04e77 SI |
166 | root@proxmox:~# pvenode acme account register default example@proxmox.com |
167 | Directory endpoints: | |
168 | 0) Let's Encrypt V2 (https://acme-v02.api.letsencrypt.org/directory) | |
169 | 1) Let's Encrypt V2 Staging (https://acme-staging-v02.api.letsencrypt.org/directory) | |
170 | 2) Custom | |
171 | Enter selection: | |
172 | 0 | |
173 | ||
174 | Attempting to fetch Terms of Service from 'https://acme-v02.api.letsencrypt.org/directory'.. | |
175 | Terms of Service: https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf | |
176 | Do you agree to the above terms? [y|N]y | |
177 | ||
178 | Attempting to register account with 'https://acme-v02.api.letsencrypt.org/directory'.. | |
179 | Generating ACME account key.. | |
180 | Registering ACME account.. | |
181 | Registration successful, account URL: 'https://acme-v02.api.letsencrypt.org/acme/acct/39335247' | |
182 | Task OK | |
d75e644b | 183 | ---- |
19b04e77 | 184 | |
0e9c6c13 FG |
185 | Automatic renewal of ACME certificates |
186 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
187 | ||
188 | If a node has been successfully configured with an ACME-provided certificate | |
189 | (either via pvenode or via the GUI), the certificate will be automatically | |
190 | renewed by the pve-daily-update.service. Currently, renewal will be attempted | |
da30f82a | 191 | if the certificate has expired already, or will expire in the next 30 days. |
0b447f1c | 192 | |
0a1739bd TL |
193 | Configuring ACME DNS APIs for validation |
194 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
0b447f1c FG |
195 | |
196 | On systems where external access for validation via the `http-01` method is | |
197 | not possible or desired, it is possible to use the `dns-01` validation method. | |
198 | This validation method requires a DNS server that allows provisioning of `TXT` | |
199 | records via an API. | |
200 | ||
201 | {PVE} re-uses the DNS plugins developed for the `acme.sh` | |
202 | footnote:[acme.sh https://github.com/acmesh-official/acme.sh] | |
203 | project, please refer to its documentation for details on configuration of | |
204 | specific APIs. | |
205 | ||
206 | Combining `http-01` and `dns-01` validation is possible in case your node is | |
207 | reachable via multiple domains with different requirements / DNS provisioning | |
208 | capabilities. Mixing DNS APIs from multiple providers or instances is also | |
209 | possible by specifying different plugin instances per domain. | |
210 | ||
211 | A special `alias` mode can be used to handle the validation on a different | |
212 | domain/DNS server, in case your primary/real DNS does not support provisioning | |
213 | via an API. Manually set up a permanent `CNAME` record for | |
214 | `_acme-challenge.domain1.example` pointing to `_acme-challenge.domain2.example` | |
215 | and set the `alias` property in the {PVE} node configuration file to | |
216 | `domain2.example` to allow the DNS server of `domain2.example` to validate all | |
217 | challenges for `domain1.example`. | |
218 | ||
219 | .Example: Setting up the OVH API for validating a domain | |
220 | ||
186c094b TL |
221 | NOTE: the account registration steps are the same no matter which plugins are |
222 | used, and are not repeated here. | |
223 | ||
224 | NOTE: `OVH_AK` and `OVH_AS` need to be obtained from OVH according to the OVH | |
225 | API documentation | |
226 | ||
227 | ||
228 | First you need to get all information so you and {pve} can access the API. | |
0b447f1c FG |
229 | |
230 | ---- | |
231 | root@proxmox:~# cat /path/to/api-token | |
232 | OVH_AK=XXXXXXXXXXXXXXXX | |
233 | OVH_AS=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY | |
234 | root@proxmox:~# source /path/to/api-token | |
235 | root@proxmox:~# curl -XPOST -H"X-Ovh-Application: $OVH_AK" -H "Content-type: application/json" \ | |
236 | https://eu.api.ovh.com/1.0/auth/credential -d '{ | |
237 | "accessRules": [ | |
238 | {"method": "GET","path": "/auth/time"}, | |
239 | {"method": "GET","path": "/domain"}, | |
240 | {"method": "GET","path": "/domain/zone/*"}, | |
241 | {"method": "GET","path": "/domain/zone/*/record"}, | |
242 | {"method": "POST","path": "/domain/zone/*/record"}, | |
243 | {"method": "POST","path": "/domain/zone/*/refresh"}, | |
244 | {"method": "PUT","path": "/domain/zone/*/record/"}, | |
245 | {"method": "DELETE","path": "/domain/zone/*/record/*"} | |
246 | ] | |
247 | }' | |
248 | {"consumerKey":"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ","state":"pendingValidation","validationUrl":"https://eu.api.ovh.com/auth/?credentialToken=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"} | |
249 | ||
250 | (open validation URL and follow instructions to link Application Key with account/Consumer Key) | |
251 | ||
252 | root@proxmox:~# echo "OVH_CK=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" >> /path/to/api-token | |
186c094b TL |
253 | ---- |
254 | ||
255 | Now you can setup the the ACME plugin: | |
256 | ||
257 | ---- | |
0b447f1c FG |
258 | root@proxmox:~# pvenode acme plugin add dns example_plugin --api ovh --data /path/to/api_token |
259 | root@proxmox:~# pvenode acme plugin config example_plugin | |
260 | ┌────────┬──────────────────────────────────────────┐ | |
261 | │ key │ value │ | |
262 | ╞════════╪══════════════════════════════════════════╡ | |
263 | │ api │ ovh │ | |
264 | ├────────┼──────────────────────────────────────────┤ | |
265 | │ data │ OVH_AK=XXXXXXXXXXXXXXXX │ | |
266 | │ │ OVH_AS=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY │ | |
267 | │ │ OVH_CK=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ │ | |
268 | ├────────┼──────────────────────────────────────────┤ | |
269 | │ digest │ 867fcf556363ca1bea866863093fcab83edf47a1 │ | |
270 | ├────────┼──────────────────────────────────────────┤ | |
271 | │ plugin │ example_plugin │ | |
272 | ├────────┼──────────────────────────────────────────┤ | |
273 | │ type │ dns │ | |
274 | └────────┴──────────────────────────────────────────┘ | |
186c094b TL |
275 | ---- |
276 | ||
277 | At last you can configure the domain you want to get certitficates for and | |
278 | place the certificate order for it: | |
279 | ||
280 | ---- | |
0b447f1c FG |
281 | root@proxmox:~# pvenode config set -acmedomain0 example.proxmox.com,plugin=example_plugin |
282 | root@proxmox:~# pvenode acme cert order | |
283 | Loading ACME account details | |
284 | Placing ACME order | |
285 | Order URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/11111111/22222222 | |
286 | ||
287 | Getting authorization details from 'https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/33333333' | |
288 | The validation for example.proxmox.com is pending! | |
289 | [Wed Apr 22 09:25:30 CEST 2020] Using OVH endpoint: ovh-eu | |
290 | [Wed Apr 22 09:25:30 CEST 2020] Checking authentication | |
291 | [Wed Apr 22 09:25:30 CEST 2020] Consumer key is ok. | |
292 | [Wed Apr 22 09:25:31 CEST 2020] Adding record | |
293 | [Wed Apr 22 09:25:32 CEST 2020] Added, sleep 10 seconds. | |
294 | Add TXT record: _acme-challenge.example.proxmox.com | |
295 | Triggering validation | |
296 | Sleeping for 5 seconds | |
297 | Status is 'valid'! | |
298 | [Wed Apr 22 09:25:48 CEST 2020] Using OVH endpoint: ovh-eu | |
299 | [Wed Apr 22 09:25:48 CEST 2020] Checking authentication | |
300 | [Wed Apr 22 09:25:48 CEST 2020] Consumer key is ok. | |
301 | Remove TXT record: _acme-challenge.example.proxmox.com | |
302 | ||
303 | All domains validated! | |
304 | ||
305 | Creating CSR | |
306 | Checking order status | |
307 | Order is ready, finalizing order | |
308 | valid! | |
309 | ||
310 | Downloading certificate | |
311 | Setting pveproxy certificate and key | |
312 | Restarting pveproxy | |
313 | Task OK | |
314 | ---- |