diff --git a/internal/certdeploy/deployers/sp_tencentcloud_eo.go b/internal/certdeploy/deployers/sp_tencentcloud_eo.go index 3732ac46..d6ac84ad 100644 --- a/internal/certdeploy/deployers/sp_tencentcloud_eo.go +++ b/internal/certdeploy/deployers/sp_tencentcloud_eo.go @@ -20,11 +20,12 @@ func init() { } provider, err := tencentcloudeo.NewSSLDeployerProvider(&tencentcloudeo.SSLDeployerProviderConfig{ - SecretId: credentials.SecretId, - SecretKey: credentials.SecretKey, - Endpoint: xmaps.GetString(options.ProviderExtendedConfig, "endpoint"), - ZoneId: xmaps.GetString(options.ProviderExtendedConfig, "zoneId"), - Domains: lo.Filter(strings.Split(xmaps.GetString(options.ProviderExtendedConfig, "domains"), ";"), func(s string, _ int) bool { return s != "" }), + SecretId: credentials.SecretId, + SecretKey: credentials.SecretKey, + Endpoint: xmaps.GetString(options.ProviderExtendedConfig, "endpoint"), + ZoneId: xmaps.GetString(options.ProviderExtendedConfig, "zoneId"), + MatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "matchPattern"), + Domains: lo.Filter(strings.Split(xmaps.GetString(options.ProviderExtendedConfig, "domains"), ";"), func(s string, _ int) bool { return s != "" }), }) return provider, err }); err != nil { diff --git a/pkg/core/ssl-deployer/providers/tencentcloud-eo/consts.go b/pkg/core/ssl-deployer/providers/tencentcloud-eo/consts.go new file mode 100644 index 00000000..c57c63ff --- /dev/null +++ b/pkg/core/ssl-deployer/providers/tencentcloud-eo/consts.go @@ -0,0 +1,8 @@ +package tencentcloudeo + +const ( + // 匹配模式:精确匹配。 + MatchPatternExact = "exact" + // 匹配模式:通配符匹配。 + MatchPatternWildcard = "wildcard" +) diff --git a/pkg/core/ssl-deployer/providers/tencentcloud-eo/tencentcloud_eo.go b/pkg/core/ssl-deployer/providers/tencentcloud-eo/tencentcloud_eo.go index 15559306..e04dc89f 100644 --- a/pkg/core/ssl-deployer/providers/tencentcloud-eo/tencentcloud_eo.go +++ b/pkg/core/ssl-deployer/providers/tencentcloud-eo/tencentcloud_eo.go @@ -14,6 +14,7 @@ import ( "github.com/certimate-go/certimate/pkg/core" sslmgrsp "github.com/certimate-go/certimate/pkg/core/ssl-manager/providers/tencentcloud-ssl" + xcert "github.com/certimate-go/certimate/pkg/utils/cert" ) type SSLDeployerProviderConfig struct { @@ -25,6 +26,9 @@ type SSLDeployerProviderConfig struct { Endpoint string `json:"endpoint,omitempty"` // 站点 ID。 ZoneId string `json:"zoneId"` + // 域名匹配模式。 + // 零值时默认值 [MatchPatternExact]。 + MatchPattern string `json:"matchPattern,omitempty"` // 加速域名列表(支持泛域名)。 Domains []string `json:"domains"` } @@ -93,12 +97,52 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } + var domains []string + switch d.config.MatchPattern { + case "", MatchPatternExact: + { + if len(d.config.Domains) == 0 { + return nil, errors.New("config `domains` is required") + } + + domains = d.config.Domains + } + + case MatchPatternWildcard: + { + if len(d.config.Domains) == 0 { + return nil, errors.New("config `domains` is required") + } + + domainsInZone, err := d.getDomainsInZone(ctx, d.config.ZoneId) + if err != nil { + return nil, err + } + + domains = lo.Filter(domainsInZone, func(domain string, _ int) bool { + for _, configDomain := range d.config.Domains { + if xcert.MatchHostname(configDomain, domain) { + return true + } + } + return false + }) + + if len(domains) == 0 { + return nil, errors.New("no domains matched in wildcard mode") + } + } + + default: + return nil, fmt.Errorf("unsupported match pattern: '%s'", d.config.MatchPattern) + } + // 配置域名证书 // REF: https://cloud.tencent.com/document/api/1552/80764 modifyHostsCertificateReq := tcteo.NewModifyHostsCertificateRequest() modifyHostsCertificateReq.ZoneId = common.StringPtr(d.config.ZoneId) modifyHostsCertificateReq.Mode = common.StringPtr("sslcert") - modifyHostsCertificateReq.Hosts = common.StringPtrs(d.config.Domains) + modifyHostsCertificateReq.Hosts = common.StringPtrs(domains) modifyHostsCertificateReq.ServerCertInfo = []*tcteo.ServerCertInfo{{CertId: common.StringPtr(upres.CertId)}} modifyHostsCertificateResp, err := d.sdkClient.ModifyHostsCertificate(modifyHostsCertificateReq) d.logger.Debug("sdk request 'teo.ModifyHostsCertificate'", slog.Any("request", modifyHostsCertificateReq), slog.Any("response", modifyHostsCertificateResp)) @@ -109,6 +153,44 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke return &core.SSLDeployResult{}, nil } +func (d *SSLDeployerProvider) getDomainsInZone(ctx context.Context, zoneId string) ([]string, error) { + var domainsInZone []string + + const pageSize = 200 + for offset := 0; ; offset += pageSize { + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + + // 查询加速域名列表 + // REF: https://cloud.tencent.com/document/api/1552/86336 + describeAccelerationDomainsReq := tcteo.NewDescribeAccelerationDomainsRequest() + describeAccelerationDomainsReq.Limit = common.Int64Ptr(pageSize) + describeAccelerationDomainsReq.Offset = common.Int64Ptr(int64(offset)) + describeAccelerationDomainsReq.ZoneId = common.StringPtr(zoneId) + describeAccelerationDomainsResp, err := d.sdkClient.DescribeAccelerationDomains(describeAccelerationDomainsReq) + d.logger.Debug("sdk request 'teo.DescribeAccelerationDomains'", slog.Any("request", describeAccelerationDomainsReq), slog.Any("response", describeAccelerationDomainsResp)) + if err != nil { + return nil, fmt.Errorf("failed to execute sdk request 'teo.DescribeAccelerationDomains': %w", err) + } + + for _, accelerationDomain := range describeAccelerationDomainsResp.Response.AccelerationDomains { + if accelerationDomain == nil || accelerationDomain.DomainName == nil { + continue + } + domainsInZone = append(domainsInZone, *accelerationDomain.DomainName) + } + + if len(describeAccelerationDomainsResp.Response.AccelerationDomains) < pageSize { + break + } + } + + return domainsInZone, nil +} + func createSDKClient(secretId, secretKey, endpoint string) (*tcteo.Client, error) { credential := common.NewCredential(secretId, secretKey) diff --git a/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProviderTencentCloudEO.tsx b/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProviderTencentCloudEO.tsx index 0fe7317a..c7180e0b 100644 --- a/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProviderTencentCloudEO.tsx +++ b/ui/src/components/workflow/designer/forms/BizDeployNodeConfigFieldsProviderTencentCloudEO.tsx @@ -1,5 +1,5 @@ import { getI18n, useTranslation } from "react-i18next"; -import { Form, Input } from "antd"; +import { Form, Input, Radio } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; @@ -9,6 +9,8 @@ import { validDomainName } from "@/utils/validators"; import { useFormNestedFieldsContext } from "./_context"; const MULTIPLE_INPUT_SEPARATOR = ";"; +const MATCH_PATTERN_EXACT = "exact" as const; +const MATCH_PATTERN_WILDCARD = "wildcard" as const; const BizDeployNodeConfigFieldsProviderTencentCloudEO = () => { const { i18n, t } = useTranslation(); @@ -42,6 +44,22 @@ const BizDeployNodeConfigFieldsProviderTencentCloudEO = () => { +