perf: 火山引擎部署alb证书插件支持部署扩展证书以及删除已过期扩展证书

This commit is contained in:
xiaojunnuo
2026-03-21 23:51:30 +08:00
parent 2ab92dc13e
commit ffd2e8149e
2 changed files with 167 additions and 9 deletions

View File

@@ -3,6 +3,7 @@ import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
import { VolcengineAccess } from "../access.js";
import { VolcengineClient } from "../ve-client.js";
import dayjs from "dayjs";
@IsTaskPlugin({
name: "VolcengineDeployToALB",
@@ -32,6 +33,7 @@ export class VolcengineDeployToALB extends AbstractTaskPlugin {
certDomains!: string[];
@TaskInput({
title: "Access授权",
helper: "火山引擎AccessKeyId、AccessKeySecret",
@@ -126,6 +128,22 @@ export class VolcengineDeployToALB extends AbstractTaskPlugin {
listenerList!: string | string[];
@TaskInput({
title: "证书部署类型",
helper: "选择部署默认证书还是扩展证书",
component: {
name: "a-select",
options: [
{ label: "默认证书", value: "default" },
{ label: "扩展证书", value: "extension" }
]
},
value: "default",
required: true
})
certType!: string;
async onInstance() {
}
@@ -149,20 +167,101 @@ export class VolcengineDeployToALB extends AbstractTaskPlugin {
const service = await this.getAlbService();
for (const listener of this.listenerList) {
this.logger.info(`开始部署监听器${listener}证书`);
await service.request({
action: "ModifyListenerAttributes",
query: {
ListenerId: listener,
CertificateSource: "cert_center",
CertCenterCertificateId: certId
}
});
this.logger.info(`部署监听器${listener}证书成功`);
if (this.certType === "default") {
// 部署默认证书
const res = await service.request({
action: "ModifyListenerAttributes",
query: {
ListenerId: listener,
CertificateSource: "cert_center",
CertCenterCertificateId: certId
}
});
this.logger.info(`部署监听器${listener}默认证书成功res:${JSON.stringify(res)}`);
} else {
// 部署扩展证书
await this.deployExtensionCertificate(service, listener, certId as string);
}
await this.ctx.utils.sleep(5000);
}
this.logger.info("部署完成");
}
private async deployExtensionCertificate(service: any, listenerId: string, certId: string) {
// 获取监听器当前的扩展证书列表
const domainExtensions = await this.getListenerDomainExtensions(service, listenerId);
// 删除过期的扩展证书
try {
await this.deleteExpiredExtensions(service, listenerId, domainExtensions);
} catch (error) {
this.logger.error(`删除过期扩展证书失败:${error.message ||error}`);
}
// 新增扩展证书
const query: any = {
ListenerId: listenerId,
"DomainExtensions.1.Action": "create",
"DomainExtensions.1.CertificateSource": "cert_center",
"DomainExtensions.1.CertCenterCertificateId": certId
};
// 如果有证书域名信息,添加到扩展证书中
if (this.certDomains && this.certDomains.length > 0) {
query["DomainExtensions.1.Domain"] = this.certDomains[0];
}
await service.request({
action: "ModifyListenerAttributes",
query: query
});
this.logger.info(`部署监听器${listenerId}扩展证书成功`);
}
private async getListenerDomainExtensions(service: any, listenerId: string): Promise<any[]> {
const res = await service.request({
action: "DescribeListenerAttributes",
method: "GET",
query: {
ListenerId: listenerId
}
});
return res.Result.DomainExtensions || [];
}
private async deleteExpiredExtensions(service: any, listenerId: string, domainExtensions: any[]) {
const expiredExtensions = [];
for (const ext of domainExtensions) {
if (!await this.isCertificateExpired(ext)) {
expiredExtensions.push(ext);
}
}
if (expiredExtensions.length === 0) {
this.logger.info(`没有过期的扩展证书,跳过删除`);
return;
}
const query: any = {
ListenerId: listenerId
};
expiredExtensions.forEach((ext, index) => {
const idx = index + 1;
query[`DomainExtensions.${idx}.Action`] = "delete";
query[`DomainExtensions.${idx}.DomainExtensionId`] = ext.DomainExtensionId;
});
this.logger.info(`准备删除过期扩展证书,数量:${expiredExtensions.length}query:${JSON.stringify(query)}`);
await service.request({
action: "ModifyListenerAttributes",
query: query
});
this.logger.info(`删除${expiredExtensions.length}个过期扩展证书成功`);
await this.ctx.utils.sleep(5000);
}
private async getCertService(access: VolcengineAccess) {
const client = new VolcengineClient({
@@ -189,6 +288,54 @@ export class VolcengineDeployToALB extends AbstractTaskPlugin {
return service;
}
private async isCertificateExpired(extension: any): Promise<boolean> {
try {
let certificateId: string;
// 根据证书来源获取证书ID
if (extension.CertificateSource === "cert_center") {
certificateId = extension.CertCenterCertificateId;
} else if (extension.CertificateSource === "alb") {
this.logger.warn(`ALB证书不支持过期检查跳过`);
return false;
} else if (extension.CertificateSource === "pca_leaf") {
this.logger.warn(`PCA Leaf证书不支持过期检查跳过`);
return false;
} else {
this.logger.warn(`未知的证书来源: ${extension.CertificateSource},跳过`);
return false;
}
if (!certificateId) {
this.logger.warn(`证书ID为空跳过`);
return false;
}
// 获取证书服务
const access = await this.getAccess<VolcengineAccess>(this.accessId);
const certService = await this.getCertService(access);
// 获取证书详情
const certDetail = await certService.GetCertificateDetail(certificateId);
// 判断证书是否过期
if (certDetail.NotAfter) {
const expireTime = dayjs(certDetail.NotAfter);
const now = dayjs();
const isExpired = expireTime.isBefore(now);
if (isExpired) {
this.logger.info(`证书 ${certificateId} 已过期,过期时间: ${expireTime.toISOString()}`);
}
return isExpired;
}
return false;
} catch (error) {
this.logger.error(`检查证书是否过期失败: ${error.message || error}`);
return false;
}
}
async onGetListenerList(data: any) {
if (!this.accessId) {
throw new Error("请选择Access授权");

View File

@@ -42,6 +42,17 @@ export class VolcengineClient {
});
return res.Result.InstanceId || res.Result.RepeatId;
};
service.GetCertificateDetail = async (certificateId: string) => {
const res = await service.request({
action: "CertificateGetInstance",
method: "POST",
body: {
InstanceId: certificateId
}
});
return res.Result;
};
return service;
}