证书管理

集群内部通信的证书

每个{PVE}集群默认创建自己的(自签名的)证书颁发机构(CA)并为每个节点生成一个由上述CA签名的证书。如果使用SPICE,这些证书被用于与集群的`pveproxy`服务以及Shell/Console特性的加密通信。

CA证书和密钥存储在Proxmox集群文件系统(pmxcfs)中。

API和Web界面的证书

REST API和web GUI由`pveproxy`服务提供,该服务在每个节点上运行。

您可以为`pveproxy`使用以下证书选项:

  1. 默认情况下,使用位于`/etc/pve/nodes/NODENAME/pve-ssl.pem`的节点特定证书。该证书由集群CA签名,因此不会被浏览器和操作系统自动信任。

  2. 使用外部提供的证书(例如,由商业CA签名的证书)。

  3. 使用ACME(Let’s Encrypt)获取可信任的证书,并自动更新,这也集成在{pve} API和网络接口中。

对于选项2和3,文件`/etc/pve/local/pveproxy-ssl.pem`(以及无需密码的`/etc/pve/local/pveproxy-ssl.key`)将会被使用。

Note
请记住,/etc/pve/local 是一个指向 /etc/pve/nodes/NODENAME 的节点特定的符号链接。

证书通过{PVE}节点管理命令管理(参见`pvenode(1)`手册页)。

Warning
不要替换或手动修改在 /etc/pve/local/pve-ssl.pem/etc/pve/local/pve-ssl.key 中自动生成的节点证书文件,或者是在 /etc/pve/pve-root-ca.pem/etc/pve/priv/pve-root-ca.key 中的集群CA文件。

上传自定义证书

如果您已经有了一个证书,想要用于{pve}节点,您可以简单地通过Web界面上传该证书。

请注意,如果提供了证书密钥文件,该文件必须不受密码保护。

通过Let’s Encrypt (ACME) 获取受信任的证书

{PVE} 包括对自动证书管理环境ACME)协议的实现,允许 {pve} 管理员使用像 Let’s Encrypt 这样的 ACME 提供者来轻松设置 TLS 证书,这些证书在现代操作系统和网络浏览器中被默认接受和信任。

目前实现的两个ACME端点是https://letsencrypt.org[Let’s Encrypt (LE)]的生产环境及其测试环境。我们的ACME客户端支持使用内置的web服务器对`http-01`挑战进行验证,以及使用支持所有DNS API端点https://acme.sh[acme.sh]的DNS插件对`dns-01`挑战进行验证。

ACME账户

您需要为每个集群注册一个ACME账户,并使用您想要使用的终端。该账户使用的电子邮件地址将作为ACME终端发出的续订到期或类似通知的联系点。

您可以通过网页界面 Datacenter → ACME 或使用 pvenode 命令行工具来注册和停用 ACME 账户。

pvenode acme account register account-name mail@example.com
Tip
由于 https://letsencrypt.org/docs/rate-limits/ [速率限制],如果您是第一次使用ACME或进行实验,您应该使用LE staging

ACME 插件

ACME插件的任务是自动验证您,因此您所操作的 {pve} 集群,是域名的真正所有者。这是自动证书管理的基础构建模块。

ACME协议规定了不同类型的挑战,例如`http-01`,其中一个web服务器提供一个包含特定内容的文件,以证明它控制了一个域名。有时这是不可能的,可能是因为技术限制,或者如果记录的地址无法从公共互联网访问。在这些情况下可以使用`dns-01`挑战。完成这个挑战需要在域的区域中创建一个特定的DNS记录。

'''{pve} 默认支持这两种挑战类型,您可以在 Datacenter → ACME 的网络界面下配置插件,或者使用 pvenode acme plugin add 命令进行配置。'''

ACME 插件配置存储在 /etc/pve/priv/acme/plugins.cfg。对于集群中的所有节点,都有一个可用的插件。

节点域

每个域都是节点特定的。您可以在 节点 → 证书 下添加新的或管理现有的域条目,或者使用 pvenode config 命令。

为节点配置好期望的域名并确保已选择期望的ACME账户后,您可以通过Web界面订购新证书。成功后,界面将在10秒后重新加载。

更新将会自动进行。

ACME HTTP 挑战插件

总是有一个隐式配置的`standalone`插件,用于通过在端口80上生成的内置Web服务器验证`http-01`挑战。

Note
名称`standalone`意味着它可以自行提供验证,无需任何第三方服务。因此,这个插件也适用于集群节点。

要使用它进行Let’s Encrypts ACME的证书管理,有一些先决条件。

  • 你必须接受Let’s Encrypt的服务条款(ToS)才能注册账户。

  • 节点的端口 80需要能够被互联网访问。

  • 端口80上必须没有其他监听器。

  • 请求的(子)域名需要解析到节点的公网IP地址。

ACME DNS API 挑战插件

在那些通过`http-01`方法进行验证的外部访问不可能或不希望的系统上,可以使用`dns-01`验证方法。这种验证方法需要一个允许通过API配置`TXT`记录的DNS服务器。

配置ACME DNS API进行验证

{PVE}重用了为`acme.sh`项目脚注:[acme.sh https://github.com/acmesh-official/acme.sh] 开发的DNS插件,请参阅其文档以获取特定API配置的详细信息。

使用DNS API配置新插件最简单的方法是通过网络界面(数据中心 → ACME)。

选择`DNS`作为挑战类型。然后你可以选择你的API提供商,输入凭据数据以通过他们的API访问你的账户。

Tip
请查看 acme.sh 的 https://github.com/acmesh-official/acme.sh/wiki/dnsapi#how-to-use-dns-api [如何使用 DNS API] wiki,以获取有关如何为您的提供商获取 API 凭证的更详细信息。

鉴于存在许多DNS提供商和API端点,{pve}会自动为一些提供商生成凭证表单。对于其他提供商,您将看到一个更大的文本区域,只需将所有凭证的`KEY`=`VALUE`对复制到那里即可。

通过CNAME别名进行DNS验证

一种特殊的 alias 模式可以用来在不同的域名/DNS服务器上进行验证,以防你的主要/真实DNS不支持通过API进行配置。手动为 _acme-challenge.domain1.example 设置一个永久的 CNAME 记录,指向 _acme-challenge.domain2.example,并在 {PVE} 节点配置文件中设置 alias 属性为 domain2.example,以允许 domain2.example 的DNS服务器验证 domain1.example 的所有挑战。

插件组合

结合使用`http-01`和`dns-01`验证是可能的,以防您的节点通过满足不同要求/拥有不同DNS配置能力的多个域名可达。通过为每个域指定不同的插件实例,也可以混合来自多个提供商或实例的DNS API。

Tip
如果可能的话,应该避免通过多个域名访问同一服务,因为这会增加复杂性。

ACME证书的自动续订

如果一个节点已经成功地使用ACME提供的证书配置(无论是通过pvenode还是通过GUI),证书将会由`pve-daily-update.service`自动续期。目前,如果证书已经过期,或者将在未来30天内过期,将尝试续期。

ACME案例与`pvenode`相关操作

例子:使用 Let’s Encrypt 证书的 Sample pvenode 调用示例

root@proxmox:~# pvenode acme account register default mail@example.invalid
Directory endpoints:
0) Let's Encrypt V2 (https://acme-v02.api.letsencrypt.org/directory)
1) Let's Encrypt V2 Staging (https://acme-staging-v02.api.letsencrypt.org/directory)
2) Custom
Enter selection: 1

服务条款: https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf
您同意上述条款吗?[y|N]y
...
任务完成
root@proxmox:~# pvenode config set --acme domains=example.invalid
root@proxmox:~# pvenode acme cert order
加载ACME账户详细信息
下达ACME订单
...
状态为'有效'!

所有域名已验证!
...
正在下载证书
设置 pveproxy 证书和密钥
重启 pveproxy
任务完成

示例:设置OVH API以验证域名

Note
无论使用哪些插件,账户注册步骤都是相同的,并且在此不再重复。
Note
OVH_AK` 和 OVH_AS 需要根据 OVH API 文档从 OVH 获取。

首先你需要获取所有信息,这样你和{pve}才能访问API。

root@proxmox:~# cat /path/to/api-token
OVH_AK=XXXXXXXXXXXXXXXX
OVH_AS=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
root@proxmox:~# source /path/to/api-token
root@proxmox:~# curl -XPOST -H"X-Ovh-Application: $OVH_AK" -H "Content-type: application/json" \
https://eu.api.ovh.com/1.0/auth/credential  -d '{
  "accessRules": [
    {"method": "GET","path": "/auth/time"},
    {"method": "GET","path": "/domain"},
    {"method": "GET","path": "/domain/zone/*"},
    {"method": "GET","path": "/domain/zone/*/record"},
    {"method": "POST","path": "/domain/zone/*/record"},
    {"method": "POST","path": "/domain/zone/*/refresh"},
    {"method": "PUT","path": "/domain/zone/*/record/"},
    {"method": "DELETE","path": "/domain/zone/*/record/*"}
]
}'
{"consumerKey":"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ","state":"pendingValidation","validationUrl":"https://eu.api.ovh.com/auth/?credentialToken=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}

打开验证链接并按照指引将应用程序密钥与账户/消费者密钥关联起来。

root@proxmox:~# echo "OVH_CK=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" >> /path/to/api-token

现在你可以设置ACME插件:

root@proxmox:~# pvenode acme plugin add dns example_plugin --api ovh --data /path/to/api_token
root@proxmox:~# pvenode acme plugin config example_plugin
┌────────┬──────────────────────────────────────────┐
│ key    │ value                                    │
╞════════╪══════════════════════════════════════════╡
│ api    │ ovh                                      │
├────────┼──────────────────────────────────────────┤
│ data   │ OVH_AK=XXXXXXXXXXXXXXXX                  │
│        │ OVH_AS=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY  │
│        │ OVH_CK=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ  │
├────────┼──────────────────────────────────────────┤
│ digest │ 867fcf556363ca1bea866863093fcab83edf47a1 │
├────────┼──────────────────────────────────────────┤
│ plugin │ example_plugin                           │
├────────┼──────────────────────────────────────────┤
│ type   │ dns                                      │
└────────┴──────────────────────────────────────────┘

最后您可以配置您想要获取证书的域名,并为其下达证书订单:

root@proxmox:~# pvenode config set -acmedomain0 example.proxmox.com,plugin=example_plugin
root@proxmox:~# pvenode acme cert order
Loading ACME account details
Placing ACME order
Order URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/11111111/22222222

从 'https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/33333333' 获取授权详情
example.proxmox.com 的验证等待中!
[Wed Apr 22 09:25:30 CEST 2020] 使用 OVH 端点:ovh-eu
[Wed Apr 22 09:25:30 CEST 2020] 正在检查认证
[Wed Apr 22 09:25:30 CEST 2020] 消费者密钥正常。
[Wed Apr 22 09:25:31 CEST 2020] 正在添加记录
[Wed Apr 22 09:25:32 CEST 2020] 已添加,等待10秒。
添加 TXT 记录:_acme-challenge.example.proxmox.com
触发验证
等待5秒
状态为'有效'!
[Wed Apr 22 09:25:48 CEST 2020] 使用 OVH 端点:ovh-eu
[Wed Apr 22 09:25:48 CEST 2020] 正在检查认证
[Wed Apr 22 09:25:48 CEST 2020] 消费者密钥正常。
移除 TXT 记录:_acme-challenge.example.proxmox.com

所有域名已验证!

创建CSR
检查订单状态
订单已准备好,正在完成订单
有效!

下载证书
设置 pveproxy 证书和密钥
重启 pveproxy
任务完成

示例:从`staging`环境切换到常规的ACME目录

更改账户的ACME目录是不支持的,但由于{pve}支持多个账户,您可以直接创建一个以生产(受信任的)ACME目录作为终点的新账户。您还可以停用测试账户并重新创建它。

示例:使用 pvenodedefault ACME 账户的目录从 staging 更改为。
root@proxmox:~# pvenode acme account deactivate default
Renaming account file from '/etc/pve/priv/acme/default' to '/etc/pve/priv/acme/_deactivated_default_4'
Task OK

root@proxmox:~# pvenode acme account register default example@proxmox.com
Directory endpoints:
0) Let's Encrypt V2 (https://acme-v02.api.letsencrypt.org/directory)
1) Let's Encrypt V2 Staging (https://acme-staging-v02.api.letsencrypt.org/directory)
2) Custom
Enter selection: 0

服务条款:https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf
你同意上述条款吗?[y|N]y
...
任务完成