Merge pull request #3 from HanadaLee/awsdeploy

支持直接部署证书到AWS ACM
This commit is contained in:
Hanada 2025-05-12 00:47:11 +08:00 committed by GitHub
commit 4850250f3c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 80 additions and 15 deletions

View File

@ -1422,7 +1422,7 @@ class DeployHelper
'name' => 'AWS',
'class' => 2,
'icon' => 'aws.ico',
'note' => '支持部署到Amazon CloudFront',
'note' => '支持部署到Amazon CloudFront、AWS Certificate Manager',
'inputs' => [
'AccessKeyId' => [
'name' => 'AccessKeyId',
@ -1452,14 +1452,24 @@ class DeployHelper
'type' => 'select',
'options' => [
['value'=>'cloudfront', 'label'=>'CloudFront'],
['value'=>'acm', 'label'=>'AWS Certificate Manager'],
],
'value' => 'cloudfront',
'value' => 'acm',
'required' => true,
],
'distribution_id' => [
'name' => '分配ID',
'type' => 'input',
'placeholder' => 'distributions id',
'show' => 'product==\'cloudfront\'',
'required' => true,
],
'acm_arn' => [
'name' => 'ACM ARN',
'type' => 'input',
'placeholder' => '',
'show' => 'product==\'acm\'',
'note' => '在AWS Certificate Manager控制台查看证书的ARN',
'required' => true,
],
],

View File

@ -29,22 +29,24 @@ class aws implements DeployInterface
}
public function deploy($fullchain, $privatekey, $config, &$info)
{
if ($config['product'] == 'acm') {
if (empty($config['acm_arn'])) throw new Exception('ACM ARN不能为空');
$this->get_cert_id($fullchain, $privatekey, $config['acm_arn'], true);
} else {
$this->deploy_cloudfront($fullchain, $privatekey, $config, $info);
}
}
private function deploy_cloudfront($fullchain, $privatekey, $config, &$info)
{
if (empty($config['distribution_id'])) throw new Exception('分配ID不能为空');
$certInfo = openssl_x509_parse($fullchain, true);
if (!$certInfo) throw new Exception('证书解析失败');
$config['cert_name'] = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
if (isset($info['cert_id']) && isset($info['cert_name']) && $info['cert_name'] == $config['cert_name']) {
$cert_id = $info['cert_id'];
$this->log('证书已上传:' . $cert_id);
} else {
$cert_id = $this->get_cert_id($fullchain, $privatekey);
$this->log('证书上传成功:' . $cert_id);
$info['cert_id'] = $cert_id;
$info['cert_name'] = $config['cert_name'];
usleep(500000);
}
$cert_id = isset($info['cert_id']) ? $info['cert_id'] : null;
$cert_id = $this->get_cert_id($fullchain, $privatekey, $cert_id, $config['cert_name']);
usleep(500000);
$client = new AWSClient($this->AccessKeyId, $this->SecretAccessKey, 'cloudfront.amazonaws.com', 'cloudfront', '2020-05-31', 'us-east-1', $this->proxy);
try {
@ -63,14 +65,62 @@ class aws implements DeployInterface
$this->log('分配ID: ' . $config['distribution_id'] . ' 证书部署成功!');
}
private function get_cert_id($fullchain, $privatekey)
private function get_cert_id($fullchain, $privatekey, $cert_id = null, $acm = false)
{
$cert = explode('-----END CERTIFICATE-----', $fullchain)[0] . '-----END CERTIFICATE-----';
if ($acm === true && $cert_id == null) {
throw new Exception('ACM ARN不能为空');
}
$certificates = explode('-----END CERTIFICATE-----', $fullchain);
$cert = $certificates[0] . '-----END CERTIFICATE-----';
$client = new AWSClient($this->AccessKeyId, $this->SecretAccessKey, 'acm.us-east-1.amazonaws.com', 'acm', '', 'us-east-1', $this->proxy);
if (!empty($cert_id)) {
try {
$data = $client->request('POST', 'CertificateManager.GetCertificate', [
'CertificateArn' => $cert_id
]);
// 如果成功获取证书信息说明证书存在直接返回cert_id
if (isset($data['Certificate']) && trim($data['Certificate']) == trim($cert)) {
$this->log('证书已是最新ACM ARN' . $cert_id);
return $cert_id;
} else {
$this->log('证书已过期或被删除,准备更新或者重新上传');
}
} catch (Exception $e) {
if ($acm === true) {
throw new Exception('获取证书信息失败请检查ACM ARN是否正确' . $e->getMessage());
}
$this->log('证书已被删除:' . $cert_id. ',准备重新上传');
}
}
$certificateChain = '';
if (count($certificates) > 1) {
// 从第二个证书开始,重新拼接中间证书链
for ($i = 1; $i < count($certificates); $i++) {
if (trim($certificates[$i]) !== '') { // 忽略空字符串(可能由末尾分割产生)
$certificateChain .= $certificates[$i] . '-----END CERTIFICATE-----';
}
}
}
$param = [
'Certificate' => base64_encode($cert),
'PrivateKey' => base64_encode($privatekey),
];
// 如果有中间证书链,则添加到参数中
if (!empty($certificateChain)) {
$param['CertificateChain'] = base64_encode($certificateChain);
}
// 如果是ACM则添加ARN参数用于更新证书
if ($acm === true) {
$param['CertificateArn'] = $cert_id;
}
$client = new AWSClient($this->AccessKeyId, $this->SecretAccessKey, 'acm.us-east-1.amazonaws.com', 'acm', '', 'us-east-1', $this->proxy);
try {
$data = $client->request('POST', 'CertificateManager.ImportCertificate', $param);
@ -78,6 +128,11 @@ class aws implements DeployInterface
} catch (Exception $e) {
throw new Exception('上传证书失败:' . $e->getMessage());
}
$this->log('证书上传成功:' . $cert_id);
$info['cert_id'] = $cert_id;
return $cert_id;
}