mirror of https://github.com/certd/certd
				
				
				
			perf: 支持部署到阿里云云原生API网关、AI网关
							parent
							
								
									17f23f3751
								
							
						
					
					
						commit
						2ca20be197
					
				|  | @ -7,9 +7,9 @@ export type AliyunClientV2Req = { | |||
|   // 接口 HTTP 方法
 | ||||
|   method?: "GET" | "POST"; | ||||
|   authType?: "AK"; | ||||
|   style?: "RPC"; | ||||
|   style?: "RPC" | "ROA"; | ||||
|   // 接口 PATH
 | ||||
|   pathname?: `/`; | ||||
|   pathname?: string; | ||||
| 
 | ||||
|   data?: any; | ||||
| }; | ||||
|  | @ -63,10 +63,10 @@ export class AliyunClientV2 { | |||
|       protocol: "HTTPS", | ||||
|       // 接口 HTTP 方法
 | ||||
|       method: req.method ?? "POST", | ||||
|       authType: "AK", | ||||
|       style: "RPC", | ||||
|       authType: req.authType ?? "AK", | ||||
|       style: req.style ?? "RPC", | ||||
|       // 接口 PATH
 | ||||
|       pathname: `/`, | ||||
|       pathname: req.pathname ?? `/`, | ||||
|       // 接口请求体内容格式
 | ||||
|       reqBodyType: "json", | ||||
|       // 接口响应体内容格式
 | ||||
|  |  | |||
|  | @ -9,7 +9,8 @@ export type AliyunCertInfo = { | |||
| export type AliyunSslClientOpts = { | ||||
|   access: AliyunAccess; | ||||
|   logger: ILogger; | ||||
|   endpoint: string; | ||||
|   endpoint?: string; | ||||
|   region?: string; | ||||
| }; | ||||
| 
 | ||||
| export type AliyunSslGetResourceListReq = { | ||||
|  | @ -48,10 +49,19 @@ export class AliyunSslClient { | |||
|   async getClient() { | ||||
|     const access = this.opts.access; | ||||
|     const client = new AliyunClient({ logger: this.opts.logger }); | ||||
| 
 | ||||
|     let endpoint = this.opts.endpoint || "cas.aliyuncs.com"; | ||||
|     if (this.opts.endpoint == null && this.opts.region) { | ||||
|       if (this.opts.region === "cn-hangzhou") { | ||||
|         endpoint = "cas.aliyuncs.com"; | ||||
|       } else { | ||||
|         endpoint = `cas.${this.opts.region}.aliyuncs.com`; | ||||
|       } | ||||
|     } | ||||
|     await client.init({ | ||||
|       accessKeyId: access.accessKeyId, | ||||
|       accessKeySecret: access.accessKeySecret, | ||||
|       endpoint: `https://${this.opts.endpoint || "cas.aliyuncs.com"}`, | ||||
|       endpoint: `https://${endpoint}`, | ||||
|       apiVersion: "2020-04-07", | ||||
|     }); | ||||
|     return client; | ||||
|  |  | |||
|  | @ -0,0 +1,272 @@ | |||
| import {AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput} from '@certd/pipeline'; | ||||
| import { | ||||
|   AliyunAccess, | ||||
|   AliyunSslClient, | ||||
|   createCertDomainGetterInputDefine, | ||||
|   createRemoteSelectInputDefine | ||||
| } from "@certd/plugin-lib"; | ||||
| import { CertApplyPluginNames, CertInfo, CertReader } from "@certd/plugin-cert"; | ||||
| import {optionsUtils} from "@certd/basic/dist/utils/util.options.js"; | ||||
| 
 | ||||
| @IsTaskPlugin({ | ||||
|   name: 'DeployCertToAliyunApig', | ||||
|   title: '阿里云-部署至云原生API网关/AI网关', | ||||
|   icon: 'svg:icon-aliyun', | ||||
|   group: pluginGroups.aliyun.key, | ||||
|   desc: '自动部署域名证书至云原生API网关、AI网关', | ||||
|   default: { | ||||
|     strategy: { | ||||
|       runStrategy: RunStrategy.SkipWhenSucceed, | ||||
|     }, | ||||
|   }, | ||||
| }) | ||||
| export class DeployCertToAliyunApig extends AbstractTaskPlugin { | ||||
|   @TaskInput({ | ||||
|     title: '域名证书', | ||||
|     helper: '请选择前置任务输出的域名证书', | ||||
|     component: { | ||||
|       name: 'output-selector', | ||||
|       from: [...CertApplyPluginNames, 'uploadCertToAliyun'], | ||||
|     }, | ||||
|     required: true, | ||||
|   }) | ||||
|   cert!: CertInfo | string; | ||||
| 
 | ||||
|   @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) | ||||
|   certDomains!: string[]; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|   @TaskInput({ | ||||
|     title: 'Access授权', | ||||
|     helper: '阿里云授权', | ||||
|     component: { | ||||
|       name: 'access-selector', | ||||
|       type: 'aliyun', | ||||
|     }, | ||||
|     required: true, | ||||
|   }) | ||||
|   accessId!: string; | ||||
| 
 | ||||
|   @TaskInput( | ||||
|     createRemoteSelectInputDefine({ | ||||
|       title: '区域', | ||||
|       helper: '请选择区域', | ||||
|       action: DeployCertToAliyunApig.prototype.onGetRegionList.name, | ||||
|       watches: ['certDomains', 'accessId'], | ||||
|       required: true, | ||||
|       component:{ | ||||
|         name:"remote-auto-complete" | ||||
|       } | ||||
|     }) | ||||
|   ) | ||||
|   regionEndpoint!: string; | ||||
| 
 | ||||
| 
 | ||||
|   @TaskInput({ | ||||
|     title: "网关类型", | ||||
|     component: { | ||||
|       name: "a-select", | ||||
|       vModel:"value", | ||||
|       options:[ | ||||
|         {value:"AI",label:"AI"}, | ||||
|         {value:"API",label:"API"}, | ||||
|       ] | ||||
|     }, | ||||
|     required: true //必填
 | ||||
|   }) | ||||
|   gatewayType!: string; | ||||
| 
 | ||||
| 
 | ||||
|   @TaskInput( | ||||
|     createRemoteSelectInputDefine({ | ||||
|       title: '绑定域名', | ||||
|       helper: '请选择域名', | ||||
|       action: DeployCertToAliyunApig.prototype.onGetDomainList.name, | ||||
|       watches: ['region',  'accessId','gatewayType'], | ||||
|       required: true, | ||||
|     }) | ||||
|   ) | ||||
|   domainList!: string[]; | ||||
| 
 | ||||
| 
 | ||||
|   @TaskInput({ | ||||
|     title: "强制HTTPS", | ||||
|     component: { | ||||
|       name: "a-select", | ||||
|       vModel:"value", | ||||
|       options:[ | ||||
|         {value:true,label:"强制HTTPS"}, | ||||
|         {value:false,label:"不强制HTTPS"}, | ||||
|       ] | ||||
|     }, | ||||
|     required: true //必填
 | ||||
|   }) | ||||
|   forceHttps!: boolean; | ||||
| 
 | ||||
|   @TaskInput({ | ||||
|     title: '证书服务接入点', | ||||
|     helper: '不会选就按默认', | ||||
|     value: 'cn-hangzhou', | ||||
|     component: { | ||||
|       name: 'a-select', | ||||
|       options: [ | ||||
|         { value: 'cn-hangzhou', label: '中国大陆' }, | ||||
|         { value: 'ap-southeast-1', label: '新加坡' }, | ||||
|       ], | ||||
|     }, | ||||
|     required: true, | ||||
|   }) | ||||
|   casRegion!: string; | ||||
| 
 | ||||
| 
 | ||||
|   async onInstance() {} | ||||
|   async execute(): Promise<void> { | ||||
|     this.logger.info('开始部署证书到云原生Api网关'); | ||||
|     if(!this.domainList){ | ||||
|       throw new Error('您还未选择域名'); | ||||
|     } | ||||
|     const access = await this.getAccess<AliyunAccess>(this.accessId); | ||||
|     const client = access.getClient(this.regionEndpoint) | ||||
| 
 | ||||
| 
 | ||||
|     let certId: any = this.cert; | ||||
|     if (typeof this.cert === 'object') { | ||||
|       const sslClient = new AliyunSslClient({ | ||||
|         access, | ||||
|         logger: this.logger, | ||||
|         region: this.casRegion, | ||||
|       }); | ||||
| 
 | ||||
|       certId = await sslClient.uploadCert({ | ||||
|         name: this.buildCertName(CertReader.getMainDomain(this.cert.crt)), | ||||
|         cert: this.cert, | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     const certIdentify  = `${certId}-${this.casRegion}` | ||||
| 
 | ||||
|     for (const domainId of this.domainList ) { | ||||
|       this.logger.info(`[${domainId}]开始部署`) | ||||
|       await this.updateCert(client, domainId,certIdentify); | ||||
|       this.logger.info(`[${domainId}]部署成功`) | ||||
|     } | ||||
| 
 | ||||
|     this.logger.info('部署完成'); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   async updateCert(client: any, domainId: string,certIdentify:string) { | ||||
| 
 | ||||
|     const domainInfoRes = await client.doRequest({ | ||||
|       action: "GetDomain", | ||||
|       version: "2024-03-27", | ||||
|       protocol: "HTTPS", | ||||
|       method: "GET", | ||||
|       authType: "AK", | ||||
|       style: "ROA", | ||||
|       pathname: `/v1/domains/${domainId}`, | ||||
|     }); | ||||
| 
 | ||||
|     const tlsCipherSuitesConfig = domainInfoRes.data?.tlsCipherSuitesConfig | ||||
| 
 | ||||
| 
 | ||||
|    const ret = await client.doRequest({ | ||||
|      action: "UpdateDomain", | ||||
|      version: "2024-03-27", | ||||
|      method: "PUT", | ||||
|      style: "ROA", | ||||
|      pathname: `/v1/domains/${domainId}`, | ||||
|       data:{ | ||||
|         body:{ | ||||
|           certIdentifier: certIdentify, | ||||
|           protocol: "HTTPS", | ||||
|           forceHttps:this.forceHttps, | ||||
|           tlsCipherSuitesConfig | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
|     this.logger.info(`设置${domainId}证书成功:`, ret.requestId); | ||||
|   } | ||||
| 
 | ||||
|   async onGetDomainList(data: any) { | ||||
|     if (!this.accessId) { | ||||
|       throw new Error('请选择Access授权'); | ||||
|     } | ||||
|     if (!this.regionEndpoint) { | ||||
|       throw new Error('请选择区域'); | ||||
|     } | ||||
|     if (!this.gatewayType) { | ||||
|       throw new Error('请选择网关类型'); | ||||
|     } | ||||
|     const access = await this.getAccess<AliyunAccess>(this.accessId); | ||||
| 
 | ||||
|     const client = access.getClient(this.regionEndpoint) | ||||
| 
 | ||||
|       const res =await client.doRequest({ | ||||
|         action: "ListDomains", | ||||
|         version: "2024-03-27", | ||||
|         method: "GET", | ||||
|         style: "ROA", | ||||
|         pathname: `/v1/domains`, | ||||
|         data:{ | ||||
|           query:{ | ||||
|             pageSize: 100, | ||||
|             gatewayType: this.gatewayType , | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     const list = res?.data?.items; | ||||
|     if (!list || list.length === 0) { | ||||
|       return [] | ||||
|     } | ||||
|     const options = list.map((item: any) => { | ||||
|       return { | ||||
|         value: item.domainId, | ||||
|         label: `${item.name}<${item.domainId}>`, | ||||
|         domain: item.name, | ||||
|       }; | ||||
|     }); | ||||
|     return optionsUtils.buildGroupOptions(options, this.certDomains); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   async onGetRegionList(data: any) { | ||||
|     const list = [ | ||||
|       {value:"cn-qingdao",label:"华北1(青岛)",endpoint:"apig.cn-qingdao.aliyuncs.com"}, | ||||
|       {value:"cn-beijing",label:"华北2(北京)",endpoint:"apig.cn-beijing.aliyuncs.com"}, | ||||
|       {value:"cn-zhangjiakou",label:"华北3(张家口)",endpoint:"apig.cn-zhangjiakou.aliyuncs.com"}, | ||||
|       {value:"cn-wulanchabu",label:"华北6(乌兰察布)",endpoint:"apig.cn-wulanchabu.aliyuncs.com"}, | ||||
|       {value:"cn-hangzhou",label:"华东1(杭州)",endpoint:"apig.cn-hangzhou.aliyuncs.com"}, | ||||
|       {value:"cn-shanghai",label:"华东2(上海)",endpoint:"apig.cn-shanghai.aliyuncs.com"}, | ||||
|       {value:"cn-shenzhen",label:"华南1(深圳)",endpoint:"apig.cn-shenzhen.aliyuncs.com"}, | ||||
|       {value:"cn-heyuan",label:"华南2(河源)",endpoint:"apig.cn-heyuan.aliyuncs.com"}, | ||||
|       {value:"cn-guangzhou",label:"华南3(广州)",endpoint:"apig.cn-guangzhou.aliyuncs.com"}, | ||||
|       {value:"ap-southeast-2",label:"澳大利亚(悉尼)已关停",endpoint:"apig.ap-southeast-2.aliyuncs.com"}, | ||||
|       {value:"ap-southeast-6",label:"菲律宾(马尼拉)",endpoint:"apig.ap-southeast-6.aliyuncs.com"}, | ||||
|       {value:"ap-northeast-2",label:"韩国(首尔)",endpoint:"apig.ap-northeast-2.aliyuncs.com"}, | ||||
|       {value:"ap-southeast-3",label:"马来西亚(吉隆坡)",endpoint:"apig.ap-southeast-3.aliyuncs.com"}, | ||||
|       {value:"ap-northeast-1",label:"日本(东京)",endpoint:"apig.ap-northeast-1.aliyuncs.com"}, | ||||
|       {value:"ap-southeast-7",label:"泰国(曼谷)",endpoint:"apig.ap-southeast-7.aliyuncs.com"}, | ||||
|       {value:"cn-chengdu",label:"西南1(成都)",endpoint:"apig.cn-chengdu.aliyuncs.com"}, | ||||
|       {value:"ap-southeast-1",label:"新加坡",endpoint:"apig.ap-southeast-1.aliyuncs.com"}, | ||||
|       {value:"ap-southeast-5",label:"印度尼西亚(雅加达)",endpoint:"apig.ap-southeast-5.aliyuncs.com"}, | ||||
|       {value:"cn-hongkong",label:"中国香港",endpoint:"apig.cn-hongkong.aliyuncs.com"}, | ||||
|       {value:"eu-central-1",label:"德国(法兰克福)",endpoint:"apig.eu-central-1.aliyuncs.com"}, | ||||
|       {value:"us-east-1",label:"美国(弗吉尼亚)",endpoint:"apig.us-east-1.aliyuncs.com"}, | ||||
|       {value:"us-west-1",label:"美国(硅谷)",endpoint:"apig.us-west-1.aliyuncs.com"}, | ||||
|       {value:"eu-west-1",label:"英国(伦敦)",endpoint:"apig.eu-west-1.aliyuncs.com"}, | ||||
|       {value:"me-east-1",label:"阿联酋(迪拜)",endpoint:"apig.me-east-1.aliyuncs.com"}, | ||||
|       {value:"me-central-1",label:"沙特(利雅得)",endpoint:"apig.me-central-1.aliyuncs.com"}, | ||||
|     ] | ||||
|     return list.map((item: any) => { | ||||
|       return { | ||||
|         value: item.endpoint, | ||||
|         label: item.label, | ||||
|         endpoint: item.endpoint, | ||||
|         regionId : item.value | ||||
|       }; | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| new DeployCertToAliyunApig(); | ||||
|  | @ -10,3 +10,4 @@ export * from './deploy-to-fc/index.js'; | |||
| export * from './deploy-to-esa/index.js'; | ||||
| export * from './deploy-to-vod/index.js'; | ||||
| export * from './deploy-to-apigateway/index.js'; | ||||
| export * from './deploy-to-apig/index.js'; | ||||
|  |  | |||
|  | @ -14,8 +14,9 @@ import { CertApplyPluginNames, CertReader } from "@certd/plugin-cert"; | |||
|  */ | ||||
| const regionDict = [ | ||||
|   { value: 'cn-hangzhou', endpoint: 'cas.aliyuncs.com', label: 'cn-hangzhou-中国大陆' }, | ||||
|   { value: 'eu-central-1', endpoint: 'cas.eu-central-1.aliyuncs.com', label: 'eu-central-1-德国(法兰克福)' }, | ||||
|   { value: 'ap-southeast-1', endpoint: 'cas.ap-southeast-1.aliyuncs.com', label: 'ap-southeast-1-新加坡(国际版选这个)' }, | ||||
|   { value: 'private-', endpoint: '', disabled:true, label: '以下是私有证书区域' }, | ||||
|   { value: 'eu-central-1', endpoint: 'cas.eu-central-1.aliyuncs.com', label: 'eu-central-1-德国(法兰克福)' }, | ||||
|   { value: 'ap-southeast-3', endpoint: 'cas.ap-southeast-3.aliyuncs.com', label: 'ap-southeast-3-马来西亚(吉隆坡)' }, | ||||
|   { value: 'ap-southeast-5', endpoint: 'cas.ap-southeast-5.aliyuncs.com', label: 'ap-southeast-5-印度尼西亚(雅加达)' }, | ||||
|   { value: 'cn-hongkong', endpoint: 'cas.cn-hongkong.aliyuncs.com', label: 'cn-hongkong-中国香港' }, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 xiaojunnuo
						xiaojunnuo