diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 61d14613..fc3c7a37 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -370,8 +370,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { switch options.Provider { case domain.DeployProviderTypeBaishanCDN: deployer, err := pBaishanCDN.NewDeployer(&pBaishanCDN.DeployerConfig{ - ApiToken: access.ApiToken, - Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), + ApiToken: access.ApiToken, + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), + CertificateId: maputil.GetString(options.ProviderDeployConfig, "certificateId"), }) return deployer, err diff --git a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go index cc179b34..bddefb42 100644 --- a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go +++ b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go @@ -157,7 +157,7 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPem string, pri InstanceId: tea.String(d.config.InstanceId), RegionId: tea.String(d.config.Region), Domain: tea.String(d.config.Domain), - Listen: &aliwaf.ModifyDomainRequestListen{CertId: tea.String(upres.CertId)}, + Listen: &aliwaf.ModifyDomainRequestListen{CertId: tea.String(upres.ExtendedData["certIdentifier"].(string))}, Redirect: &aliwaf.ModifyDomainRequestRedirect{Loadbalance: tea.String("iphash")}, } modifyDomainReq = assign(modifyDomainReq, describeDomainDetailResp.Body) diff --git a/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go index e6aec2ab..ce204525 100644 --- a/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go +++ b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go @@ -21,6 +21,9 @@ type DeployerConfig struct { ApiToken string `json:"apiToken"` // 加速域名(支持泛域名)。 Domain string `json:"domain"` + // 证书 ID。 + // 选填。 + CertificateId string `json:"certificateId,omitempty"` } type DeployerProvider struct { @@ -62,63 +65,79 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe return nil, errors.New("config `domain` is required") } - // 查询域名配置 - // REF: https://portal.baishancloud.com/track/document/api/1/1065 - getDomainConfigReq := &bssdk.GetDomainConfigRequest{ - Domains: d.config.Domain, - Config: []string{"https"}, - } - getDomainConfigResp, err := d.sdkClient.GetDomainConfig(getDomainConfigReq) - d.logger.Debug("sdk request 'baishan.GetDomainConfig'", slog.Any("request", getDomainConfigReq), slog.Any("response", getDomainConfigResp)) - if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.GetDomainConfig'") - } else if len(getDomainConfigResp.Data) == 0 { - return nil, errors.New("domain config not found") - } - - // 新增证书 - // REF: https://portal.baishancloud.com/track/document/downloadPdf/1441 - certificateId := "" - createCertificateReq := &bssdk.CreateCertificateRequest{ - Certificate: certPem, - Key: privkeyPem, - Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()), - } - createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) - d.logger.Debug("sdk request 'baishan.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp)) - if err != nil { - if createCertificateResp != nil { - if createCertificateResp.GetCode() == 400699 && strings.Contains(createCertificateResp.GetMessage(), "this certificate is exists") { - // 证书已存在,忽略新增证书接口错误 - re := regexp.MustCompile(`\d+`) - certificateId = re.FindString(createCertificateResp.GetMessage()) + if d.config.CertificateId == "" { + // 新增证书 + // REF: https://portal.baishancloud.com/track/document/downloadPdf/1441 + certificateId := "" + createCertificateReq := &bssdk.CreateCertificateRequest{ + Certificate: certPem, + Key: privkeyPem, + Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()), + } + createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + d.logger.Debug("sdk request 'baishan.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp)) + if err != nil { + if createCertificateResp != nil { + if createCertificateResp.GetCode() == 400699 && strings.Contains(createCertificateResp.GetMessage(), "this certificate is exists") { + // 证书已存在,忽略新增证书接口错误 + re := regexp.MustCompile(`\d+`) + certificateId = re.FindString(createCertificateResp.GetMessage()) + } } + + if certificateId == "" { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.CreateCertificate'") + } + } else { + certificateId = createCertificateResp.Data.CertId.String() } - if certificateId == "" { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.CreateCertificate'") + // 查询域名配置 + // REF: https://portal.baishancloud.com/track/document/api/1/1065 + getDomainConfigReq := &bssdk.GetDomainConfigRequest{ + Domains: d.config.Domain, + Config: []string{"https"}, + } + getDomainConfigResp, err := d.sdkClient.GetDomainConfig(getDomainConfigReq) + d.logger.Debug("sdk request 'baishan.GetDomainConfig'", slog.Any("request", getDomainConfigReq), slog.Any("response", getDomainConfigResp)) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.GetDomainConfig'") + } else if len(getDomainConfigResp.Data) == 0 { + return nil, errors.New("domain config not found") + } + + // 设置域名配置 + // REF: https://portal.baishancloud.com/track/document/api/1/1045 + setDomainConfigReq := &bssdk.SetDomainConfigRequest{ + Domains: d.config.Domain, + Config: &bssdk.DomainConfig{ + Https: &bssdk.DomainConfigHttps{ + CertId: json.Number(certificateId), + ForceHttps: getDomainConfigResp.Data[0].Config.Https.ForceHttps, + EnableHttp2: getDomainConfigResp.Data[0].Config.Https.EnableHttp2, + EnableOcsp: getDomainConfigResp.Data[0].Config.Https.EnableOcsp, + }, + }, + } + setDomainConfigResp, err := d.sdkClient.SetDomainConfig(setDomainConfigReq) + d.logger.Debug("sdk request 'baishan.SetDomainConfig'", slog.Any("request", setDomainConfigReq), slog.Any("response", setDomainConfigResp)) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.SetDomainConfig'") } } else { - certificateId = createCertificateResp.Data.CertId.String() - } - - // 设置域名配置 - // REF: https://portal.baishancloud.com/track/document/api/1/1045 - setDomainConfigReq := &bssdk.SetDomainConfigRequest{ - Domains: d.config.Domain, - Config: &bssdk.DomainConfig{ - Https: &bssdk.DomainConfigHttps{ - CertId: json.Number(certificateId), - ForceHttps: getDomainConfigResp.Data[0].Config.Https.ForceHttps, - EnableHttp2: getDomainConfigResp.Data[0].Config.Https.EnableHttp2, - EnableOcsp: getDomainConfigResp.Data[0].Config.Https.EnableOcsp, - }, - }, - } - setDomainConfigResp, err := d.sdkClient.SetDomainConfig(setDomainConfigReq) - d.logger.Debug("sdk request 'baishan.SetDomainConfig'", slog.Any("request", setDomainConfigReq), slog.Any("response", setDomainConfigResp)) - if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.SetDomainConfig'") + // 替换证书 + // REF: https://portal.baishancloud.com/track/document/downloadPdf/1441 + createCertificateReq := &bssdk.CreateCertificateRequest{ + CertificateId: &d.config.CertificateId, + Certificate: certPem, + Key: privkeyPem, + Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()), + } + createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + d.logger.Debug("sdk request 'baishan.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp)) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.CreateCertificate'") + } } return &deployer.DeployResult{}, nil diff --git a/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go b/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go index 9f3e9212..f7495c40 100644 --- a/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go +++ b/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go @@ -116,6 +116,10 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe return &uploader.UploadResult{ CertId: fmt.Sprintf("%d", tea.Int64Value(certDetail.CertificateId)), CertName: *certDetail.Name, + ExtendedData: map[string]any{ + "instanceId": tea.StringValue(getUserCertificateDetailResp.Body.InstanceId), + "certIdentifier": tea.StringValue(getUserCertificateDetailResp.Body.CertIdentifier), + }, }, nil } } @@ -129,8 +133,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe } // 生成新证书名(需符合阿里云命名规则) - var certId, certName string - certName = fmt.Sprintf("certimate_%d", time.Now().UnixMilli()) + certName := fmt.Sprintf("certimate_%d", time.Now().UnixMilli()) // 上传新证书 // REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-uploadusercertificate @@ -145,10 +148,25 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.UploadUserCertificate'") } - certId = fmt.Sprintf("%d", tea.Int64Value(uploadUserCertificateResp.Body.CertId)) + // 获取证书详情 + // REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-getusercertificatedetail + getUserCertificateDetailReq := &alicas.GetUserCertificateDetailRequest{ + CertId: uploadUserCertificateResp.Body.CertId, + CertFilter: tea.Bool(true), + } + getUserCertificateDetailResp, err := u.sdkClient.GetUserCertificateDetail(getUserCertificateDetailReq) + u.logger.Debug("sdk request 'cas.GetUserCertificateDetail'", slog.Any("request", getUserCertificateDetailReq), slog.Any("response", getUserCertificateDetailResp)) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.GetUserCertificateDetail'") + } + return &uploader.UploadResult{ - CertId: certId, + CertId: fmt.Sprintf("%d", tea.Int64Value(getUserCertificateDetailResp.Body.Id)), CertName: certName, + ExtendedData: map[string]any{ + "instanceId": tea.StringValue(getUserCertificateDetailResp.Body.InstanceId), + "certIdentifier": tea.StringValue(getUserCertificateDetailResp.Body.CertIdentifier), + }, }, nil } diff --git a/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go b/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go index f0a3ccb5..8e30d554 100644 --- a/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go +++ b/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go @@ -71,7 +71,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 获取证书列表,避免重复上传 // REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ListCertificates.html - listCertificatesNextToken := new(string) + var listCertificatesNextToken *string = nil listCertificatesMaxItems := int32(1000) for { listCertificatesReq := &awsacm.ListCertificatesInput{ diff --git a/internal/pkg/vendors/baishan-sdk/models.go b/internal/pkg/vendors/baishan-sdk/models.go index b7dfd3f5..397061d4 100644 --- a/internal/pkg/vendors/baishan-sdk/models.go +++ b/internal/pkg/vendors/baishan-sdk/models.go @@ -27,9 +27,10 @@ func (r *baseResponse) GetMessage() string { } type CreateCertificateRequest struct { - Certificate string `json:"certificate"` - Key string `json:"key"` - Name string `json:"name"` + CertificateId *string `json:"cert_id,omitempty"` + Certificate string `json:"certificate"` + Key string `json:"key"` + Name string `json:"name"` } type CreateCertificateResponse struct { diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx index 828d5845..ad05b6a8 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx @@ -7,6 +7,7 @@ import { validDomainName } from "@/utils/validators"; type DeployNodeConfigFormBaishanCDNConfigFieldValues = Nullish<{ domain: string; + certificateId?: string | number; }>; export type DeployNodeConfigFormBaishanCDNConfigProps = { @@ -34,6 +35,13 @@ const DeployNodeConfigFormBaishanCDNConfig = ({ domain: z .string({ message: t("workflow_node.deploy.form.baishan_cdn_domain.placeholder") }) .refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")), + certificateId: z + .union([z.string(), z.number().int()]) + .nullish() + .refine((v) => { + if (!v) return true; + return /^\d+$/.test(v + "") && +v > 0; + }, t("workflow_node.deploy.form.baishan_cdn_certificate_id.placeholder")), }); const formRule = createSchemaFieldRule(formSchema); @@ -58,6 +66,15 @@ const DeployNodeConfigFormBaishanCDNConfig = ({ > + +