diff --git a/packages/plugins/plugin-cert/package.json b/packages/plugins/plugin-cert/package.json index 79e19a1b..f90dd780 100644 --- a/packages/plugins/plugin-cert/package.json +++ b/packages/plugins/plugin-cert/package.json @@ -14,9 +14,10 @@ "preview": "vite preview" }, "dependencies": { - "@certd/basic": "^1.25.9", "@certd/acme-client": "^1.25.9", + "@certd/basic": "^1.25.9", "@certd/pipeline": "^1.25.9", + "@google-cloud/publicca": "^1.3.0", "dayjs": "^1.11.7", "jszip": "^3.10.1", "node-forge": "^0.10.0", diff --git a/packages/plugins/plugin-cert/src/access/google-access.ts b/packages/plugins/plugin-cert/src/access/google-access.ts new file mode 100644 index 00000000..efc66355 --- /dev/null +++ b/packages/plugins/plugin-cert/src/access/google-access.ts @@ -0,0 +1,97 @@ +import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline"; + +@IsAccess({ + name: "google", + title: "google cloud", + desc: "谷歌云授权", +}) +export class GoogleAccess extends BaseAccess { + @AccessInput({ + title: "密钥类型", + value: "serviceAccount", + component: { + placeholder: "密钥类型", + name: "a-select", + vModel: "value", + options: [ + { value: "serviceAccount", label: "服务账号密钥" }, + { value: "apiKey", label: "ApiKey,暂不可用", disabled: true }, + ], + }, + helper: "密钥类型", + required: true, + encrypt: false, + }) + type = ""; + + @AccessInput({ + title: "项目ID", + component: { + placeholder: "ProjectId", + }, + helper: "ProjectId", + required: true, + encrypt: false, + mergeScript: ` + return { + show:ctx.compute(({form})=>{ + return form.access.type === 'apiKey' + }) + } + `, + }) + projectId = ""; + + @AccessInput({ + title: "ApiKey", + component: { + placeholder: "ApiKey", + }, + helper: "不要选,目前没有用", + required: true, + encrypt: true, + mergeScript: ` + return { + show:ctx.compute(({form})=>{ + return form.access.type === 'apiKey' + }) + } + `, + }) + apiKey = ""; + + @AccessInput({ + title: "服务账号密钥", + component: { + placeholder: "serviceAccountSecret", + name: "a-textarea", + vModel: "value", + rows: 4, + }, + helper: + "[如何创建服务账号](https://cloud.google.com/iam/docs/service-accounts-create?hl=zh-CN) \n[获取密钥](https://console.cloud.google.com/iam-admin/serviceaccounts?hl=zh-cn),点击详情,点击创建密钥,将下载json文件,把内容填在此处", + required: true, + encrypt: true, + mergeScript: ` + return { + show:ctx.compute(({form})=>{ + return form.access.type === 'serviceAccount' + }) + } + `, + }) + serviceAccountSecret = ""; + + @AccessInput({ + title: "https代理", + component: { + placeholder: "http://127.0.0.1:10811", + }, + helper: "Google的请求需要走代理,如果不配置,则会使用环境变量中的全局HTTPS_PROXY配置\n或者服务器本身在海外,则不需要配置", + required: false, + encrypt: false, + }) + httpsProxy = ""; +} + +new GoogleAccess(); diff --git a/packages/plugins/plugin-cert/src/access/index.ts b/packages/plugins/plugin-cert/src/access/index.ts index 4111cb7d..0ea7960a 100644 --- a/packages/plugins/plugin-cert/src/access/index.ts +++ b/packages/plugins/plugin-cert/src/access/index.ts @@ -1 +1,2 @@ export * from "./eab-access.js"; +export * from "./google-access.js"; diff --git a/packages/plugins/plugin-cert/src/libs/google.ts b/packages/plugins/plugin-cert/src/libs/google.ts new file mode 100644 index 00000000..81a24fc1 --- /dev/null +++ b/packages/plugins/plugin-cert/src/libs/google.ts @@ -0,0 +1,62 @@ +import { EabAccess, GoogleAccess } from "../access/index.js"; +import { ILogger } from "@certd/basic"; + +export class GoogleClient { + access: GoogleAccess; + logger: ILogger; + constructor(opts: { logger: ILogger; access: GoogleAccess }) { + this.access = opts.access; + this.logger = opts.logger; + } + async getEab() { + // https://cloud.google.com/docs/authentication/api-keys-use#using-with-client-libs + const { v1 } = await import("@google-cloud/publicca"); + // process.env.HTTPS_PROXY = "http://127.0.0.1:10811"; + const access = this.access; + if (!access.serviceAccountSecret) { + throw new Error("服务账号密钥 不能为空"); + } + const credentials = JSON.parse(access.serviceAccountSecret); + + const client = new v1.PublicCertificateAuthorityServiceClient({ credentials }); + const parent = `projects/${access.projectId}/locations/global`; + const externalAccountKey = {}; + const request = { + parent, + externalAccountKey, + }; + + let envHttpsProxy = ""; + try { + if (this.access.httpsProxy) { + //设置临时使用代理 + envHttpsProxy = process.env.HTTPS_PROXY; + process.env.HTTPS_PROXY = this.access.httpsProxy; + } + this.logger.info("开始获取google eab授权"); + const response = await client.createExternalAccountKey(request); + const { keyId, b64MacKey } = response[0]; + const eabAccess = new EabAccess(); + eabAccess.kid = keyId; + eabAccess.hmacKey = b64MacKey.toString(); + this.logger.info(`google eab授权获取成功,kid: ${eabAccess.kid}`); + return eabAccess; + } finally { + if (envHttpsProxy) { + process.env.HTTPS_PROXY = envHttpsProxy; + } + } + } +} + +// const access = new GoogleAccess(); +// access.projectId = "hip-light-432411-d4"; +// access.serviceAccountSecret = ` +// +// +// `; +// // process.env.HTTPS_PROXY = "http://127.0.0.1:10811"; +// const client = new GoogleClient(access); +// client.getEab().catch((e) => { +// console.error(e); +// }); diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts index 526bd993..7fb6c6a2 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -5,6 +5,7 @@ import _ from "lodash-es"; import { createDnsProvider, DnsProviderContext, IDnsProvider } from "../../dns-provider/index.js"; import { CertReader } from "./cert-reader.js"; import { CertApplyBasePlugin } from "./base.js"; +import { GoogleClient } from "../../libs/google.js"; export type { CertInfo }; export * from "./cert-reader.js"; @@ -145,18 +146,56 @@ export class CertApplyPlugin extends CertApplyBasePlugin { }, maybeNeed: true, required: true, - helper: - "需要提供EAB授权\nZeroSSL:请前往[zerossl开发者中心](https://app.zerossl.com/developer),生成 'EAB Credentials' \n Google:请查看[google获取eab帮助文档](https://github.com/certd/certd/blob/v2/doc/google/google.md)", + helper: "需要提供EAB授权\nZeroSSL:请前往[zerossl开发者中心](https://app.zerossl.com/developer),生成 'EAB Credentials'", mergeScript: ` return { show: ctx.compute(({form})=>{ - return form.sslProvider === 'zerossl' || form.sslProvider === 'google' + return form.sslProvider === 'zerossl' }) } `, }) eabAccessId!: number; + @TaskInput({ + title: "GoogleEAB授权", + component: { + name: "access-selector", + type: "eab", + }, + maybeNeed: true, + required: false, + helper: + "请查看[google获取eab帮助文档](https://github.com/certd/certd/blob/v2/doc/google/google.md)\n注意此方式获取的EAB授权是一次性的,下次申请需要重新获取授权\n推荐使用Google服务账号授权自动获取EAB", + mergeScript: ` + return { + show: ctx.compute(({form})=>{ + return form.sslProvider === 'google' + }) + } + `, + }) + googleEabAccessId!: number; + + @TaskInput({ + title: "Google服务账号授权", + component: { + name: "access-selector", + type: "google", + }, + maybeNeed: true, + required: false, + helper: "google服务账号授权,需要配置代理或者服务器本身在海外\n代理配置方法:配置环境变量https_proxy", + mergeScript: ` + return { + show: ctx.compute(({form})=>{ + return form.sslProvider === 'google' + }) + } + `, + }) + googleAccessId!: number; + @TaskInput({ title: "加密算法", value: "rsa_2048", @@ -205,9 +244,30 @@ export class CertApplyPlugin extends CertApplyBasePlugin { async onInit() { let eab: any = null; - if (this.eabAccessId) { + + if (this.sslProvider === "google") { + if (this.googleAccessId) { + const googleAccess = await this.ctx.accessService.getById(this.googleAccessId); + const googleClient = new GoogleClient({ + access: googleAccess, + logger: this.logger, + }); + eab = await googleClient.getEab(); + } else if (this.googleEabAccessId || this.eabAccessId) { + this.logger.warn("您正在使用google一次性EAB授权,下次申请证书需要重新获取"); + eab = await this.ctx.accessService.getById(this.googleEabAccessId); + } else { + this.logger.error("google需要配置EAB授权或服务账号授权"); + return; + } + } else if (this.sslProvider === "zerossl") { + if (this.eabAccessId) { + this.logger.error("zerossl需要EAB授权"); + return; + } eab = await this.ctx.accessService.getById(this.eabAccessId); } + this.acme = new AcmeService({ userContext: this.userContext, logger: this.logger, diff --git a/packages/ui/certd-client/src/views/certd/pipeline/certd-form/crud.tsx b/packages/ui/certd-client/src/views/certd/pipeline/certd-form/crud.tsx index 9ea2dbe9..e5228eb8 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/certd-form/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/pipeline/certd-form/crud.tsx @@ -69,7 +69,7 @@ export default function (certPluginGroup: PluginGroup, formWrapperRef: any): Cre return ( ); }