另一个ACME客户端:一个解耦的Let’s Encrypt客户端

安装: 1

依赖: 0

建议者: 0

安全性: 0

星星: 0

关注者: 2

分支: 84

类型:

v1.0 2022-12-03 21:30 UTC

This package is not auto-updated.

Last update: 2024-09-23 04:57:30 UTC


README

ACME客户端,基于Afosto/Yaac进行分支

用PHP编写,此客户端旨在成为一个简化和解耦的Let’s Encrypt客户端,基于ACME V2

解耦于文件系统或Web服务器

例如,不是将证书写入磁盘下的nginx配置,此客户端仅返回数据(证书和私钥)。

为什么

为什么我需要这个包?在Digicatech,我们像任何其他SaaS一样在多租户环境中运行我们的软件,因此我们不能使用已经存在的许多客户端。

几乎所有客户端都耦合到某种类型的Web服务器或固定的(一组)域名。如果需要动态获取和安装证书,此包可能非常有用。

要求

  • PHP7+
  • openssl
  • Flysystem(任何适配器均可) - 用于存储Let’s Encrypt账户信息

入门

入门非常简单。首先安装客户端,然后您需要构建一个flysystem文件系统,实例化客户端,然后您就可以开始请求证书。

安装

使用composer轻松安装此包。

composer require digicatech/yaac

实例化客户端

要启动客户端,您需要三样东西;您的Let’s Encrypt账户的用户名、初始化的Flysystem,以及您需要决定是否颁发Fake LE Intermediate X1(预发布:MODE_STAGING)或Let's Encrypt Authority X3(实时:MODE_LIVE,用于生产)证书。

use League\Flysystem\Filesystem;
use League\Flysystem\Adapter\Local;
use Digicatech\Acme\Client;
 
//Prepare flysystem
$adapter = new Local('data');
$filesystem = new Filesystem($adapter);
 
//Construct the client
$client = new Client([
    'username' => 'example@example.org',
    'fs'       => $filesystem,
    'mode'     => Client::MODE_STAGING,
]);

在实例化客户端时,如有需要,将创建一个新的Let’s Encrypt账户,然后同意服务条款。

创建订单

要开始检索证书,我们首先需要创建一个订单。这可以通过以下方式进行

$order = $client->createOrder(['example.org', 'www.example.org']);

在上面的示例中,主域后面跟着一个或多个二级域。确保您可以为每个域证明所有权。结果,证书将对所有提供的域有效。

证明所有权

在您可以为特定域获取证书之前,您需要证明您拥有给定的域(域)。我们请求授权以证明所有权。获取订单授权。对于在创建订单请求中提供的每个域,都会返回一个授权。

$authorizations = $client->authorize($order);

现在您有一个Authorization对象的数组。这些对象具有您可以使用(包括DNSHTTP)来提供所有权证明的挑战。

HTTP验证

HTTP验证(在特定URL上提供特定内容,例如:example.org/.well-known/acme-challenge/*)如下所示

使用以下示例启动HTTP验证。首先获取挑战,下一步是使挑战可通过以下方式访问

foreach ($authorizations as $authorization) {
    $file = $authorization->getFile();
    file_put_contents($file->getFilename(), $file->getContents());   
}

如果您需要通配符证书,您将需要使用DNS验证,见下文

DNS验证

您还可以使用DNS验证 - 要这样做,您将需要访问DNS提供商的API以为目标域创建TXT记录。

foreach ($authorizations as $authorization) {
    $txtRecord = $authorization->getTxtRecord();
    
    //To get the name of the TXT record call:
    $txtRecord->getName();

    //To get the value of the TXT record call:
    $txtRecord->getValue();
}

自我测试

在公开挑战(通过HTTP或DNS访问)之后,我们应该进行自检以确保其工作正常,然后再让Let's Encrypt验证所有权。

对于HTTP挑战测试调用

if (!$client->selfTest($authorization, Client::VALIDATION_HTTP)) {
    throw new \Exception('Could not verify ownership via HTTP');
}

对于DNS测试调用

if (!$client->selfTest($authorization, Client::VALIDATION_DNS)) {
    throw new \Exception('Could not verify ownership via DNS');
}
sleep(30); // this further sleep is recommended, depending on your DNS provider, see below

在使用DNS验证的情况下,在selfTest确认DNS已更新后,建议您在继续之前等待一些额外的时间,例如sleep(30);。这是因为Let’s Encrypt将执行多视角验证,而您的DNS提供商可能尚未在其网络中完成更改的传播。

如果您过早地进行,Let's Encrypt将无法验证

请求验证

下一步是请求验证所有权。对于每个授权(域名),我们要求Let’s Encrypt验证挑战。

对于HTTP验证

foreach ($authorizations as $authorization) {
    $client->validate($authorization->getHttpChallenge(), 15);
}

对于DNS验证

foreach ($authorizations as $authorization) {
    $client->validate($authorization->getDnsChallenge(), 15);
}

上述代码将首先执行自检,如果成功,将尝试15次请求Let’s Encrypt验证挑战(间隔1秒)并获取更新状态(Let’s Encrypt验证挑战可能需要几秒钟)。

获取证书

现在要知道我们是否可以请求订单的证书,测试订单是否准备就绪如下

if ($client->isReady($order)) {
    //The validation was successful.
}

我们现在知道验证已完成,可以获取证书。操作如下

$certificate = $client->getCertificate($order);

我们现在有了证书,将其存储在文件系统中

//Store the certificate and private key where you need it
file_put_contents('certificate.cert', $certificate->getCertificate());
file_put_contents('private.key', $certificate->getPrivateKey());

获取单独的中间证书和域名证书

$domainCertificate = $certificate->getCertificate(false);
$intermediateCertificate = $certificate->getIntermediate();