diff --git a/packages/plugins/plugin-lib/src/aliyun/access/aliyun-access.ts b/packages/plugins/plugin-lib/src/aliyun/access/aliyun-access.ts index f7c493b9..5ced97a3 100644 --- a/packages/plugins/plugin-lib/src/aliyun/access/aliyun-access.ts +++ b/packages/plugins/plugin-lib/src/aliyun/access/aliyun-access.ts @@ -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", // 接口响应体内容格式 diff --git a/packages/plugins/plugin-lib/src/aliyun/lib/ssl-client.ts b/packages/plugins/plugin-lib/src/aliyun/lib/ssl-client.ts index 112b858c..df57e7ab 100644 --- a/packages/plugins/plugin-lib/src/aliyun/lib/ssl-client.ts +++ b/packages/plugins/plugin-lib/src/aliyun/lib/ssl-client.ts @@ -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; diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-apig/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-apig/index.ts new file mode 100644 index 00000000..a949b397 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-apig/index.ts @@ -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 { + this.logger.info('开始部署证书到云原生Api网关'); + if(!this.domainList){ + throw new Error('您还未选择域名'); + } + const access = await this.getAccess(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(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(); diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/index.ts index 87e353bc..7794faf0 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/index.ts @@ -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'; diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/upload-to-aliyun/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/upload-to-aliyun/index.ts index 52c38aa0..398fd49d 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/upload-to-aliyun/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/upload-to-aliyun/index.ts @@ -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-中国香港' },