mirror of
https://github.com/certd/certd.git
synced 2026-04-14 12:30:54 +08:00
233 lines
6.0 KiB
TypeScript
233 lines
6.0 KiB
TypeScript
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||
import { CertApplyPluginNames, CertInfo, CertReader } from "@certd/plugin-cert";
|
||
import {
|
||
AliyunAccess, AliyunClientV2,
|
||
AliyunSslClient,
|
||
createCertDomainGetterInputDefine,
|
||
createRemoteSelectInputDefine
|
||
} from "@certd/plugin-lib";
|
||
|
||
@IsTaskPlugin({
|
||
name: "AliyunDeployCertToESA",
|
||
title: "阿里云-部署至ESA",
|
||
icon: "svg:icon-aliyun",
|
||
group: pluginGroups.aliyun.key,
|
||
desc: "部署证书到阿里云ESA(边缘安全加速)",
|
||
needPlus: false,
|
||
default: {
|
||
strategy: {
|
||
runStrategy: RunStrategy.SkipWhenSucceed
|
||
}
|
||
}
|
||
})
|
||
export class AliyunDeployCertToESA extends AbstractTaskPlugin {
|
||
@TaskInput({
|
||
title: "域名证书",
|
||
helper: "请选择证书申请任务输出的域名证书",
|
||
component: {
|
||
name: "output-selector",
|
||
from: [...CertApplyPluginNames, 'uploadCertToAliyun']
|
||
},
|
||
required: true
|
||
})
|
||
cert!: CertInfo;
|
||
|
||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||
certDomains!: string[];
|
||
|
||
@TaskInput({
|
||
title: "大区",
|
||
value: "cn-hangzhou",
|
||
component: {
|
||
name: "a-auto-complete",
|
||
vModel: "value",
|
||
options: [
|
||
{ value: "cn-hangzhou", label: "华东1(杭州)" },
|
||
{ value: "ap-southeast-1", label: "新加坡" }
|
||
]
|
||
},
|
||
required: true
|
||
})
|
||
regionId!: string;
|
||
|
||
@TaskInput({
|
||
title: "证书接入点",
|
||
helper: "不会选就保持默认即可",
|
||
value: "cas.aliyuncs.com",
|
||
component: {
|
||
name: "a-select",
|
||
options: [
|
||
{ value: "cas.aliyuncs.com", label: "中国大陆" },
|
||
{ value: "cas.ap-southeast-1.aliyuncs.com", label: "新加坡" }
|
||
// { value: "cas.eu-central-1.aliyuncs.com", label: "德国(法兰克福)" }
|
||
]
|
||
},
|
||
required: true
|
||
})
|
||
casEndpoint!: string;
|
||
|
||
|
||
@TaskInput({
|
||
title: "Access授权",
|
||
helper: "阿里云授权AccessKeyId、AccessKeySecret",
|
||
component: {
|
||
name: "access-selector",
|
||
type: "aliyun"
|
||
},
|
||
required: true
|
||
})
|
||
accessId!: string;
|
||
|
||
@TaskInput(
|
||
createRemoteSelectInputDefine({
|
||
title: "站点",
|
||
helper: "请选择要部署证书的站点",
|
||
action: AliyunDeployCertToESA.prototype.onGetSiteList.name,
|
||
watches: ["accessId", "regionId"]
|
||
})
|
||
)
|
||
siteIds!: string[];
|
||
|
||
|
||
async onInstance() {
|
||
}
|
||
|
||
async getAliyunCertId(access: AliyunAccess) {
|
||
let certId: any = this.cert;
|
||
let certName: any = this.appendTimeSuffix("certd");
|
||
if (typeof this.cert === "object") {
|
||
const sslClient = new AliyunSslClient({
|
||
access,
|
||
logger: this.logger,
|
||
endpoint: this.casEndpoint
|
||
});
|
||
|
||
certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt));
|
||
|
||
certId = await sslClient.uploadCert({
|
||
name: certName,
|
||
cert: this.cert
|
||
});
|
||
this.logger.info("上传证书成功", certId, certName);
|
||
}
|
||
return {
|
||
certId,
|
||
certName
|
||
};
|
||
}
|
||
|
||
async execute(): Promise<void> {
|
||
this.logger.info("开始部署证书到阿里云");
|
||
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||
|
||
const client = await this.getClient(access);
|
||
|
||
const { certId, certName } = await this.getAliyunCertId(access);
|
||
|
||
for (const siteId of this.siteIds) {
|
||
try {
|
||
const res = await client.doRequest({
|
||
// 接口名称
|
||
action: "SetCertificate",
|
||
// 接口版本
|
||
version: "2024-09-10",
|
||
data: {
|
||
body:{
|
||
SiteId: siteId,
|
||
CasId: certId,
|
||
Type: "cas",
|
||
Name: certName
|
||
}
|
||
}
|
||
});
|
||
this.logger.info(`部署站点[${siteId}]证书成功:${JSON.stringify(res)}`);
|
||
|
||
} catch (e) {
|
||
if (e.message.includes("Certificate.Duplicated")) {
|
||
this.logger.info(`站点[${siteId}]证书已存在,无需重复部署`);
|
||
}else{
|
||
throw e;
|
||
}
|
||
}
|
||
|
||
try{
|
||
await this.clearSiteCert(client,siteId);
|
||
}catch (e) {
|
||
this.logger.error("清理站点[${siteId}]证书失败",e)
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
async getClient(access: AliyunAccess) {
|
||
const endpoint = `esa.${this.regionId}.aliyuncs.com`;
|
||
return access.getClient(endpoint);
|
||
}
|
||
|
||
async onGetSiteList(data: any) {
|
||
if (!this.accessId) {
|
||
throw new Error("请选择Access授权");
|
||
}
|
||
const access = await this.getAccess<AliyunAccess>(this.accessId);
|
||
|
||
const client = await this.getClient(access);
|
||
const res = await client.doRequest({
|
||
action: "ListSites",
|
||
version: "2024-09-10",
|
||
method: "GET",
|
||
data: {}
|
||
});
|
||
|
||
const list = res?.Sites;
|
||
if (!list || list.length === 0) {
|
||
throw new Error("没有找到站点,请先创建站点");
|
||
}
|
||
|
||
const options = list.map((item: any) => {
|
||
return {
|
||
label: item.SiteName,
|
||
value: item.SiteId,
|
||
domain: item.SiteName
|
||
};
|
||
});
|
||
return this.ctx.utils.options.buildGroupOptions(options, this.certDomains);
|
||
}
|
||
|
||
async clearSiteCert(client: AliyunClientV2, siteId: string) {
|
||
this.logger.info(`开始清理站点[${siteId}]过期证书`);
|
||
const certListRes = await client.doRequest({
|
||
action: "ListCertificates",
|
||
version: "2024-09-10",
|
||
method: "GET",
|
||
data:{
|
||
query: {
|
||
SiteId: siteId
|
||
}
|
||
}
|
||
});
|
||
|
||
const list = certListRes.Result;
|
||
for (const item of list) {
|
||
this.logger.info(`证书${item.Name}状态:${item.Status}`);
|
||
if (item.Status === "Expired") {
|
||
this.logger.info(`证书${item.Name}已过期,执行删除`);
|
||
await client.doRequest({
|
||
action: "DeleteCertificate",
|
||
version: "2024-09-10",
|
||
// 接口 HTTP 方法
|
||
method: "GET",
|
||
data:{
|
||
query: {
|
||
SiteId: siteId,
|
||
Id: item.id
|
||
}
|
||
}
|
||
});
|
||
this.logger.info(`证书${item.Name}已删除`);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
new AliyunDeployCertToESA();
|