第七章:自动化证书管理环境

ACME:Automated Certificate Management Environment

对于一个随处使用的协议,TLS有一大堆缺点。组织每年使用的任何流程,如更新证书,都会受到忽视,不可避免地会被遗忘,直到为时已晚,或者在几次失败后,会受到侵入性的高层监督。你安装了新的证书,三天后,一个零日漏洞会从你的网络服务器上扎根。证书撤销很麻烦,而且不完全有效。您的组织被收购,所有证书都需要重新购买。你使用你的CA的API自动进行证书管理,三个月后,董事会的某个人参加了一个聚会,在一只小狗提到你的CA不尊重他的无知,所以你必须更换CA后,一个不可信任的小王子会去清理。

TLS需要的是一个自动化证书管理的标准协议。一种在一堆不同工具中实现的协议,允许您选择软件,就像选择要运行的web服务器一样。您可以将此工具指向任何CA,并自动续订、吊销或编辑证书。这将使您能够将证书请求从偶尔的烦恼转变为可遗忘的稳定状态。

互联网安全研究小组(Internet Security Research Group —— ISRG)正是通过自动证书管理环境(Automated Certificate Management Environment —— ACME)创建了这一点。ACME是用于客户端CA交互的客户端-服务器协议,有几十种实现。与由单独的CA开发的各种API不同,ACME已经通过了标准流程,正式成为RFC 8555。ACME最初由ISRG的证书颁发机构Let’s Encrypt测试和部署,现在由各种免费和商业CA部署。其他组织也在试验ACME用于非服务器证书,例如可在以下网址获得的S/MIME证书 https://acme.castle.cloud

第七章:自动化证书管理环境ACME如何工作ACME注册ACME流程ACEM 挑战HTTP-01DNS-01TLS-ALPN-01我该使用哪种挑战?测试 ACMEACME 客户端DehydratedDehydrated 钩子证书目录和用户核心dehydrated配置更改CAs其他设置域名列表Dehydrated 和 HTTP-01web服务器设置Apache设置HTTP-01钩子脚本运行dehydratedDehydrated目录证书目录存档证书证书部署DNS-01 挑战DNS-01 测试环境配置动态子区域DNS别名DNS-01 Hook 脚本使用DNS-01运行 DehydratedDNS-01冲突每个域配置ACME续订

ACME如何工作

ACME将标准的客户端-服务器应用程序与基于DNS的验证挑战相结合。记住,域名验证(Domain Validation)是专门针对域名服务的。CA可以合法地使用DNS来验证对站点的控制。

CA的ACME服务器可以通过URL访问,通常是HTTPS网站。任何能够访问API的主机都可以创建一个帐户、提交CSR并请求签名。

ACME注册

当您第一次使用ACME客户端时,它会创建自己的密钥对来唯一标识客户端。客户端第一次联系服务器时,必须接受CA的条款,然后注册一个与该公钥绑定的帐户。ACME客户端对这些操作有特定的一次性标志。该客户端和服务器之间的所有进一步交互都使用该密钥进行签名。当你使用免费的CA时,这个过程是自动的,只需要几秒钟。有了帐户,客户端可以提交证书签名、吊销和续订请求。

客户端的公钥用作唯一标识符,因此您可以将ACME与商业CA一起使用。CA将验证组织的身份,并为您提供一个漂亮的门户网站,您可以在其中更新您的信用卡号并列出您的ACME客户端密钥。由于ACME现在是一种标准协议,许多CA正在全速投入部署。

ACME流程

一旦客户端注册,它就可以向服务器提交订单。一个命令声明,“这是我控制并希望获得证书的主机和/或域。”

服务器必须验证客户端是否控制这些域,因此它会发送一份支持的质询方法列表。质询方法描述了ACME服务器可以返回服务器并验证客户端是否真的控制了它的方式。客户端从列表中选择其首选的质询方法。客户端想要获得证书的每个主机名都有自己的挑战。

一旦客户端为每个域选择了挑战(challenge),服务器就会发送有关如何执行挑战的详细信息。客户端执行质询并告诉服务器验证其工作。服务器验证质询是否成功。如果客户端未通过质询,则订单失败。如果客户端成功,它可以完成订单并将CSR提交给服务器。服务器对请求进行签名,并将证书返回给客户端。客户端负责无聊的系统管理员任务,如将证书复制到位和重新启动任何服务器。

ACEM 挑战

ACME挑战包括令牌和密钥授权。

令牌(token)是一个位置。客户端负责创建和放置令牌。

密钥授权(key authorization)是令牌和帐户密钥摘要的组合。密钥授权用作令牌的内容。

ACME服务器检查令牌位置,如果找到密钥授权,则同意客户端控制该服务器。

ACME目前支持三种不同的挑战方法:HTTP-01、DNS-01和TLS-ALPN-01。

HTTP-01

在HTTP-01方法中,ACME服务器告诉客户端在目录 /.well-known/acme-challenge/ 下,在证书所针对的主机的特定URL处使质询令牌可用。

假设我使用HTTP-01来验证我的控制 https://mwl.io 。当我的客户端提交订单并选择HTTP-01挑战时,服务器会说“这是您的挑战令牌和密钥授权。”我的客户端必须创建一个以令牌命名的文件,并在目录中提供它 https://mwl.io/.well-known/acme-challenge 。此文件必须包含密钥授权。

几秒钟后,ACME服务器检查文件是否存在以及是否包含密钥授权。如果检查成功,ACME服务器通知客户端它可以发送其CSR。

此挑战仅在端口80上运行,但您可以在端口443上将其重定向到HTTPS。您不能使用其他端口或其他协议。这可能是使用ACME最简单的方法。配置一个web服务器,在 /.well-known/acme-challenge 上提供ACME客户端拥有的目录。

HTTP-01适用于简单配置。如果负载平衡器后面有多个web服务器,则ACME客户端可以快速地将挑战文件复制到任何地方并在之后进行清理,或者告诉负载平衡器将查询定向到特定服务器。复制这些文件的方式因环境而异,因此很少有ACME客户端支持此类功能。

可以理解的是,Let's Encrypt策略不允许使用HTTP-01创建通配符证书。其他CA可能会选择不同的政策。

DNS-01

如果HTTP-01质询表明ACME客户端有权访问主机,则DNS-01质询声明代理有权更改域的DNS记录。这与谷歌网站验证使用的原则相同。密钥授权必须放在目标域中的TXT记录中,位于_acme-challenge.domainname 下。DNS验证需要ACME客户端和网络之间更大的集成。

当我的ACME客户端选择DNS质询来验证 mwl.io 时,ACME服务器会响应类似“将此密钥授权作为TXT置于_ACME_challenge.mwl.io 下”的内容。ACME客户端插入记录并告诉服务器进行检查。ACME服务器检查域的DNS以查找挑战条目。如果挑战存在,服务器告诉客户端提交其CSR。

当您的web服务器不可公开访问、使用HTTP的备用端口或需要通配符证书时,请使用DNS-01。当您需要在目标服务器以外的主机上运行ACME客户端时,也可以使用它。

TLS-ALPN-01

TLS-ALPN-01质询方法完全在TLS内进行。ALPN,即应用层协议协商(Application Layer Protocol Negotiation),是应用程序在单个端口上请求不同服务的一种方式。每个协议都分配了一个唯一的协议ID,就像TCP/IP端口一样。这是多路复用协议的另一种方式,这次是在单个加密端口上。

ALPN挑战的工作原理与HTTP挑战非常相似。目标服务器必须在端口443上运行一个讲TLS的服务器。此服务器不一定需要是web服务器,但它必须响应ACME的ALPN请求。

TLS-ALPN-01的数据流略有不同。在选择挑战之前,客户端拥有部署此挑战所需的所有信息,因此客户端设置挑战并告诉服务器“我选择TLS-ALPN-01,挑战已准备就绪。”服务器立即进行检查。如果挑战成功,服务器告诉客户端发送CSR。

ALPN很好,因为它完全在TLS中运行。应用服务器必须同时支持ALPN和ACME ALPN协议,这并不好。最早的解决方案涉及纯ACME挑战响应者。ACME客户端将关闭web服务器,在端口443上启动ACME响应程序,续订证书,关闭ACME质询响应程序,并重新激活web服务器。这并不理想,但允许对协议进行测试。如果您的应用程序不支持ACME而不是ALPN,并且您可以处理一些停机时间,您可以调查脱水患者等响应者。

应用程序正在添加对ALPN的本机支持。Apache的mod_md既是ACME客户端,也是ALPN响应器。Nginx使用代理配置将ACME请求从HTTPS请求转移。人们正在快速开发和改进ALPN解决方案。

当您的web服务器前面有代理或负载均衡器,并且您希望这些代理将ACME TLS请求转移到响应者时,请考虑TLS-ALPN-01。ALPN不适用于通配符证书,目标主机必须位于公共互联网上。

我该使用哪种挑战?

使用最简单的挑战方法来满足你的需求。如果您需要具有当前免费CA的通配符证书,则必须使用DNS-01。否则,请在TLS-ALPN-01和HTTP-01之间进行选择。

证书操作不是机密的。企业社会责任中的一切都是公共信息;唯一的秘密数据是私钥。您可以通过未加密的HTTP安全地运行ACME。然而,我倾向于在保密方面犯错。如果你的应用程序有一个集成、稳定和可靠的TLS-ALPN-01实现,我建议你尝试一下。同样,如果你有一个涉及“集群”之类的复杂环境,看看你的基础设施设备是否支持TLS-ALPN-01。

如果你的环境很简单,HTTP-01是完全合理的。大多数ACME客户端使用HTTP-01。

虽然ACME允许您在多种挑战方法之间进行选择,但我鼓励您选择一种并坚持下去。多种挑战可能性会产生多种失败路径。相反,在证书生命周期的三分之二左右,开始尝试更新证书。免费ACME CA的证书将在九十天后到期,因此您有三十天的时间续订证书。当临时问题阻止您在第一次尝试时续订证书时,您有足够的时间重试。或者发现你的主机配置错误。

测试 ACME

每个ACME挑战都带来了系统管理挑战。当您第一次配置ACME客户端时,它拒绝正常运行,您可能会编辑一个配置文件,并在两分钟内重新运行一个命令十几次。这是测试新工具或协议的正常部分。

任何免费资源都会被滥用。如果一个CA提供免费证书,那么一些既不了解证书也不了解“共享资源”含义的自私混蛋将每小时为他的所有网站创建新的证书。

免费CA对每个帐户的资源施加了严格的限制。如果您达到其中一个速率限制,CA将拒绝所有进一步的请求,直到限制到期。这些速率限制通常只会受到大型服务器场、ACME客户端开发人员和系统管理员在首次ACME部署中遇到的困难。即使你让一种挑战方法可靠地工作,添加第二种方法也可能会再次挑战这些限制。

这就是为什么像Let's Encrypt和Buypass这样的CA提供临时(staging)或测试(test)环境的原因。每个临时环境都有一个测试CA。由临时环境签名的证书不是全局信任的,但您可以为您的客户端下载根证书。暂存环境允许您测试设置,而不会遇到生产资源限制。

临时ACME服务器的URL与生产服务器不同。从暂存更改为生产意味着在ACME客户端中更改该URL。

当你第一次使用ACME时,特别是当你尝试不同的挑战方法时,检查你选择的CA是否有一个测试环境。您不希望您的测试达到极限并干扰生产。

ACME 客户端

与任何开放协议一样,您可以自由选择最适合您需求的ACME客户端。一些操作系统或应用程序堆栈包含自己的ACME客户端。OpenBSD有 acme-client(1) ,这是我最喜欢的HTTP-01挑战,但遗憾的是,它并没有整齐地打包在其他操作系统上。Apache有 mod_md 可以直接从web服务器管理ACME。在我写这篇 mod_md 的时候,它还没有完全准备好,但很多人都在投资它。Docker有一个容器,可以将Let's Encrypt直接集成到你的系统中,而不必担心任何混乱的ACME或TLS细节。你应该考虑使用与你的应用程序或操作系统紧密集成的客户端。

证书机器人(certbot —— https://certbot.eff.org/) 是第一个ACME客户端,由电子前沿基金会(Electronic Frontier Foundation)和Let's Encrypt开发,以便人们可以测试该协议。虽然这是第一个,但它不是官方标准。它是用Python编写的,Python包含在许多操作系统中,但在其他操作系统上是一个附加组件。目前,certbot尚不支持TLS-ALPN-01。

我们用 dehydrated (https://dehydrated.io/)作为我们的参考实施。这是用shell写的。它被广泛使用,并得到了社区和商业赞助商的大力支持。它唯一的依赖项是微不足道的bash和curl,以及sed和grep等核心系统程序。像老树莓派这样的微型机器可以很容易地运行dehydrateddehydrated 的主要优点是它的钩子,可以很容易地延伸以支持各种挑战。

Dehydrated

我们所有的参考Unixes都包括一个 dehydrated 包装。它是CentOS EPEL存储库的一部分,就像所有其他有用的软件一样。如果你的Unix没有 dehydrated 包,请从 https://dehydrated.io 抓取它。它只包含文档、shell脚本和示例配置;你不需要编译任何东西。

dehydrated 只有少数成分。主脚本,dehydrated ,提供核心功能。这是您将运行以执行所有ACME任务的命令。Dehydrated需要一个配置文件,名为 config 。(通过在命令行上指定所有内容,它可以在没有配置文件的情况下运行,但对于长期使用,配置文件更易于管理。)该脚本检查BSD上使用的 /usr/local/etc/dehydrate 和大多数Linux版本使用的 /etc/dehyde/config ,然后回到当前工作目录和运行 dehydrated 目录等选项。不要依赖后两者。如果您的软件包没有提供目录,请创建一个并将所有内容放在那里。我们将使用 /etc/dehydrated 作为示例。将 config.sample 复制到此目录作为引用,然后将其复制到 config

Dehydrated 钩子

dehydrated 支持无挑战方法。相反,外部钩子(hook)脚本提供了所有挑战功能。当开发出另一种挑战方法时,您只需要添加一个新的钩子来支持它。Dehydrated包含一个钩子脚本, hook.sh ,用于在单个主机上进行简单的HTTP-01验证。如果您没有使用负载均衡器并且不需要DNS验证,hook.sh 应该能满足您的需求。

每个负载均衡器和DNS服务器都有自己的管理接口,dehydrated 无法为它们提供钩子。dehydrated 网站有一个由贡献者编写的钩子集合。第三方DNS提供商(包括注册商)有任意数量的挂钩,支持nsupdate的名称服务器也有挂钩。在流行的负载均衡器上有用于HTTP-01验证的钩子脚本。查看 dehydrated 维基以获取选择。如果你在维基上找不到你的设置的钩子,可以在整个互联网上搜索。

Dehydrated会自动在配置目录中搜索名为 hook.sh 的脚本。(某些Unixes会覆盖此默认值。)您放置在那里的任何脚本都会作为钩子脚本运行。如果你使用的脚本不是提供的 hook.sh ,我建议给它一个不同的名称,并在配置文件中设置该名称。

如果我引用 hook.sh ,我的意思是 dehydrated 包含的HTTP-01验证脚本。 “Hooks” 或 “hook” 泛指任何钩子脚本。

证书目录和用户

Dehydrated 生成证书。它需要一个地方来存放那些证书。您希望这些证书只能由dehydrated 程序和 root 访问。这意味着你需要一个 dehydrated 用户。如果您的操作系统包创建了此用户和主目录,请使用它们。

Debian和CentOS希望以root身份运行 dehydrated ,并提供 root 拥有的工作目录。没有ACME客户端需要访问权限来创建文件系统。我强烈建议创建一个新的、无特权的用户和目录。

与其创建一个 dehydrated 用户,不如创建一个名为 acme 的更通用的用户。如果您决定更改软件,您可以将此帐户重新用于接下来尝试的任何ACME客户端。由于托管证书的信息正在发生变化,它们属于 /var 。在这里,我创建了 acme 用户,其主目录为 /var/acme 。此用户的UID和GID为443,但您可以使用系统上任何可用的UID。

您需要以 acme 用户的身份运行命令。保护此帐户因您的Unix而异。如果您可以禁用该帐户并仍以该用户身份运行命令,请这样做。否则,请给用户一个冗长、令人不快的随机密码,以防止其他人轻松访问它。

Dehydrated可以在此处管理证书和相关文件。

在本书的其余部分,我将假设您使用的是用户acme。如果您更喜欢其他用户名,请根据需要替换它。现在您已经有了一个dehydrated玩耍的目录,我们可以配置 dehydrated

核心dehydrated配置

主要的dehydrated配置文件位于 /etc/dehydrate/config 中。这是Unix传统中的一系列变量赋值。哈希标记表示注释。无论您使用哪种挑战方法,每次dehpydrated安装都需要一些常见设置。

BASEDIR变量定义了脱水将保存所有证书、密钥和工作文档的目录。这一定是acme的。

告诉dehydrated应该以哪个用户和组的身份运行:

CA的每个帐户都需要一个联系电子邮件地址。CA将通知此地址证书即将到期,以及新的API地址等重大更改。

每个dehydrated安装都需要一个域列表来获取证书,通常存储在文件 domains.txt 中。默认位置是工作目录。如果有问题,dehydrated 可能会把名单扔掉。把你的域名列表放在脱水后无法触及的地方,比如配置目录。

默认挑战类型为HTTP-01。如果你使用的是另一种,请告诉dehydrated。

每种挑战方法都有自己的配置选项,您可以根据需要将其添加到配置中。

更改CAs

Dehydrated的默认CA是Let's Encrypt,但Dehydrated 0.7.0及更高版本为最流行的免费证书颁发机构提供了内置配置。在我写这篇文章的时候,它有Let’s Encrypt的测试和生产(letsencrypt-testletsencrypts),Buypass的测试和产品(buypass-testbuypass),以及ZeroSSL(zerossl)。用 CA 变量设置这些。以下实例中,我指的是Let's Encrypt的暂存环境:

当使用dehydrated的旧版本时,或者您希望使用dehydrated不知道的CA时,请将 CA 设置为证书颁发机构的API URL。每个ACME CA都在其文档中提供此设置。

当您更改CA并运行dehydrated时,它会自动在新CA注册帐户并获取新证书。它将旧CA的所有帐户信息保留在仅限于 acme 用户的目录中,因此如果您切换回来,它可以使用旧帐户。

其他设置

Dehydrated具有在奇怪情况下可能需要的各种其他设置和配置。

您可以读取替代默认设置的其他配置文件,而不是更改主配置文件。使用 CONFIG_D 为覆盖文件设置一个目录,就像Debian默认的那样。

Dehydrated读取每个名称以 .sh 结尾的文件,并将其添加到配置中。这些文件是按字母数字顺序读取的,后面文件中的条目会覆盖前面的条目。尽量减少您有多少覆盖文件。我发现这对于每个挑战或每个钩子的配置文件最有用,因为钩子有唯一的变量名。

如果您需要特殊的 curl(1) 选项来访问CA,例如使用代理服务器,请在 CURL_OPTS 中指定它们。

我们将根据需要探索其他设置。

域名列表

文件 domains.txt 包含您要获取和维护证书的所有域的列表。每个证书都有自己的行,就像这样:

列表中的每个名称都是证书上的服务器备选名称。第一个条目被分配给通用名称,也用作保存证书信息的目录名称。在这里,没有前导www的每个站点的版本是通用名称,其他站点则成为SAN。

通用名称最多只能包含64个字符,包括顶级域。如果您的域名长度超过64个字符,例如“我的” youkeepusingthatwordIdonotthinkitmeanswhatyouthinkitmeans.com ,您必须将其用作SAN,而不是通用名。

即使你的行很长,也不能用反斜杠把它分开。

您可以为一组不想与配置文件中的特定名称绑定的相关SAN创建dehydrated alias 。例如,我为我的一些小说系列租了域名,并想用TLS包装它们的网络重定向。我很容易感到困惑。在 montagueportal.com 的配置文件中引用 immortalclay.com 的证书会让我感到困惑。如果这些证书有一个更有用的通用名称,那就更好了。将此类别名放在 domains.txt 行末尾,前面加一个大于的符号(>)。

这两个域名的证书现在使用目录 fiction ,如本章后面的“The Dehydrated Directory”所述。

别名对于通配符证书特别有用。考虑这个 domains.txt 条目:

这会为 mwl.io 域下的所有主机(但不是 mwl.io 本身)请求一个通配符证书,并将其放在目录 *.mwl.io 中。我鼓励每个人用星号开始一次目录名,作为学习练习。一旦你明白了这一点,你就会欣赏这个别名。

您可以使用实际的主机名作为通用名和目录,但这并不总是可取的。

有了这个,我们可以通过ACME获得我们的第一个证书。

Dehydrated 和 HTTP-01

使用公共互联网上可用的单个web服务器,使用Let's Encrypt等免费CA,开始您的ACME实验。这是最简单的配置。我们将使用此主机通过HTTP-01挑战设置ACME。您必须在web服务器上配置一个目录,设置一个钩子脚本来添加和删除挑战,并编写一个部署脚本。

从web服务器开始。

web服务器设置

当dehydrated向服务器发送挑战时,ACME服务器将发回一个文件名和一个字符串以放入该文件中。dehydrated(或您选择的任何客户端)将该文件放在一个目录中。当服务器完成挑战时,dehydrated 会删除文件。最简单的方法是,为所有站点的ACME挑战创建一个文件系统目录,并告诉web服务器将该目录映射到该URL。由于我的所有网站都在 /var/www 下,我创建了 /var/www/acme 并将其所有权更改为 acme:acme

这个目录必须在我想要证书的每个网站上都可用,作为子目录 /.nearned/acme-challenge 。CA质询请求该目录中的特定文件,因此该目录不需要被索引、浏览或从任何地方链接。此目录必须在您要为其获取证书的每个站点上都可用。如果我想要一份涵盖两者的证书 https://mwl.io 以及 https://www.mwl.io ,服务器必须同时提供这两种功能 https://mwl.io/.well-known/acme-challenge/ 以及 https://www.mwl.io/.well-known/acme-challenge/

虽然我避免使用大多数特定于应用程序的说明,但这里有一个Apache的示例配置。

Apache设置

此主机上的每个网站最终都将通过ACME获得证书,我将多次重用ACME配置。这尖叫道:“包括文件!”

大多数Apache配置都有一个 Includes 目录,其中每个以 .conf 结尾的文件都会被吸入服务器配置。它是为虚拟主机设计的,每个域都有自己的配置文件。我们不是在创建全局配置,而是创建一个可以包含在多个站点中的Apache片段。这意味着它不能自动被吸入。ACME配置文件可以以 .conf 以外的任何文件结尾。

这是一个包含以下内容的 acme.config 文件:

每个需要ACME访问的虚拟主机只需要一个配置语句。

这使您可以更轻松地管理这个目录,它与每个站点上的其他任何内容都完全无关。

重新加载web服务器并在浏览器中调用挑战目录。它应该禁止你浏览内容。不过,如果你在 /var/www/acme 中创建了一个测试文件,它应该是可用的。

您的web服务器现在支持ACME挑战。

HTTP-01钩子脚本

Dehydrated包含一个名为 hook.sh 的HTTP-01挑战方法的钩子脚本。您的软件包可能已经在某个地方安装了它。如果将此脚本复制到配置目录 /etc/dehydrated/hook.shdehydrated 会自动找到它。如果您将脚本放在其他地方,请在 config 中使用 HOOK 变量通知dehydrated。

您必须使用 WELLKNOWN 配置文件选项告诉 hook.sh 在哪里可以找到映射到您网站的 .well-known/acme-challenges 目录的文件系统。我所有的网站都映射 /var/www/acme./well-known/acme-challenges

现在,您已准备好尝试HTTP-01验证。这将为您获取证书,但您必须编辑 hook.sh 才能激活它们。

运行dehydrated

以用户acme身份运行所有 dehydrated 命令。您可以为此配置 sudo(1) ,但我们将使用 su(1) 。通过检查你的dehydrated版本来测试它。

这演示了您可以将命令作为 acme 运行。首先,注册此ACME客户端并接受条款。

如果你忘记了这一步,dehydrated 会在你试图做任何事情时提醒你。

现在,用 -c 标志运行 dehydrated 。(如果您倾向于长期选项,请使用 --cron 。)这告诉脱水者检查所有现有证书的到期日期,续订30天内到期的所有证书,并请求任何尚不存在的证书。你最终会使用 dehydrated -c 令其每周运行。

dehydrated 首先会告诉您它正在处理哪些域。此证书尚不存在,因此它会继续创建新的CSR。

当dehydrated将域列表发送到ACME服务器,服务器会发回每个域的文件名和该文件名的内容。下面,dehydrated会创建文件。

既然挑战文件已经存在,dehydrated 告诉服务器继续执行挑战。

请注意,输出没有说明挑战的类型。所有dehydrated关心的是,它向钩子脚本提供了挑战信息,钩子脚本接受了挑战。

如果每一个挑战都得到了满足,dehydrated 已经证明它控制着这些域。它已经实现了域验证。它可以自己清理。

您现在拥有证书。某处。

Dehydrated目录

所有与证书相关的材料都会保存在 dehydrated 的基本目录的子目录中,如 config 中的 BASEDIR 所设置的。我的是 /var/acme ,在四个目录之一中。

accounts 目录包含此 dehydrated 安装的帐户信息。每个CA都有自己的子目录。实际帐户信息和脱水的密钥对存储在该子目录中的JSON文件中。

archive 目录包含过期的证书、密钥和CSR。虽然ACME应该透明无缝地自动续订证书,但手头有旧证书让我放心。有关详细信息,请参阅“存档证书”。

chains 下,您将找到缓存的证书链文件。Dehydrated 缓存根和中间证书链文件,以加快构建完整的链文件。

证书目录

Dehydrated 将证书、CSR、密钥和组装链文件存储在 cert 目录中。每个域都有自己的目录,以证书的通用名命名,这是 domains.txt 行中的第一个条目。您将在域的目录中看到五种类型的文件:私钥、CSR、证书、链文件和全链文件。所有证书材料都存储在以创建证书的时间命名的文件中。Dehydrated还会创建指向最新文件的符号链接,以便外部程序可以轻松访问它们。看看这些新创建的 mwl.io 证书文件。

文件 cert-1608225253.pem 是已签名的证书。如果你想知道证书是什么时候创建的,请使用 date(1) 将1608225253转换为人类可读的日期。不过,当证书续订时,没有人想更新他们的服务器配置,因此 dehydrated 符号将 cert.pem 链接到当前证书。

同样,文件 cert.csr 指向最新的CSR, chain.pem 指向包含CA证书和验证证书所需的任何中间证书的链文件,而 fullchain.pem 包含从根到主机的每个证书。 privkey.pem 链接到当前私钥文件。

把这一切放在一起,我会告诉我的服务器在 /var/acme/certs/mwl.io/cert.pem 中查找 mwl.io 的证书,在 /var/acme/certs/mwl.io/privkey.pem 中找到私钥。得益于符号链接,该应用程序完全不知道证书续订。

存档证书

几次续订后,证书目录会变得拥挤。你可能想保留最后一两个证书以防万一,但它们肯定会把你的工作区弄得一团糟。Dehydrated具有存档功能,可以将过时的证书、CSR、链和私钥移动到存档目录。

运行 dehydrated --cleanupdehydrated -gc 命令 dehydrated 将未使用的内容移动到以证书的公用名命名的存档下的文件夹中。您可能有一些多余的CSR或早期尝试回答挑战的关键文件。像这样把它们清理干净:

决定要保留过期证书多长时间,并安排归档过程和查找删除作业来清理任何旧证书。

证书部署

大多数应用程序仅在启动时读取证书文件。续订证书和更改证书文件不会更改应用程序提供的证书。您必须告诉应用程序重新读取证书。虽然安排每天凌晨3点执行 apachectl reload 是可行的,但编辑挂钩脚本会让你更加优雅。

示例 hook.sh 包含一个函数 deploy_cert ,该函数在证书更新后被调用。它专门用于添加命令。该示例显示了将新证书复制到web服务器期望找到它们的位置,但告诉web服务器查看 dehydrated 证书的位置更简单。部署阶段是发布 kill -HUPreloadrestart 的地方,无论您需要什么让服务器读取其新证书。

acme 用户可能需要额外的权限来运行部署命令。如果您在使用sudo等命令时遇到问题,但部署命令是软重载或同样不引人注目的命令,您可能会在 dehydrated 后几分钟安排部署。

使用部署命令后,您应该拥有使用HTTP-01验证完全自动化证书续订所需的一切。一旦你做到了这一点,你就可以研究DNS-01。

DNS-01 挑战

虽然HTTP-01挑战表明ACME客户端有能力在web服务器上创建任意文件,但DNS-01挑战表明,ACME客户端可以在目标主机的区域中创建任意DNS条目。它还要求将ACME客户端更深入地集成到网络中,这在某些组织中可能是不可能的。然而,这是获取通配符证书的唯一方法,也是为不公开的主机获取证书的最直接方法。

如果您必须将ACME客户端与web服务器分开,或者您需要web服务器以外的应用程序的证书,DNS-01可能会满足您的要求。将证书从ACME客户端移动到应用程序服务器完全是您的问题。这可以像 cp(1)rsync(1) 一样简单。像Ansible或Puppet这样的自动化系统也可以处理分发,或者您可以部署像Anvil这样的ACME特定证书系统(https://github.com/dlangille/anvil)。

DNS-01挑战只能由具备域名服务工作知识的人实施。如果你没有使用过DNS,或者像 ddns-confgen(1)nsupdate(1) 这样的词让你为了城堡的安全而运行,请坚持使用HTTP-01或立即联系你的DNS管理员。

幸运的是,DNS-01挑战只需要对DNS区域进行有限的访问。不幸的是,并非所有DNS服务器都可以实现这种受限访问。许多DNS服务器要么允许对整个区域进行写访问,要么阻止它。我们将用BIND进行演示,BIND可以被紧密地但不完全限制。

DNS-01质询要求在 _acme-challenge 子域下为证书中的每个SAN创建TXT记录。如果我想要 mwl.io 的证书,ACME客户端将为 _acme-challenge.mwl.io 创建一个TXT记录。如果我还有一个SAN为 www.mwl.io ,则挑战必须为 _acme-callenge.www.mwl.io 创建一个相同的记录。二十个证书和二百个SAN意味着创建和删除二百个TXT记录。

您可以使用CNAME(别名)将这些全部指向单个TXT记录。如果你同时挑战多个域名,它们可能会相互干扰。这取决于您的ACME客户端。

你有一个选择。您可以授予ACME客户端在每个域中创建和删除这些TXT记录的权限,或者您可以为每个名称创建一个CNAME,并允许ACME客户端访问以更新单个记录。在您当前的工作流程中,什么更容易?在你的环境中,哪一个侵入性较小?你真的要配置所有这些访问控制,还是所有这些CNAME?您的DNS服务器能否严格限制访问,还是只提供“此程序可能会更改此区域中的记录”访问控制?如果您没有细粒度的访问控制,您可以考虑部署一个ACME客户端可以更改的单个“burner”域,并将所有CNAME指向该域。

这两种方法在初始配置时需要大约相同的时间和精力,那么你应该使用哪种方法呢?

如果您想在一次 dehydrated 运行中续订多个域,请授予 dehydrated 访问权限以分别更新每个域。不过,我们大多数人只需要DNS-01用于特殊情况,并且可以使用HTTP-01用于常规证书。否则,请根据创建全新证书所需的工作量来决定。如果获得修改DNS条目的访问权限需要召开大量的变更控制会议或与顽固的供应商打交道,但您可以轻松地将CNAME添加到区域中,请使用基于CNAME的方法。如果您的环境的权威DNS服务很笨拙或缺乏细粒度的访问控制,请使用CNAME和burner域。如果您必须使用DNS-01更新多个域,您可以在刻录机域中为每个域分配自己的子域。如果您可以轻松创建子域并限制访问控制,也许您应该单独设置每个域。

DNS-01 测试环境

我的许多域都是静态的,每个域只包含一个或两个长期存在的IP地址。每个新的SAN意味着要么创建一个新的CNAME,要么创建一条新的访问控制语句并在每个SAN中启用动态DNS。我发现创建CNAME更容易,甚至可以在包含文件中完成。在这里,我为 mwl.io 设置了DNS-01挑战。

当 dehydrated 运行时,钩子会在子区域 _acme-challenge.mwl.io 中创建一个TXT记录。所有DNS-01挑战都由每个区域中的永久别名指向那里。一旦挑战得到满足,钩子就会删除TXT记录。

我们将在BIND中通过设置具有动态DNS的子区域、配置和测试该子区域的访问控制、设置CNAME以及从 dehydrated 站点配置基于nsupdate的DNS-01挂钩脚本来演示这一点。

配置动态子区域

我不希望任何ACME客户端对我的任何域具有完全访问权限,因此我将 _acme-challenge.mwl.io 配置为 mwl.io 的子区域。此子区域不应位于 mw1.io 的区域文件中;相反,该域必须将这些条目委托给子区域。我可以自定义子域的访问控制,同时让 mwl.io 保持距离和不可接触。

从组织的标准区域文件开始,清空除SOA记录和名称服务器之外的所有条目。所有其他区域内容将动态提供。把它放在BIND的工作目录中,可能是 /etc/namedb/working 。名称服务器用户拥有此目录及其中的所有文件。我将此文件命名为 acme.mwl.io

此子域现在需要一个 named.conf 条目。该条目的难点将是动态DNS密钥,但BIND包含 ddns-confgen(8) 来创建密钥并告诉您将它们放在哪里。在这里,我们使用它为zone _acme-challenge.mwl.io 生成一个名为“acme”的密钥:

将密钥复制到单独的文件 acme.key 中。您的所有ACME客户端都需要此文件的副本。要么将此密钥复制到 named.conf 中,要么将其与包含文件一起吸入。其余的产出并不重要;我们将实施比它所建议的更严格的措施。

现在named知道了密钥,我们可以告诉它我们的新区域并分配访问权限。

更新策略声明允许动态DNS更新,并将其限制为名为 acme 的密钥、名为 _acme-challenge.mwl.io 的区域和TXT记录。

使用 named-checkconf -z 命令验证您的名称服务器配置。如果您没有对所有内容进行加密,请重新加载您的名称Server并验证它是否识别新域。

如果返回的不是SOA记录,请检查错误日志。如果您有工作区,请根据DNS-01的要求使用 nsupdate 添加TXT记录。使用 -k 加载区域的授权密钥。

这应该会创建条目,但如果您不确定或以前没有使用过动态DNS更新,请使用 show 仔细检查您的工作:

这看起来像是一个实际的区域文件条目。提交它:

确认它在该区域:

密钥可用。现在删除它,使用相同的过程,但用 delete 命令代替 add 。完成ACME挑战后,务必将其删除。

在将运行ACME客户端的主机上重复此测试。如果不起作用,请检查ACME客户端对UDP端口53上的权威DNS服务器的访问。一切正常后,设置你的别名。

DNS别名

每个需要证书的主机都必须有一个DNS别名,将其 _acme-challenge 别名指向挑战域 _acme-clallenge.mwl.io 。要为 example.comwww.example.com 获取证书,我必须为每个这样的主机创建CNAME:

CNAME必须在五到十分钟内迅速到期。您不希望旧的ACME挑战值在互联网上漂移,因为它们会干扰未来ACME挑战的验证。

我的挑战域不能有 _acme-challenge.mwl.io 的CNAME,因为这是 dehydrated 钩子修改的真实条目。然而,它确实需要为 _acme-challenge.www.mwl.io 创建一个CNAME。

DNS-01 Hook 脚本

钩子脚本必须部署挑战令牌,删除挑战令牌,并触发激活续订证书所需的任何操作。Dehydrated的wiki包含一个示例钩子脚本,该脚本使用 nsupdate(1) 在区域中添加和删除挑战令牌。

Dehydrated使用参数调用其钩子脚本。钩子可以使用这些参数来构建一个更新区域的命令行。这在技术上是正确的方法,但我希望你花你的脑细胞来理解脚本的作用,而不是解码 printf(1) 语句。此处展示的 dns-hook.sh 脚本是 dehydrated 页面上该脚本的简化变体,也可在https://cdn.mwl.io/ 找到。不要在生产中使用这个简单的演示脚本:看看它的功能和工作原理,然后从 dehydrated 维基上的许多脚本中抓取一个生产级脚本。

钩子脚本的第一个参数是挑战步骤。在 deploy_challenge 阶段,钩子脚本需要设置挑战令牌。在 clean_challenge 中,钩子脚本会删除这些标记。当证书续订时,dehydrated 调用 deploy_cert 。当证书不变时,以及 dehydrated 启动和退出时,也会调用钩子,但这些很少使用。

第二个参数是接受挑战的域名。第三个参数是文件名,对HTTP-01有用,但对DNS-01不必要。第四个参数是必须进入文件或DNS TXT记录的ASCII字符串。这是此演示脚本所需的唯一组件。

deploy_challenge 阶段使用printf构建动态DNS更新命令,并将其提供给 nsupdate(1)

clean_challenge 阶段从等待开始。您的ACME客户端可以比证书颁发机构运行得更快。无需等待,您可以在所有挑战完成之前清理您的挑战令牌。等待后,脚本会删除挑战令牌。

deploy_cert 中,我们对web服务器进行软重新加载。如果您有一个复杂的部署过程,您可能希望将这些命令移动到一个单独的脚本中。您可能需要使用sudo来授予 acme 用户运行该脚本的权限,或者以其他用户的身份安排部署。

这个脚本是故障无关计算的一个很好的例子,仅供演示。如果您正在使用BIND,请从 dehydrated 站点获取一个基于nsupdate的脚本。如果你正在使用另一个DNS服务器或域名注册商的服务,可能也有相应的脚本。

使用DNS-01运行 Dehydrated

既然你已经有了所有的碎片,运行 dehydrated吧。由于 dehydrated 为您管理所有细节,因此命令不变:

您现在拥有证书。或错误消息。两者都很有用,尽管前者更方便。

DNS-01冲突

钩子脚本会删除所有现有的DNS-01挑战令牌,并放入自己的令牌。如果你同时在多台服务器上运行 dehydrated ,它们会争夺你动态区域的控制权。

解决这个问题的最简单方法是不要在多台服务器上同时运行 dehydrated 。如果每台服务器上都有多个域,并且每个域都需要一段时间才能运行,请仔细安排它们或为每台服务器创建一个单独的更新区域。

每个域配置

每个组织都有一个令人讨厌的域,有着非常特殊的要求和对特殊性的任性坚持。也许你的大多数域名都能很好地应对HTTP-01挑战,但这个烦人的域名需要通配符证书,因此必须使用DNS-01。Dehydrated允许您使用 config 中的 DOMAINS_D 选项为每个域配置文件设置一个目录:

每个域的配置文件允许设置大多数但不是所有选项。您不能使用其他CA;这需要一个完全不同的 dehydrated 配置目录。但是,您可以设置不同的挑战类型、钩子、密钥算法和每个证书的详细信息。仅设置与常用设置不同的选项。在证书的通用名之后命名每个域的配置文件。

mwl.io 需要DNS-01挑战,而其他所有内容都需要HTTP-01。我创建了 /etc/dehydrate/domans.d/mwl.io ,并设置了挑战和钩子脚本:

当我正常运行 dehydrated 时,它会获取每个域的配置文件。

我现在可以获得一个通配符证书,而无需强制我的所有域使用繁琐的DNS-01验证。

Dehydrated 有更多的特点。如果你的应用程序无法维护自己的OCSP主食,它可以为你下载。您可以强制使用IPv4或IPv6、吊销证书、选择算法等。查看文档以了解完整细节,但这应该能让你开始。

ACME续订

ACME的真正魔力在于更新时间。免费ACME证书将在九十天后过期。大多数免费CA将在到期前三十天内续订证书。每次ACME客户端运行时,它都会检查其每个证书的到期日期。如果证书在三十天内到期,它将使用与请求证书完全相同的过程自动续订证书。

一旦您有了一个可用的客户端,续订证书意味着将其安排为自动运行。每周一次的证书检查会让客户端在证书到期前四次尝试续订证书。这应该绰绰有余,除非你每周都在那一刻遇到暂时的问题。

现在您已经有了自动证书,让我们讨论一些进一步锁定TLS的方法。