digicatech / yaac
另一个ACME客户端:一个解耦的Let’s Encrypt客户端
Requires
- ext-json: *
- ext-openssl: *
- guzzlehttp/guzzle: ^6.3|^7.0
- league/flysystem: ^1.0|^3.0
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
对象的数组。这些对象具有您可以使用(包括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();