mirror of
https://github.com/netcccyun/dnsmgr.git
synced 2026-02-21 15:31:12 +08:00
新增华为云OBS、天翼云函数计算部署,阿里云、腾讯云等新增上传到证书管理选项
This commit is contained in:
parent
137193d465
commit
fb69ed702b
@ -370,9 +370,8 @@ class DeployHelper
|
||||
'id' => [
|
||||
'name' => '证书ID',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'placeholder' => '留空则为添加证书',
|
||||
'note' => '在网站管理->证书管理查看证书的ID,注意域名是否与证书匹配',
|
||||
'required' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
@ -435,9 +434,8 @@ class DeployHelper
|
||||
'id' => [
|
||||
'name' => '证书ID',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'placeholder' => '留空则为添加证书',
|
||||
'note' => '在站点->证书管理查看证书的ID,注意域名是否与证书匹配',
|
||||
'required' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
@ -1060,6 +1058,7 @@ ctrl+x 保存退出',
|
||||
['value'=>'vod', 'label'=>'视频点播'],
|
||||
['value'=>'fc', 'label'=>'函数计算3.0'],
|
||||
['value'=>'fc2', 'label'=>'函数计算2.0'],
|
||||
['value'=>'upload', 'label'=>'上传到证书管理'],
|
||||
],
|
||||
'value' => 'cdn',
|
||||
'required' => true,
|
||||
@ -1171,7 +1170,7 @@ ctrl+x 保存退出',
|
||||
'name' => '绑定的域名',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'show' => 'product!=\'esa\'&&product!=\'clb\'&&product!=\'alb\'&&product!=\'nlb\'',
|
||||
'show' => 'product!=\'esa\'&&product!=\'clb\'&&product!=\'alb\'&&product!=\'nlb\'&&product!=\'upload\'',
|
||||
'required' => true,
|
||||
],
|
||||
],
|
||||
@ -1224,6 +1223,7 @@ ctrl+x 保存退出',
|
||||
['value'=>'tse', 'label'=>'云原生API网关TSE'],
|
||||
['value'=>'tcb', 'label'=>'云开发TCB'],
|
||||
['value'=>'lighthouse', 'label'=>'轻量应用服务器'],
|
||||
['value'=>'upload', 'label'=>'上传到证书管理'],
|
||||
['value'=>'update', 'label'=>'更新证书内容(证书ID不变)'],
|
||||
],
|
||||
'value' => 'cdn',
|
||||
@ -1324,7 +1324,7 @@ ctrl+x 保存退出',
|
||||
'name' => '绑定的域名',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'show' => 'product!=\'clb\'&&product!=\'tke\'',
|
||||
'show' => 'product!=\'clb\'&&product!=\'tke\'&&product!=\'upload\'',
|
||||
'note' => 'CDN、EO、WAF多个域名可用,隔开,其他只能填写1个域名',
|
||||
'required' => true,
|
||||
],
|
||||
@ -1375,15 +1375,31 @@ ctrl+x 保存退出',
|
||||
['value'=>'cdn', 'label'=>'内容分发网络CDN'],
|
||||
['value'=>'elb', 'label'=>'弹性负载均衡ELB'],
|
||||
['value'=>'waf', 'label'=>'Web应用防火墙WAF'],
|
||||
['value'=>'obs', 'label'=>'对象存储服务OBS'],
|
||||
['value'=>'upload', 'label'=>'上传到证书管理'],
|
||||
],
|
||||
'value' => 'cdn',
|
||||
'required' => true,
|
||||
],
|
||||
'obs_endpoint' => [
|
||||
'name' => 'Endpoint地址',
|
||||
'type' => 'input',
|
||||
'placeholder' => '填写示例:obs.cn-north-4.myhuaweicloud.com',
|
||||
'show' => 'product==\'obs\'',
|
||||
'required' => true,
|
||||
],
|
||||
'obs_bucket' => [
|
||||
'name' => '桶名称',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'show' => 'product==\'obs\'',
|
||||
'required' => true,
|
||||
],
|
||||
'domain' => [
|
||||
'name' => '绑定的域名',
|
||||
'type' => 'input',
|
||||
'placeholder' => '多个域名可使用,分隔',
|
||||
'show' => 'product==\'cdn\'',
|
||||
'show' => 'product==\'cdn\'||product==\'obs\'',
|
||||
'required' => true,
|
||||
],
|
||||
'project_id' => [
|
||||
@ -1478,6 +1494,7 @@ ctrl+x 保存退出',
|
||||
['value'=>'cdn', 'label'=>'CDN'],
|
||||
['value'=>'oss', 'label'=>'OSS'],
|
||||
['value'=>'pili', 'label'=>'视频直播'],
|
||||
['value'=>'upload', 'label'=>'上传到证书管理'],
|
||||
],
|
||||
'value' => 'cdn',
|
||||
'required' => true,
|
||||
@ -1493,6 +1510,7 @@ ctrl+x 保存退出',
|
||||
'name' => '绑定的域名',
|
||||
'type' => 'input',
|
||||
'placeholder' => '多个域名可使用,分隔',
|
||||
'show' => 'product!=\'upload\'',
|
||||
'required' => true,
|
||||
],
|
||||
],
|
||||
@ -1603,6 +1621,7 @@ ctrl+x 保存退出',
|
||||
['value'=>'cdn', 'label'=>'CDN'],
|
||||
['value'=>'blb', 'label'=>'普通型BLB'],
|
||||
['value'=>'appblb', 'label'=>'应用型BLB'],
|
||||
['value'=>'upload', 'label'=>'上传到证书管理'],
|
||||
],
|
||||
'value' => 'cdn',
|
||||
'required' => true,
|
||||
@ -1737,6 +1756,7 @@ ctrl+x 保存退出',
|
||||
['value'=>'tos', 'label'=>'对象存储TOS'],
|
||||
['value'=>'live', 'label'=>'视频直播'],
|
||||
['value'=>'imagex', 'label'=>'veImageX'],
|
||||
['value'=>'upload', 'label'=>'上传到证书管理'],
|
||||
],
|
||||
'value' => 'cdn',
|
||||
'required' => true,
|
||||
@ -1752,7 +1772,7 @@ ctrl+x 保存退出',
|
||||
'name' => '绑定的域名',
|
||||
'type' => 'input',
|
||||
'placeholder' => '多个域名可使用,分隔',
|
||||
'show' => 'product!=\'clb\'&&product!=\'alb\'',
|
||||
'show' => 'product!=\'clb\'&&product!=\'alb\'&&product!=\'upload\'',
|
||||
'required' => true,
|
||||
],
|
||||
'listener_id' => [
|
||||
@ -1948,10 +1968,22 @@ ctrl+x 保存退出',
|
||||
['value'=>'cdn', 'label'=>'CDN加速'],
|
||||
['value'=>'icdn', 'label'=>'全站加速'],
|
||||
['value'=>'accessone', 'label'=>'边缘安全加速平台'],
|
||||
['value'=>'cf', 'label'=>'函数计算'],
|
||||
],
|
||||
'value' => 'cdn',
|
||||
'required' => true,
|
||||
],
|
||||
'region_id' => [
|
||||
'name' => '所属地域',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
['value'=>'bb9fdb42056f11eda1610242ac110002', 'label'=>'华东1'],
|
||||
['value'=>'200000002368', 'label'=>'西南1'],
|
||||
],
|
||||
'value' => 'bb9fdb42056f11eda1610242ac110002',
|
||||
'show' => 'product==\'cf\'',
|
||||
'required' => true,
|
||||
],
|
||||
'domain' => [
|
||||
'name' => '绑定的域名',
|
||||
'type' => 'input',
|
||||
@ -2034,9 +2066,8 @@ ctrl+x 保存退出',
|
||||
'id' => [
|
||||
'name' => '证书ID',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'placeholder' => '留空则为添加证书',
|
||||
'note' => '在SSL证书->我的证书页面查看,注意域名是否与证书匹配',
|
||||
'required' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@ -30,7 +30,7 @@ class Ctyun
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function request($method, $path, $query = null, $params = null)
|
||||
public function request($method, $path, $query = null, $params = null, $header = null)
|
||||
{
|
||||
if (!empty($query)) {
|
||||
$query = array_filter($query, function ($a) { return $a !== null;});
|
||||
@ -50,6 +50,11 @@ class Ctyun
|
||||
if ($body) {
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
if (!empty($header)) {
|
||||
foreach ($header as $key => $value) {
|
||||
$headers[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$authorization = $this->generateSign($query, $headers, $body, $date);
|
||||
$headers['Eop-Authorization'] = $authorization;
|
||||
@ -151,7 +156,7 @@ class Ctyun
|
||||
curl_close($ch);
|
||||
|
||||
$arr = json_decode($response, true);
|
||||
if (isset($arr['statusCode']) && $arr['statusCode'] == 100000) {
|
||||
if (isset($arr['statusCode']) && ($arr['statusCode'] == 100000 || $arr['statusCode'] == 0 && $this->endpoint == 'cf-global.ctapi.ctyun.cn')) {
|
||||
return isset($arr['returnObj']) ? $arr['returnObj'] : true;
|
||||
} elseif (isset($arr['errorMessage'])) {
|
||||
throw new Exception($arr['errorMessage']);
|
||||
|
||||
232
app/lib/client/HuaweiOBS.php
Normal file
232
app/lib/client/HuaweiOBS.php
Normal file
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
namespace app\lib\client;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* 华为云OBS
|
||||
*/
|
||||
class HuaweiOBS
|
||||
{
|
||||
private $AccessKeyId;
|
||||
private $SecretAccessKey;
|
||||
private $Endpoint;
|
||||
private $proxy = false;
|
||||
|
||||
public function __construct($AccessKeyId, $SecretAccessKey, $Endpoint, $proxy = false)
|
||||
{
|
||||
$this->AccessKeyId = $AccessKeyId;
|
||||
$this->SecretAccessKey = $SecretAccessKey;
|
||||
$this->Endpoint = $Endpoint;
|
||||
$this->proxy = $proxy;
|
||||
}
|
||||
|
||||
public function setBucketCustomdomain($bucket, $domain, $cert_name, $fullchain, $privatekey)
|
||||
{
|
||||
$strXml = <<<EOF
|
||||
<CustomDomainConfiguration>
|
||||
</CustomDomainConfiguration>
|
||||
EOF;
|
||||
$xml = new \SimpleXMLElement($strXml);
|
||||
$xml->addChild('Name', $cert_name);
|
||||
$xml->addChild('Certificate', $fullchain);
|
||||
$xml->addChild('PrivateKey', $privatekey);
|
||||
$body = $xml->asXML();
|
||||
|
||||
$options = [
|
||||
'bucket' => $bucket,
|
||||
'key' => '',
|
||||
];
|
||||
$query = [
|
||||
'customdomain' => $domain
|
||||
];
|
||||
return $this->request('PUT', '/', $query, $body, $options);
|
||||
}
|
||||
|
||||
public function deleteBucketCustomdomain($bucket, $domain)
|
||||
{
|
||||
$options = [
|
||||
'bucket' => $bucket,
|
||||
'key' => '',
|
||||
];
|
||||
$query = [
|
||||
'customdomain' => $domain
|
||||
];
|
||||
return $this->request('DELETE', '/', $query, '', $options);
|
||||
}
|
||||
|
||||
public function getBucketCustomdomain($bucket)
|
||||
{
|
||||
$options = [
|
||||
'bucket' => $bucket,
|
||||
'key' => '',
|
||||
];
|
||||
$query = [
|
||||
'customdomain' => '',
|
||||
];
|
||||
return $this->request('GET', '/', $query, '', $options);
|
||||
}
|
||||
|
||||
private function request($method, $path, $query, $body, $options)
|
||||
{
|
||||
$hostname = $options['bucket'] . '.' . $this->Endpoint;
|
||||
$query_string = $this->toQueryString($query);
|
||||
$query_string = empty($query_string) ? '' : '?' . $query_string;
|
||||
$requestUrl = 'https://' . $hostname . $path . $query_string;
|
||||
$headers = [
|
||||
'Content-Type' => 'application/xml',
|
||||
'Content-MD5' => base64_encode(md5($body, true)),
|
||||
'Date' => gmdate('D, d M Y H:i:s \G\M\T'),
|
||||
];
|
||||
$headers['Authorization'] = $this->getAuthorization($method, $path, $query, $headers, $options);
|
||||
$header = [];
|
||||
foreach ($headers as $key => $value) {
|
||||
$header[] = $key . ': ' . $value;
|
||||
}
|
||||
return $this->curl($method, $requestUrl, $body, $header);
|
||||
}
|
||||
|
||||
private function curl($method, $url, $body, $header)
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
if ($this->proxy) {
|
||||
curl_set_proxy($ch);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
if (!empty($body)) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
||||
}
|
||||
$response = curl_exec($ch);
|
||||
$errno = curl_errno($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
if ($errno) {
|
||||
$errmsg = curl_error($ch);
|
||||
curl_close($ch);
|
||||
throw new Exception('Curl error: ' . $errmsg);
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode >= 200 && $httpCode < 300) {
|
||||
if (empty($response)) return true;
|
||||
return $this->xml2array($response);
|
||||
}
|
||||
$arr = $this->xml2array($response);
|
||||
if (isset($arr['Message'])) {
|
||||
throw new Exception($arr['Message']);
|
||||
} else {
|
||||
throw new Exception('HTTP Code: ' . $httpCode);
|
||||
}
|
||||
}
|
||||
|
||||
private function toQueryString($params = array())
|
||||
{
|
||||
$temp = array();
|
||||
uksort($params, 'strnatcasecmp');
|
||||
foreach ($params as $key => $value) {
|
||||
if (is_string($key) && !is_array($value)) {
|
||||
if (strlen($value) > 0) {
|
||||
$temp[] = rawurlencode($key) . '=' . rawurlencode($value);
|
||||
} else {
|
||||
$temp[] = rawurlencode($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return implode('&', $temp);
|
||||
}
|
||||
|
||||
private function xml2array($xml)
|
||||
{
|
||||
if (!$xml) {
|
||||
return false;
|
||||
}
|
||||
LIBXML_VERSION < 20900 && libxml_disable_entity_loader(true);
|
||||
return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA), JSON_UNESCAPED_UNICODE), true);
|
||||
}
|
||||
|
||||
private function getAuthorization($method, $url, $query, $headers, $options)
|
||||
{
|
||||
$method = strtoupper($method);
|
||||
$date = $headers['Date'];
|
||||
$resourcePath = $this->getResourcePath($options);
|
||||
$stringToSign = $this->calcStringToSign($method, $date, $headers, $resourcePath, $query);
|
||||
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $this->SecretAccessKey, true));
|
||||
return 'OBS ' . $this->AccessKeyId . ':' . $signature;
|
||||
}
|
||||
|
||||
private function getResourcePath(array $options)
|
||||
{
|
||||
$resourcePath = '/';
|
||||
if (strlen($options['bucket']) > 0) {
|
||||
$resourcePath .= $options['bucket'] . '/';
|
||||
}
|
||||
if (strlen($options['key']) > 0) {
|
||||
$resourcePath .= $options['key'];
|
||||
}
|
||||
return $resourcePath;
|
||||
}
|
||||
|
||||
private function calcStringToSign($method, $date, array $headers, $resourcePath, array $query)
|
||||
{
|
||||
/*
|
||||
SignToString =
|
||||
VERB + "\n"
|
||||
+ Content-MD5 + "\n"
|
||||
+ Content-Type + "\n"
|
||||
+ Date + "\n"
|
||||
+ CanonicalizedOSSHeaders
|
||||
+ CanonicalizedResource
|
||||
Signature = base64(hmac-sha1(AccessKeySecret, SignToString))
|
||||
*/
|
||||
$contentMd5 = '';
|
||||
$contentType = '';
|
||||
// CanonicalizedOSSHeaders
|
||||
$signheaders = array();
|
||||
foreach ($headers as $key => $value) {
|
||||
$lowk = strtolower($key);
|
||||
if (strncmp($lowk, "x-obs-", 6) == 0) {
|
||||
$signheaders[$lowk] = $value;
|
||||
} else if ($lowk === 'content-md5') {
|
||||
$contentMd5 = $value;
|
||||
} else if ($lowk === 'content-type') {
|
||||
$contentType = $value;
|
||||
}
|
||||
}
|
||||
ksort($signheaders);
|
||||
$canonicalizedOSSHeaders = '';
|
||||
foreach ($signheaders as $key => $value) {
|
||||
$canonicalizedOSSHeaders .= $key . ':' . $value . "\n";
|
||||
}
|
||||
// CanonicalizedResource
|
||||
$signquery = array();
|
||||
foreach ($query as $key => $value) {
|
||||
if (in_array($key, $this->signKeyList)) {
|
||||
$signquery[$key] = $value;
|
||||
}
|
||||
}
|
||||
ksort($signquery);
|
||||
$sortedQueryList = array();
|
||||
foreach ($signquery as $key => $value) {
|
||||
if (strlen($value) > 0) {
|
||||
$sortedQueryList[] = $key . '=' . $value;
|
||||
} else {
|
||||
$sortedQueryList[] = $key;
|
||||
}
|
||||
}
|
||||
$queryStringSorted = implode('&', $sortedQueryList);
|
||||
$canonicalizedResource = $resourcePath;
|
||||
if (!empty($queryStringSorted)) {
|
||||
$canonicalizedResource .= '?' . $queryStringSorted;
|
||||
}
|
||||
return $method . "\n" . $contentMd5 . "\n" . $contentType . "\n" . $date . "\n" . $canonicalizedOSSHeaders . $canonicalizedResource;
|
||||
}
|
||||
|
||||
private $signKeyList = array(
|
||||
'acl', 'policy', 'torrent', 'logging', 'location', 'storageinfo', 'quota', 'storagepolicy', 'requestpayment', 'versions', 'versioning', 'versionid', 'uploads', 'uploadid', 'partnumber', 'website', 'notification', 'lifecycle', 'deletebucket', 'delete', 'cors', 'restore', 'tagging', 'response-content-type', 'response-content-language', 'response-expires', 'response-cache-control', 'response-content-disposition', 'response-content-encoding', 'x-image-process', 'backtosource', 'storageclass', 'replication', 'append', 'position', 'x-oss-process', 'CDNNotifyConfiguration', 'attname', 'customdomain', 'directcoldaccess', 'encryption', 'inventory', 'length', 'metadata', 'modify', 'name', 'rename', 'truncate', 'x-image-save-bucket', 'x-image-save-object', 'x-obs-security-token', 'x-obs-callback'
|
||||
);
|
||||
}
|
||||
@ -66,6 +66,7 @@ class aliyun implements DeployInterface
|
||||
$this->deploy_alb($cert_id, $config);
|
||||
} elseif ($config['product'] == 'nlb') {
|
||||
$this->deploy_nlb($cert_id, $config);
|
||||
} elseif ($config['product'] == 'upload') {
|
||||
} else {
|
||||
throw new Exception('未知的产品类型');
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ class baidu implements DeployInterface
|
||||
$this->deploy_blb($cert_id, $config);
|
||||
} elseif ($config['product'] == 'appblb') {
|
||||
$this->deploy_appblb($cert_id, $config);
|
||||
} elseif ($config['product'] == 'upload') {
|
||||
} else {
|
||||
throw new Exception('不支持的产品类型');
|
||||
}
|
||||
|
||||
@ -43,7 +43,39 @@ class cdnfly implements DeployInterface
|
||||
public function deploy($fullchain, $privatekey, $config, &$info)
|
||||
{
|
||||
$id = $config['id'];
|
||||
if (empty($id)) throw new Exception('证书ID不能为空');
|
||||
if (empty($id)) {
|
||||
$certInfo = openssl_x509_parse($fullchain, true);
|
||||
if (!$certInfo) throw new Exception('证书解析失败');
|
||||
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
|
||||
$params = [
|
||||
'type' => 'custom',
|
||||
'name' => $cert_name,
|
||||
'cert' => $fullchain,
|
||||
'key' => $privatekey,
|
||||
];
|
||||
if ($this->auth == 1) {
|
||||
$access_token = $this->login();
|
||||
$url = $this->url . '/v1/certs';
|
||||
$body = json_encode($params);
|
||||
$headers = [
|
||||
'Access-Token' => $access_token,
|
||||
];
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, 'POST');
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['code']) && $result['code'] == 0) {
|
||||
$id = $result['data'];
|
||||
} elseif (isset($result['msg'])) {
|
||||
throw new Exception('证书添加失败,' . $result['msg']);
|
||||
} else {
|
||||
throw new Exception('证书添加失败,返回数据解析失败');
|
||||
}
|
||||
} else {
|
||||
$id = $this->request('/v1/certs', $params, 'POST');
|
||||
}
|
||||
$this->log("证书ID:{$id}添加成功!");
|
||||
$info['config']['id'] = $id;
|
||||
return;
|
||||
}
|
||||
|
||||
$params = [
|
||||
'type' => 'custom',
|
||||
|
||||
@ -39,6 +39,8 @@ class ctyun implements DeployInterface
|
||||
$this->deploy_icdn($fullchain, $privatekey, $config);
|
||||
} elseif ($config['product'] == 'accessone') {
|
||||
$this->deploy_accessone($fullchain, $privatekey, $config);
|
||||
} elseif ($config['product'] == 'cf') {
|
||||
$this->deploy_cf($fullchain, $privatekey, $config);
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,6 +172,44 @@ class ctyun implements DeployInterface
|
||||
$this->log('边缘安全加速域名 ' . $config['domain'] . ' 部署证书成功!');
|
||||
}
|
||||
|
||||
private function deploy_cf($fullchain, $privatekey, $config)
|
||||
{
|
||||
$client = new CtyunClient($this->AccessKeyId, $this->SecretAccessKey, 'cf-global.ctapi.ctyun.cn', $this->proxy);
|
||||
try {
|
||||
$data = $client->request('GET', '/openapi/v1/domains/customdomains/' . $config['domain'], null, null, ['regionId' => $config['region_id']]);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('获取自定义域名配置失败:' . $e->getMessage());
|
||||
}
|
||||
|
||||
if (isset($data['certConfig']['certificate']) && trim($data['certConfig']['certificate']) == trim($fullchain)) {
|
||||
$this->log('函数计算域名 ' . $config['domain'] . ' 证书已部署,无需重复操作!');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($data['protocol'] == 'HTTP') $data['protocol'] = 'HTTP,HTTPS';
|
||||
$param = [
|
||||
'domainName' => $config['domain'],
|
||||
'description' => $data['description'],
|
||||
'protocol' => $data['protocol'],
|
||||
'certConfig' => [
|
||||
'certName' => 'cert' . substr($config['cert_name'], strpos($config['cert_name'], '-') + 1),
|
||||
'certificate' => $fullchain,
|
||||
'privateKey' => $privatekey,
|
||||
],
|
||||
'authConfig' => $data['authConfig'],
|
||||
'routeConfig' => $data['routeConfig'],
|
||||
];
|
||||
try {
|
||||
$client->request('PUT', '/openapi/v1/domains/customdomains/' . $config['domain'], null, $param, ['regionId' => $config['region_id']]);
|
||||
} catch (Exception $e) {
|
||||
if (strpos($e->getMessage(), '请求已提交,请勿重复操作!') === false) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->log('函数计算域名 ' . $config['domain'] . ' 部署证书成功!');
|
||||
}
|
||||
|
||||
public function setLogger($func)
|
||||
{
|
||||
$this->logger = $func;
|
||||
|
||||
@ -4,6 +4,7 @@ namespace app\lib\deploy;
|
||||
|
||||
use app\lib\DeployInterface;
|
||||
use app\lib\client\HuaweiCloud;
|
||||
use app\lib\client\HuaweiOBS;
|
||||
use Exception;
|
||||
|
||||
class huawei implements DeployInterface
|
||||
@ -39,6 +40,11 @@ class huawei implements DeployInterface
|
||||
$this->deploy_elb($fullchain, $privatekey, $config);
|
||||
} elseif ($config['product'] == 'waf') {
|
||||
$this->deploy_waf($fullchain, $privatekey, $config);
|
||||
} elseif ($config['product'] == 'obs') {
|
||||
$this->deploy_obs($fullchain, $privatekey, $config);
|
||||
} elseif ($config['product'] == 'upload') {
|
||||
$cert_id = $this->get_cert_id($fullchain, $privatekey);
|
||||
$info['cert_id'] = $cert_id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,6 +123,19 @@ class huawei implements DeployInterface
|
||||
$this->log('WAF证书ID ' . $config['cert_id'] . ' 更新证书成功!');
|
||||
}
|
||||
|
||||
private function deploy_obs($fullchain, $privatekey, $config)
|
||||
{
|
||||
if (empty($config['domain'])) throw new Exception('绑定的域名不能为空');
|
||||
if (empty($config['obs_endpoint'])) throw new Exception('OBS Endpoint不能为空');
|
||||
if (empty($config['obs_bucket'])) throw new Exception('OBS 桶名称不能为空');
|
||||
$obsClient = new HuaweiOBS($this->AccessKeyId, $this->SecretAccessKey, $config['obs_endpoint'], $this->proxy);
|
||||
foreach (explode(',', $config['domain']) as $domain) {
|
||||
if (empty($domain)) continue;
|
||||
$obsClient->setBucketCustomdomain($config['obs_bucket'], $domain, $config['cert_name'], $fullchain, $privatekey);
|
||||
$this->log('OSS域名 ' . $domain . ' 部署证书成功!');
|
||||
}
|
||||
}
|
||||
|
||||
private function get_cert_id($fullchain, $privatekey)
|
||||
{
|
||||
$certInfo = openssl_x509_parse($fullchain, true);
|
||||
|
||||
@ -191,7 +191,7 @@ class huoshan implements DeployInterface
|
||||
if (!$certInfo) throw new Exception('证书解析失败');
|
||||
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
|
||||
|
||||
$client = new Volcengine($this->AccessKeyId, $this->SecretAccessKey, 'open.volcengineapi.com', 'certificate_service', '2024-10-01', 'cn-beijing', $this->proxy);
|
||||
$client = new Volcengine($this->AccessKeyId, $this->SecretAccessKey, 'certificate-service.volcengineapi.com', 'certificate_service', '2024-10-01', 'cn-beijing', $this->proxy);
|
||||
$param = [
|
||||
'Tag' => $cert_name,
|
||||
'Repeatable' => false,
|
||||
@ -207,10 +207,20 @@ class huoshan implements DeployInterface
|
||||
}
|
||||
if (!empty($data['InstanceId'])) {
|
||||
$cert_id = $data['InstanceId'];
|
||||
$this->log('上传证书成功 CertId=' . $cert_id);
|
||||
|
||||
$param = [
|
||||
'InstanceId' => $cert_id,
|
||||
'Options' => [
|
||||
'ExpiredNotice' => 'Disabled',
|
||||
],
|
||||
];
|
||||
$client->request('POST', 'CertificateUpdateInstance', $param);
|
||||
|
||||
} else {
|
||||
$cert_id = $data['RepeatId'];
|
||||
$this->log('找到已上传的证书 CertId=' . $cert_id);
|
||||
}
|
||||
$this->log('上传证书成功 CertId=' . $cert_id);
|
||||
return $cert_id;
|
||||
}
|
||||
|
||||
|
||||
@ -41,13 +41,29 @@ class lecdn implements DeployInterface
|
||||
|
||||
public function deploy($fullchain, $privatekey, $config, &$info)
|
||||
{
|
||||
$id = $config['id'];
|
||||
if (empty($id)) throw new Exception('证书ID不能为空');
|
||||
|
||||
if ($this->auth == 0) {
|
||||
$this->login();
|
||||
}
|
||||
|
||||
$id = $config['id'];
|
||||
if (empty($id)) {
|
||||
$certInfo = openssl_x509_parse($fullchain, true);
|
||||
if (!$certInfo) throw new Exception('证书解析失败');
|
||||
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
|
||||
$params = [
|
||||
'name' => $cert_name,
|
||||
'type' => 'upload',
|
||||
'ssl_pem' => base64_encode($fullchain),
|
||||
'ssl_key' => base64_encode($privatekey),
|
||||
'auto_renewal' => false,
|
||||
];
|
||||
$data = $this->request('/prod-api/certificate', $params, 'POST');
|
||||
$id = $data['id'];
|
||||
$this->log("证书ID:{$id}添加成功!");
|
||||
$info['config']['id'] = $id;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = $this->request('/prod-api/certificate/' . $id);
|
||||
} catch (Exception $e) {
|
||||
|
||||
@ -44,10 +44,10 @@ class opanel implements DeployInterface
|
||||
// 没有指定节点,只部署到主控节点
|
||||
try {
|
||||
$this->request('/core/settings/ssl/update', $params);
|
||||
$this->log("主节点面板证书更新成功!");
|
||||
$this->log("面板证书更新成功!");
|
||||
return;
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("主节点面板证书更新失败:" . $e->getMessage());
|
||||
throw new Exception("面板证书更新失败:" . $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
// 同时部署到主节点和所有指定的子节点
|
||||
@ -131,11 +131,11 @@ class opanel implements DeployInterface
|
||||
];
|
||||
try {
|
||||
$this->request('/websites/ssl/upload', $params, $nodeName);
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书ID:{$config['id']}更新成功!" : "主节点 证书ID:{$config['id']}更新成功!";
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书ID:{$config['id']}更新成功!" : "证书ID:{$config['id']}更新成功!";
|
||||
$this->log($logMsg);
|
||||
return;
|
||||
} catch (Exception $e) {
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书ID:{$config['id']}更新失败:" : "主节点 证书ID:{$config['id']}更新失败:";
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书ID:{$config['id']}更新失败:" : "证书ID:{$config['id']}更新失败:";
|
||||
throw new Exception($logMsg . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@ -147,10 +147,10 @@ class opanel implements DeployInterface
|
||||
$params = ['page' => 1, 'pageSize' => 500];
|
||||
try {
|
||||
$data = $this->request("/websites/ssl/search", $params, $nodeName);
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] " : "主节点 ";
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] " : "";
|
||||
$this->log($logMsg . '获取证书列表成功(total=' . $data['total'] . ')');
|
||||
} catch (Exception $e) {
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] " : "主节点 ";
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] " : "";
|
||||
throw new Exception($logMsg . '获取证书列表失败:' . $e->getMessage());
|
||||
}
|
||||
|
||||
@ -179,12 +179,12 @@ class opanel implements DeployInterface
|
||||
];
|
||||
try {
|
||||
$this->request('/websites/ssl/upload', $params, $nodeName);
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书ID:{$row['id']}更新成功!" : "主节点 证书ID:{$row['id']}更新成功!";
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书ID:{$row['id']}更新成功!" : "证书ID:{$row['id']}更新成功!";
|
||||
$this->log($logMsg);
|
||||
$success++;
|
||||
} catch (Exception $e) {
|
||||
$errmsg = $e->getMessage();
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书ID:{$row['id']}更新失败:" : "主节点 证书ID:{$row['id']}更新失败:";
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书ID:{$row['id']}更新失败:" : "证书ID:{$row['id']}更新失败:";
|
||||
$this->log($logMsg . $errmsg);
|
||||
}
|
||||
}
|
||||
@ -199,7 +199,7 @@ class opanel implements DeployInterface
|
||||
'description' => '',
|
||||
];
|
||||
$this->request('/websites/ssl/upload', $params, $nodeName);
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书上传成功!" : "主节点 证书上传成功!";
|
||||
$logMsg = $nodeName ? "节点 [{$nodeName}] 证书上传成功!" : "证书上传成功!";
|
||||
$this->log($logMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,9 @@ class qiniu implements DeployInterface
|
||||
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
|
||||
|
||||
$cert_id = $this->get_cert_id($fullchain, $privatekey, $certInfo['subject']['CN'], $cert_name);
|
||||
$info['cert_id'] = $cert_id;
|
||||
$info['cert_name'] = $cert_name;
|
||||
if ($config['product'] == 'upload') return;
|
||||
|
||||
foreach (explode(',', $domains) as $domain) {
|
||||
if (empty($domain)) continue;
|
||||
@ -50,8 +53,6 @@ class qiniu implements DeployInterface
|
||||
throw new Exception('未知的产品类型');
|
||||
}
|
||||
}
|
||||
$info['cert_id'] = $cert_id;
|
||||
$info['cert_name'] = $cert_name;
|
||||
}
|
||||
|
||||
private function deploy_cdn($domain, $cert_id)
|
||||
|
||||
@ -26,19 +26,43 @@ class rainyun implements DeployInterface
|
||||
|
||||
public function deploy($fullchain, $privatekey, $config, &$info)
|
||||
{
|
||||
if (empty($config['id'])) throw new Exception('证书ID不能为空');
|
||||
if (empty($config['id'])) {
|
||||
$params = [
|
||||
'cert' => $fullchain,
|
||||
'key' => $privatekey,
|
||||
];
|
||||
try {
|
||||
$this->request('/product/sslcenter/', $params, 'POST');
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('上传证书失败,' . $e->getMessage());
|
||||
}
|
||||
|
||||
$params = [
|
||||
'cert' => $fullchain,
|
||||
'key' => $privatekey,
|
||||
];
|
||||
try {
|
||||
$this->request('/product/sslcenter/' . $config['id'], $params, 'PUT');
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
$params = [
|
||||
'options' => '{"columnFilters":{"Domain":""},"sort":[],"page":1,"perPage":1}',
|
||||
];
|
||||
try {
|
||||
$data = $this->request('/product/sslcenter/?' . http_build_query($params), null, 'GET');
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('获取证书列表失败,' . $e->getMessage());
|
||||
}
|
||||
if (empty($data['Records'])) throw new Exception('未找到已上传的证书');
|
||||
$cert_id = $data['Records'][0]['ID'];
|
||||
$info['config']['id'] = $cert_id;
|
||||
|
||||
$this->log('证书ID:' . $cert_id . '添加成功!');
|
||||
} else {
|
||||
$params = [
|
||||
'cert' => $fullchain,
|
||||
'key' => $privatekey,
|
||||
];
|
||||
try {
|
||||
$this->request('/product/sslcenter/' . $config['id'], $params, 'PUT');
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
|
||||
$this->log('证书ID:' . $config['id'] . '更新成功!');
|
||||
}
|
||||
|
||||
$this->log('证书ID:' . $config['id'] . '更新成功!');
|
||||
}
|
||||
|
||||
private function request($path, $params = null, $method = null)
|
||||
@ -55,7 +79,7 @@ class rainyun implements DeployInterface
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['code']) && $result['code'] == 200) {
|
||||
return $result;
|
||||
return isset($result['data']) ? $result['data'] : null;
|
||||
} elseif (isset($result['message'])) {
|
||||
throw new Exception($result['message']);
|
||||
} else {
|
||||
|
||||
@ -36,6 +36,7 @@ class tencent implements DeployInterface
|
||||
}
|
||||
$cert_id = $this->get_cert_id($fullchain, $privatekey);
|
||||
if (!$cert_id) throw new Exception('证书ID获取失败');
|
||||
$info['cert_id'] = $cert_id;
|
||||
if ($config['product'] == 'cos') {
|
||||
if (empty($config['regionid'])) throw new Exception('所属地域ID不能为空');
|
||||
if (empty($config['cos_bucket'])) throw new Exception('存储桶名称不能为空');
|
||||
@ -65,6 +66,8 @@ class tencent implements DeployInterface
|
||||
return $this->deploy_scf($cert_id, $config);
|
||||
} elseif ($config['product'] == 'teo' && isset($config['site_id'])) {
|
||||
return $this->deploy_teo($cert_id, $config);
|
||||
} elseif ($config['product'] == 'upload') {
|
||||
return;
|
||||
} else {
|
||||
if (empty($config['domain'])) throw new Exception('绑定的域名不能为空');
|
||||
if ($config['product'] == 'waf') {
|
||||
@ -77,7 +80,6 @@ class tencent implements DeployInterface
|
||||
}
|
||||
try {
|
||||
$record_id = $this->deploy_common($config['product'], $cert_id, $instance_id);
|
||||
$info['cert_id'] = $cert_id;
|
||||
$info['record_id'] = $record_id;
|
||||
} catch (Exception $e) {
|
||||
if (isset($info['record_id'])) {
|
||||
|
||||
@ -92,8 +92,11 @@ class upyun implements DeployInterface
|
||||
}
|
||||
}
|
||||
|
||||
if ($i == 0) throw new Exception('未找到可迁移的证书');
|
||||
$this->log('共迁移' . $i . '个证书,关联域名' . $d . '个');
|
||||
if ($i == 0) {
|
||||
$this->log('未找到可迁移的证书');
|
||||
} else {
|
||||
$this->log('共迁移' . $i . '个证书,关联域名' . $d . '个');
|
||||
}
|
||||
}
|
||||
|
||||
private function login()
|
||||
|
||||
@ -70,8 +70,15 @@ class CertDeployService
|
||||
$this->saveResult(-1, $e->getMessage(), date('Y-m-d H:i:s', time() + (array_key_exists($this->task['retry'], self::$retry_interval) ? self::$retry_interval[$this->task['retry']] : 3600)));
|
||||
throw $e;
|
||||
} finally {
|
||||
if($this->info){
|
||||
Db::name('cert_deploy')->where('id', $this->task['id'])->update(['info' => json_encode($this->info)]);
|
||||
if ($this->info && is_array($this->info)) {
|
||||
if (isset($this->info['config']) && is_array($this->info['config'])) {
|
||||
$config = array_merge(json_decode($this->task['config'], true), $this->info['config']);
|
||||
Db::name('cert_deploy')->where('id', $this->task['id'])->update(['config' => json_encode($config)]);
|
||||
unset($this->info['config']);
|
||||
}
|
||||
if (!empty($this->info)) {
|
||||
Db::name('cert_deploy')->where('id', $this->task['id'])->update(['info' => json_encode($this->info)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user