From eb97f7a6617315a00865dc49d12a4f4d03be8acf Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 12 Mar 2025 16:56:02 +0800 Subject: [PATCH 1/3] refactor: clean code --- .../workflow/node/DeployNodeConfigFormLocalConfig.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormLocalConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormLocalConfig.tsx index af2e2a43..bd1cced6 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormLocalConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormLocalConfig.tsx @@ -138,14 +138,14 @@ const DeployNodeConfigFormLocalConfig = ({ form: formInst, formName, disabled, i switch (key) { case "reload_nginx": { - formInst.setFieldValue("shellEnv", "sh"); + formInst.setFieldValue("shellEnv", SHELLENV_SH); formInst.setFieldValue("postCommand", "sudo service nginx reload"); } break; case "binding_iis": { - formInst.setFieldValue("shellEnv", "powershell"); + formInst.setFieldValue("shellEnv", SHELLENV_POWERSHELL); formInst.setFieldValue( "postCommand", `# 请将以下变量替换为实际值 @@ -182,7 +182,7 @@ Remove-Item -Path "$pfxPath" -Force case "binding_netsh": { - formInst.setFieldValue("shellEnv", "powershell"); + formInst.setFieldValue("shellEnv", SHELLENV_POWERSHELL); formInst.setFieldValue( "postCommand", `# 请将以下变量替换为实际值 @@ -210,7 +210,7 @@ Remove-Item -Path "$pfxPath" -Force break; case "binding_rdp": { - formInst.setFieldValue("shellEnv", "powershell"); + formInst.setFieldValue("shellEnv", SHELLENV_POWERSHELL); formInst.setFieldValue( "postCommand", `# 请将以下变量替换为实际值 From d1aed36154e5131b87eca0338ce6908492a0af11 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 12 Mar 2025 19:36:14 +0800 Subject: [PATCH 2/3] fix: #512 --- .../core/deployer/providers/aliyun-alb/aliyun_alb.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go index 4388fbf0..8c25bc25 100644 --- a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go +++ b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go @@ -297,7 +297,9 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL var errs []error for _, listenerCertificate := range listenerCertificates { - if *listenerCertificate.CertificateId == cloudCertId { + // 监听证书 ID 格式:${证书 ID}-${地域} + certificateId := strings.Split(*listenerCertificate.CertificateId, "-")[0] + if certificateId == cloudCertId { certificateIsAssociated = true continue } @@ -306,14 +308,14 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL continue } - listenerCertificateId, err := strconv.ParseInt(*listenerCertificate.CertificateId, 10, 64) + certificateIdAsInt64, err := strconv.ParseInt(certificateId, 10, 64) if err != nil { errs = append(errs, err) continue } getUserCertificateDetailReq := &aliyunCas.GetUserCertificateDetailRequest{ - CertId: tea.Int64(listenerCertificateId), + CertId: tea.Int64(certificateIdAsInt64), } getUserCertificateDetailResp, err := d.sdkClients.cas.GetUserCertificateDetail(getUserCertificateDetailReq) if err != nil { @@ -332,7 +334,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL continue } - certificateIdsExpired = append(certificateIdsExpired, *listenerCertificate.CertificateId) + certificateIdsExpired = append(certificateIdsExpired, certificateId) } if len(errs) > 0 { From 17af07e4bb34789395dd669c3553272b90ede44d Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 12 Mar 2025 19:58:58 +0800 Subject: [PATCH 3/3] feat: support sni on deployment to aliyun waf --- internal/deployer/providers.go | 1 + .../providers/aliyun-waf/aliyun_waf.go | 105 +++++++++++++----- .../volcengine-imagex/volcengine_imagex.go | 21 ++-- .../DeployNodeConfigFormAliyunWAFConfig.tsx | 18 +++ .../i18n/locales/en/nls.workflow.nodes.json | 3 + .../i18n/locales/zh/nls.workflow.nodes.json | 5 +- 6 files changed, 116 insertions(+), 37 deletions(-) diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 1efd9c96..5c785780 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -226,6 +226,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { AccessKeySecret: access.AccessKeySecret, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), InstanceId: maps.GetValueAsString(options.ProviderDeployConfig, "instanceId"), + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), }) 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 ccb9adc6..928a0d56 100644 --- a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go +++ b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go @@ -24,8 +24,10 @@ type DeployerConfig struct { AccessKeySecret string `json:"accessKeySecret"` // 阿里云地域。 Region string `json:"region"` - // 阿里云 WAF 实例 ID。 + // WAF 实例 ID。 InstanceId string `json:"instanceId"` + // 接入域名(支持泛域名)。 + Domain string `json:"domain,omitempty"` } type DeployerProvider struct { @@ -74,38 +76,87 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) } - d.logger.Logt("certificate file uploaded", upres) + if d.config.Domain == "" { + // 未指定接入域名,只需替换默认证书即可 - // 查询默认 SSL/TLS 设置 - // REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedefaulthttps - describeDefaultHttpsReq := &aliyunWaf.DescribeDefaultHttpsRequest{ - InstanceId: tea.String(d.config.InstanceId), - RegionId: tea.String(d.config.Region), - } - describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttps(describeDefaultHttpsReq) - if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDefaultHttps'") - } + // 查询默认 SSL/TLS 设置 + // REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedefaulthttps + describeDefaultHttpsReq := &aliyunWaf.DescribeDefaultHttpsRequest{ + InstanceId: tea.String(d.config.InstanceId), + RegionId: tea.String(d.config.Region), + } + describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttps(describeDefaultHttpsReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDefaultHttps'") + } else { + d.logger.Logt("已查询到默认 SSL/TLS 设置", describeDefaultHttpsResp) + } - d.logger.Logt("已查询到默认 SSL/TLS 设置", describeDefaultHttpsResp) + // 修改默认 SSL/TLS 设置 + // REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydefaulthttps + modifyDefaultHttpsReq := &aliyunWaf.ModifyDefaultHttpsRequest{ + InstanceId: tea.String(d.config.InstanceId), + RegionId: tea.String(d.config.Region), + CertId: tea.String(upres.CertId), + TLSVersion: tea.String("tlsv1"), + EnableTLSv3: tea.Bool(false), + } + if describeDefaultHttpsResp.Body != nil && describeDefaultHttpsResp.Body.DefaultHttps != nil { + modifyDefaultHttpsReq.TLSVersion = describeDefaultHttpsResp.Body.DefaultHttps.TLSVersion + modifyDefaultHttpsReq.EnableTLSv3 = describeDefaultHttpsResp.Body.DefaultHttps.EnableTLSv3 + } + modifyDefaultHttpsResp, err := d.sdkClient.ModifyDefaultHttps(modifyDefaultHttpsReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDefaultHttps'") + } else { + d.logger.Logt("已修改默认 SSL/TLS 设置", modifyDefaultHttpsResp) + } + } else { + // 指定接入域名 - // 修改默认 SSL/TLS 设置 - // REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydefaulthttps - modifyDefaultHttpsReq := &aliyunWaf.ModifyDefaultHttpsRequest{ - InstanceId: tea.String(d.config.InstanceId), - RegionId: tea.String(d.config.Region), - CertId: tea.String(upres.CertId), - TLSVersion: describeDefaultHttpsResp.Body.DefaultHttps.TLSVersion, - EnableTLSv3: describeDefaultHttpsResp.Body.DefaultHttps.EnableTLSv3, - } - modifyDefaultHttpsResp, err := d.sdkClient.ModifyDefaultHttps(modifyDefaultHttpsReq) - if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDefaultHttps'") - } + // 查询 CNAME 接入详情 + // REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedomaindetail + describeDomainDetailReq := &aliyunWaf.DescribeDomainDetailRequest{ + InstanceId: tea.String(d.config.InstanceId), + RegionId: tea.String(d.config.Region), + Domain: tea.String(d.config.Domain), + } + describeDomainDetailResp, err := d.sdkClient.DescribeDomainDetail(describeDomainDetailReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDomainDetail'") + } else { + d.logger.Logt("已查询到 CNAME 接入详情", describeDomainDetailResp) + } - d.logger.Logt("已修改默认 SSL/TLS 设置", modifyDefaultHttpsResp) + // 修改 CNAME 接入资源 + // REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydomain + modifyDomainReq := &aliyunWaf.ModifyDomainRequest{ + InstanceId: tea.String(d.config.InstanceId), + RegionId: tea.String(d.config.Region), + Domain: tea.String(d.config.Domain), + Listen: &aliyunWaf.ModifyDomainRequestListen{ + CertId: tea.String(upres.CertId), + TLSVersion: tea.String("tlsv1"), + EnableTLSv3: tea.Bool(false), + }, + Redirect: &aliyunWaf.ModifyDomainRequestRedirect{}, + } + if describeDomainDetailResp.Body != nil && describeDomainDetailResp.Body.Listen != nil { + modifyDomainReq.Listen.TLSVersion = describeDomainDetailResp.Body.Listen.TLSVersion + modifyDomainReq.Listen.EnableTLSv3 = describeDomainDetailResp.Body.Listen.EnableTLSv3 + modifyDomainReq.Listen.FocusHttps = describeDomainDetailResp.Body.Listen.FocusHttps + } + modifyDomainResp, err := d.sdkClient.ModifyDomain(modifyDomainReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDomain'") + } else { + d.logger.Logt("已修改 CNAME 接入资源", modifyDomainResp) + } + } return &deployer.DeployResult{}, nil } diff --git a/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go b/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go index 57d133ec..1bd6d109 100644 --- a/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go +++ b/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go @@ -104,19 +104,22 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe ServiceID: d.config.ServiceId, }, UpdateHTTPSBody: &veImageX.UpdateHTTPSBody{ - Domain: getDomainConfigResp.Result.Domain, + Domain: d.config.Domain, HTTPS: &veImageX.UpdateHTTPSBodyHTTPS{ - CertID: upres.CertId, - EnableHTTP2: getDomainConfigResp.Result.HTTPSConfig.EnableHTTP2, - EnableHTTPS: getDomainConfigResp.Result.HTTPSConfig.EnableHTTPS, - EnableOcsp: getDomainConfigResp.Result.HTTPSConfig.EnableOcsp, - TLSVersions: getDomainConfigResp.Result.HTTPSConfig.TLSVersions, - EnableForceRedirect: getDomainConfigResp.Result.HTTPSConfig.EnableForceRedirect, - ForceRedirectType: getDomainConfigResp.Result.HTTPSConfig.ForceRedirectType, - ForceRedirectCode: getDomainConfigResp.Result.HTTPSConfig.ForceRedirectCode, + CertID: upres.CertId, + EnableHTTPS: true, }, }, } + if getDomainConfigResp.Result != nil && getDomainConfigResp.Result.HTTPSConfig != nil { + updateHttpsReq.UpdateHTTPSBody.HTTPS.EnableHTTPS = getDomainConfigResp.Result.HTTPSConfig.EnableHTTPS + updateHttpsReq.UpdateHTTPSBody.HTTPS.EnableHTTP2 = getDomainConfigResp.Result.HTTPSConfig.EnableHTTP2 + updateHttpsReq.UpdateHTTPSBody.HTTPS.EnableOcsp = getDomainConfigResp.Result.HTTPSConfig.EnableOcsp + updateHttpsReq.UpdateHTTPSBody.HTTPS.TLSVersions = getDomainConfigResp.Result.HTTPSConfig.TLSVersions + updateHttpsReq.UpdateHTTPSBody.HTTPS.EnableForceRedirect = getDomainConfigResp.Result.HTTPSConfig.EnableForceRedirect + updateHttpsReq.UpdateHTTPSBody.HTTPS.ForceRedirectType = getDomainConfigResp.Result.HTTPSConfig.ForceRedirectType + updateHttpsReq.UpdateHTTPSBody.HTTPS.ForceRedirectCode = getDomainConfigResp.Result.HTTPSConfig.ForceRedirectCode + } updateHttpsResp, err := d.sdkClient.UpdateHTTPS(context.TODO(), updateHttpsReq) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'imagex.UpdateHttps'") diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunWAFConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunWAFConfig.tsx index b7206d04..4f8fec71 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunWAFConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunWAFConfig.tsx @@ -3,9 +3,12 @@ import { Form, type FormInstance, Input } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; +import { validDomainName } from "@/utils/validators"; + type DeployNodeConfigFormAliyunWAFConfigFieldValues = Nullish<{ region: string; instanceId: string; + domain?: string; }>; export type DeployNodeConfigFormAliyunWAFConfigProps = { @@ -39,6 +42,12 @@ const DeployNodeConfigFormAliyunWAFConfig = ({ .nonempty(t("workflow_node.deploy.form.aliyun_waf_instance_id.placeholder")) .max(64, t("common.errmsg.string_max", { max: 64 })) .trim(), + domain: z + .string() + .nullish() + .refine((v) => { + return !v || validDomainName(v!, { allowWildcard: true }); + }, t("common.errmsg.domain_invalid")), }); const formRule = createSchemaFieldRule(formSchema); @@ -72,6 +81,15 @@ const DeployNodeConfigFormAliyunWAFConfig = ({ > + + } + > + + ); }; diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index 2cd53ab1..893e8ddd 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -202,6 +202,9 @@ "workflow_node.deploy.form.aliyun_waf_instance_id.label": "Alibaba Cloud WAF instance ID", "workflow_node.deploy.form.aliyun_waf_instance_id.placeholder": "Please enter Alibaba Cloud WAF instance ID", "workflow_node.deploy.form.aliyun_waf_instance_id.tooltip": "For more information, see https://waf.console.aliyun.com", + "workflow_node.deploy.form.aliyun_waf_domain.label": "Alibaba Cloud WAF domain (Optional)", + "workflow_node.deploy.form.aliyun_waf_domain.placeholder": "Please enter Alibaba Cloud WAF domain name", + "workflow_node.deploy.form.aliyun_waf_domain.tooltip": "For more information, see https://waf.console.aliyun.com", "workflow_node.deploy.form.aws_cloudfront_region.label": "AWS CloudFront Region", "workflow_node.deploy.form.aws_cloudfront_region.placeholder": "Please enter AWS CloudFront region (e.g. us-east-1)", "workflow_node.deploy.form.aws_cloudfront_region.tooltip": "For more information, see https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index b94d35fa..a2ff6c8e 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -201,7 +201,10 @@ "workflow_node.deploy.form.aliyun_waf_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint", "workflow_node.deploy.form.aliyun_waf_instance_id.label": "阿里云 WAF 实例 ID", "workflow_node.deploy.form.aliyun_waf_instance_id.placeholder": "请输入阿里云 WAF 实例 ID", - "workflow_node.deploy.form.aliyun_waf_instance_id.tooltip": "这是什么?请参阅 https://waf.console.aliyun.com", + "workflow_node.deploy.form.aliyun_waf_instance_id.tooltip": "这是什么?请参阅 https://waf.console.aliyun.com

仅支持 CNAME 接入。", + "workflow_node.deploy.form.aliyun_waf_domain.label": "阿里云 WAF 接入域名(可选)", + "workflow_node.deploy.form.aliyun_waf_domain.placeholder": "请输入阿里云 WAF 接入域名(支持泛域名)", + "workflow_node.deploy.form.aliyun_waf_domain.tooltip": "这是什么?请参阅 waf.console.aliyun.com

不填写时,将替换实例的默认证书。", "workflow_node.deploy.form.aws_cloudfront_region.label": "AWS CloudFront 服务区域", "workflow_node.deploy.form.aws_cloudfront_region.placeholder": "请输入 AWS CloudFront 服务区域(例如:us-east-1)", "workflow_node.deploy.form.aws_cloudfront_region.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints",