afosto/yaac

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

安装量: 306 750

依赖: 1

建议者: 0

安全: 0

星星: 219

关注者: 13

分支: 85

开放问题: 7

类型:

v1.5.2 2023-05-02 15:11 UTC

This package is auto-updated.

Last update: 2024-09-13 16:46:27 UTC


README

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

与文件系统或 web 服务器解耦

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

为什么

为什么我需要这个包?在 Afosto,我们像任何其他 SaaS 一样,在多租户环境中运行我们的软件,因此我们无法使用现有的许多客户端。

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

要求

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

入门

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

安装

使用 composer 轻松安装此包。

composer require afosto/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 Afosto\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,
]);

创建订单

要开始检索证书,我们首先需要创建一个订单。操作如下

在上面的示例中,主要域名后面跟着一个或多个辅助域名。确保您可以为每个域名证明所有权。因此,证书将针对提供的所有域名有效。

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

在创建订单请求中,为提供的每个域名请求一个授权以证明所有权。

证明所有权

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

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

您现在有一个 Authorization 对象的数组。这些对象包含您可以使用的挑战(既可以是 DNS 也可以是 HTTP),以提供所有权证明。

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();

谁在使用它?

您是否在使用此包,我们非常乐意了解。请发送PR以列出您的项目或公司。