import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { CertInfo ,CertApplyPluginNames, CertReader} from '@certd/plugin-cert'; import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; @IsTaskPlugin({ name: 'AliyunDeployCertToALB', title: '阿里云-部署至ALB(应用负载均衡)', icon: 'svg:icon-aliyun', group: pluginGroups.aliyun.key, desc: 'ALB,更新监听器的默认证书', needPlus: false, default: { strategy: { runStrategy: RunStrategy.SkipWhenSucceed, }, }, }) export class AliyunDeployCertToALB extends AbstractTaskPlugin { @TaskInput({ title: '域名证书', helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID,可以减少上传到阿里云的证书数量', component: { name: 'output-selector', from: [...CertApplyPluginNames, 'uploadCertToAliyun'], }, required: true, }) cert!: CertInfo | number; @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) certDomains!: string[]; @TaskInput({ title: 'Access授权', helper: '阿里云授权AccessKeyId、AccessKeySecret', component: { name: 'access-selector', type: 'aliyun', }, required: true, }) accessId!: string; @TaskInput( createRemoteSelectInputDefine({ title: 'ALB所在地区', typeName: 'AliyunDeployCertToALB', multi: false, action: AliyunDeployCertToALB.prototype.onGetRegionList.name, watches: ['accessId'], }) ) regionId: string; @TaskInput( createRemoteSelectInputDefine({ title: '负载均衡列表', helper: '要部署证书的负载均衡ID', typeName: 'AliyunDeployCertToALB', action: AliyunDeployCertToALB.prototype.onGetLoadBalanceList.name, watches: ['regionId'], }) ) loadBalancers!: string[]; @TaskInput( createRemoteSelectInputDefine({ title: '监听器列表', helper: '要部署证书的监听器列表', typeName: 'AliyunDeployCertToALB', action: AliyunDeployCertToALB.prototype.onGetListenerList.name, watches: ['loadBalancers'], }) ) listeners!: 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; async onInstance() {} async getLBClient(access: AliyunAccess, region: string) { const client = new AliyunClient({ logger: this.logger }); const version = '2020-06-16'; await client.init({ accessKeyId: access.accessKeyId, accessKeySecret: access.accessKeySecret, //https://wafopenapi.cn-hangzhou.aliyuncs.com endpoint: `https://alb.${region}.aliyuncs.com`, apiVersion: version, }); return client; } async execute(): Promise { this.logger.info(`开始部署证书到阿里云(alb)`); const access = await this.getAccess(this.accessId); const certId = await this.getAliyunCertId(access); const client = await this.getLBClient(access, this.regionId); for (const listener of this.listeners) { //查询原来的证书 let params: any = {}; params = { ListenerId: listener, Certificates: [ { CertificateId: certId, }, ], }; const res = await client.request('UpdateListenerAttribute', params); this.checkRet(res); this.logger.info(`部署${listener}监听器证书成功`, JSON.stringify(res)); //删除旧证书关联 } this.logger.info('执行完成'); } async getAliyunCertId(access: AliyunAccess) { let certId: any = this.cert; if (typeof this.cert === 'object') { const sslClient = new AliyunSslClient({ access, logger: this.logger, endpoint: this.casEndpoint, }); const certName = this.buildCertName(CertReader.getMainDomain(this.cert.crt)) certId = await sslClient.uploadCert({ name: certName, cert: this.cert, }); } return certId; } async onGetRegionList(data: any) { if (!this.accessId) { throw new Error('请选择Access授权'); } const access = await this.getAccess(this.accessId); const client = await this.getLBClient(access, 'cn-shanghai'); const res = await client.request('DescribeRegions', {}); this.checkRet(res); if (!res?.Regions || res?.Regions.length === 0) { throw new Error('没有找到Regions列表'); } return res.Regions.map((item: any) => { return { label: item.LocalName, value: item.RegionId, endpoint: item.RegionEndpoint, }; }); } async onGetLoadBalanceList(data: any) { if (!this.accessId) { throw new Error('请先选择Access授权'); } if (!this.regionId) { throw new Error('请先选择地区'); } const access = await this.getAccess(this.accessId); const client = await this.getLBClient(access, this.regionId); const params = { MaxResults: 100, }; const res = await client.request('ListLoadBalancers', params); this.checkRet(res); if (!res?.LoadBalancers || res?.LoadBalancers.length === 0) { throw new Error('没有找到LoadBalancers'); } return res.LoadBalancers.map((item: any) => { const label = `${item.LoadBalancerId}<${item.LoadBalancerName}}>`; return { label: label, value: item.LoadBalancerId, }; }); } async onGetListenerList(data: any) { if (!this.accessId) { throw new Error('请先选择Access授权'); } if (!this.regionId) { throw new Error('请先选择地区'); } const access = await this.getAccess(this.accessId); const client = await this.getLBClient(access, this.regionId); const params: any = { MaxResults: 100, }; if (this.loadBalancers && this.loadBalancers.length > 0) { params.LoadBalancerIds = this.loadBalancers; } const res = await client.request('ListListeners', params); this.checkRet(res); if (!res?.Listeners || res?.Listeners.length === 0) { throw new Error('没有找到HTTPS监听器'); } return res.Listeners.map((item: any) => { const label = `${item.ListenerId}<${item.ListenerDescription}@${item.LoadBalancerId}>`; return { label: label, value: item.ListenerId, lbid: item.LoadBalancerId, }; }); } checkRet(ret: any) { if (ret.Code != null) { throw new Error(ret.Message); } } } new AliyunDeployCertToALB();