feat: add tencent cloud ssl-deploy deployer

This commit is contained in:
Fu Diwei
2025-02-10 22:19:08 +08:00
parent 316bd58b68
commit 6673871db2
14 changed files with 414 additions and 55 deletions

View File

@@ -34,6 +34,7 @@ import (
providerTencentCloudCSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-css"
providerTencentCloudECDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ecdn"
providerTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-eo"
providerTencentCloudSSLDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy"
providerUCloudUCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-ucdn"
providerUCloudUS3 "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-us3"
providerVolcEngineCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-cdn"
@@ -387,7 +388,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger,
return deployer, logger, err
}
case domain.DeployProviderTypeTencentCloudCDN, domain.DeployProviderTypeTencentCloudCLB, domain.DeployProviderTypeTencentCloudCOS, domain.DeployProviderTypeTencentCloudCSS, domain.DeployProviderTypeTencentCloudECDN, domain.DeployProviderTypeTencentCloudEO:
case domain.DeployProviderTypeTencentCloudCDN, domain.DeployProviderTypeTencentCloudCLB, domain.DeployProviderTypeTencentCloudCOS, domain.DeployProviderTypeTencentCloudCSS, domain.DeployProviderTypeTencentCloudECDN, domain.DeployProviderTypeTencentCloudEO, domain.DeployProviderTypeTencentCloudSSLDeploy:
{
access := domain.AccessConfigForTencentCloud{}
if err := maps.Decode(options.ProviderAccessConfig, &access); err != nil {
@@ -450,6 +451,16 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger,
}, logger)
return deployer, logger, err
case domain.DeployProviderTypeTencentCloudSSLDeploy:
deployer, err := providerTencentCloudSSLDeploy.NewWithLogger(&providerTencentCloudSSLDeploy.TencentCloudSSLDeployDeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"),
ResourceType: maps.GetValueAsString(options.ProviderDeployConfig, "resourceType"),
ResourceIds: slices.Filter(strings.Split(maps.GetValueAsString(options.ProviderDeployConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }),
}, logger)
return deployer, logger, err
default:
break
}

View File

@@ -82,40 +82,41 @@ type DeployProviderType string
NOTICE: If you add new constant, please keep ASCII order.
*/
const (
DeployProviderTypeAliyunALB = DeployProviderType("aliyun-alb")
DeployProviderTypeAliyunCASDeploy = DeployProviderType("aliyun-cas-deploy")
DeployProviderTypeAliyunCDN = DeployProviderType("aliyun-cdn")
DeployProviderTypeAliyunCLB = DeployProviderType("aliyun-clb")
DeployProviderTypeAliyunDCDN = DeployProviderType("aliyun-dcdn")
DeployProviderTypeAliyunESA = DeployProviderType("aliyun-esa")
DeployProviderTypeAliyunLive = DeployProviderType("aliyun-live")
DeployProviderTypeAliyunNLB = DeployProviderType("aliyun-nlb")
DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss")
DeployProviderTypeAliyunWAF = DeployProviderType("aliyun-waf")
DeployProviderTypeAWSCloudFront = DeployProviderType("aws-cloudfront")
DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn")
DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn")
DeployProviderTypeDogeCloudCDN = DeployProviderType("dogecloud-cdn")
DeployProviderTypeEdgioApplications = DeployProviderType("edgio-applications")
DeployProviderTypeHuaweiCloudCDN = DeployProviderType("huaweicloud-cdn")
DeployProviderTypeHuaweiCloudELB = DeployProviderType("huaweicloud-elb")
DeployProviderTypeKubernetesSecret = DeployProviderType("k8s-secret")
DeployProviderTypeLocal = DeployProviderType("local")
DeployProviderTypeQiniuCDN = DeployProviderType("qiniu-cdn")
DeployProviderTypeQiniuPili = DeployProviderType("qiniu-pili")
DeployProviderTypeSSH = DeployProviderType("ssh")
DeployProviderTypeTencentCloudCDN = DeployProviderType("tencentcloud-cdn")
DeployProviderTypeTencentCloudCLB = DeployProviderType("tencentcloud-clb")
DeployProviderTypeTencentCloudCOS = DeployProviderType("tencentcloud-cos")
DeployProviderTypeTencentCloudCSS = DeployProviderType("tencentcloud-css")
DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn")
DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo")
DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn")
DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3")
DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn")
DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb")
DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn")
DeployProviderTypeVolcEngineLive = DeployProviderType("volcengine-live")
DeployProviderTypeVolcEngineTOS = DeployProviderType("volcengine-tos")
DeployProviderTypeWebhook = DeployProviderType("webhook")
DeployProviderTypeAliyunALB = DeployProviderType("aliyun-alb")
DeployProviderTypeAliyunCASDeploy = DeployProviderType("aliyun-casdeploy")
DeployProviderTypeAliyunCDN = DeployProviderType("aliyun-cdn")
DeployProviderTypeAliyunCLB = DeployProviderType("aliyun-clb")
DeployProviderTypeAliyunDCDN = DeployProviderType("aliyun-dcdn")
DeployProviderTypeAliyunESA = DeployProviderType("aliyun-esa")
DeployProviderTypeAliyunLive = DeployProviderType("aliyun-live")
DeployProviderTypeAliyunNLB = DeployProviderType("aliyun-nlb")
DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss")
DeployProviderTypeAliyunWAF = DeployProviderType("aliyun-waf")
DeployProviderTypeAWSCloudFront = DeployProviderType("aws-cloudfront")
DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn")
DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn")
DeployProviderTypeDogeCloudCDN = DeployProviderType("dogecloud-cdn")
DeployProviderTypeEdgioApplications = DeployProviderType("edgio-applications")
DeployProviderTypeHuaweiCloudCDN = DeployProviderType("huaweicloud-cdn")
DeployProviderTypeHuaweiCloudELB = DeployProviderType("huaweicloud-elb")
DeployProviderTypeKubernetesSecret = DeployProviderType("k8s-secret")
DeployProviderTypeLocal = DeployProviderType("local")
DeployProviderTypeQiniuCDN = DeployProviderType("qiniu-cdn")
DeployProviderTypeQiniuPili = DeployProviderType("qiniu-pili")
DeployProviderTypeSSH = DeployProviderType("ssh")
DeployProviderTypeTencentCloudCDN = DeployProviderType("tencentcloud-cdn")
DeployProviderTypeTencentCloudCLB = DeployProviderType("tencentcloud-clb")
DeployProviderTypeTencentCloudCOS = DeployProviderType("tencentcloud-cos")
DeployProviderTypeTencentCloudCSS = DeployProviderType("tencentcloud-css")
DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn")
DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo")
DeployProviderTypeTencentCloudSSLDeploy = DeployProviderType("tencentcloud-ssldeploy")
DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn")
DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3")
DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn")
DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb")
DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn")
DeployProviderTypeVolcEngineLive = DeployProviderType("volcengine-live")
DeployProviderTypeVolcEngineTOS = DeployProviderType("volcengine-tos")
DeployProviderTypeWebhook = DeployProviderType("webhook")
)

View File

@@ -4,7 +4,7 @@ type DeployResourceType string
const (
// 资源类型:通过 SSL 服务部署到云资源实例。
DEPLOY_RESOURCE_USE_SSLDEPLOY = DeployResourceType("ssl-deploy")
DEPLOY_RESOURCE_VIA_SSLDEPLOY = DeployResourceType("ssl-deploy")
// 资源类型:部署到指定负载均衡器。
DEPLOY_RESOURCE_LOADBALANCER = DeployResourceType("loadbalancer")
// 资源类型:部署到指定监听器。

View File

@@ -96,8 +96,8 @@ func (d *TencentCloudCLBDeployer) Deploy(ctx context.Context, certPem string, pr
// 根据部署资源类型决定部署方式
switch d.config.ResourceType {
case DEPLOY_RESOURCE_USE_SSLDEPLOY:
if err := d.deployToInstanceUseSsl(ctx, upres.CertId); err != nil {
case DEPLOY_RESOURCE_VIA_SSLDEPLOY:
if err := d.deployViaSslService(ctx, upres.CertId); err != nil {
return nil, err
}
@@ -123,7 +123,7 @@ func (d *TencentCloudCLBDeployer) Deploy(ctx context.Context, certPem string, pr
return &deployer.DeployResult{}, nil
}
func (d *TencentCloudCLBDeployer) deployToInstanceUseSsl(ctx context.Context, cloudCertId string) error {
func (d *TencentCloudCLBDeployer) deployViaSslService(ctx context.Context, cloudCertId string) error {
if d.config.LoadbalancerId == "" {
return errors.New("config `loadbalancerId` is required")
}

View File

@@ -68,7 +68,7 @@ func TestDeploy(t *testing.T) {
SecretId: fSecretId,
SecretKey: fSecretKey,
Region: fRegion,
ResourceType: provider.DEPLOY_RESOURCE_USE_SSLDEPLOY,
ResourceType: provider.DEPLOY_RESOURCE_VIA_SSLDEPLOY,
LoadbalancerId: fLoadbalancerId,
ListenerId: fListenerId,
Domain: fDomain,

View File

@@ -0,0 +1,156 @@
package tencentcloudssldeploy
import (
"context"
"errors"
"fmt"
"time"
xerrors "github.com/pkg/errors"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
"github.com/usual2970/certimate/internal/pkg/core/deployer"
"github.com/usual2970/certimate/internal/pkg/core/logger"
"github.com/usual2970/certimate/internal/pkg/core/uploader"
uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl"
)
type TencentCloudSSLDeployDeployerConfig struct {
// 腾讯云 SecretId。
SecretId string `json:"secretId"`
// 腾讯云 SecretKey。
SecretKey string `json:"secretKey"`
// 腾讯云地域。
Region string `json:"region"`
// 腾讯云云资源类型。
ResourceType string `json:"resourceType"`
// 腾讯云云资源 ID 数组。
ResourceIds []string `json:"resourceIds"`
}
type TencentCloudSSLDeployDeployer struct {
config *TencentCloudSSLDeployDeployerConfig
logger logger.Logger
sdkClient *tcSsl.Client
sslUploader uploader.Uploader
}
var _ deployer.Deployer = (*TencentCloudSSLDeployDeployer)(nil)
func New(config *TencentCloudSSLDeployDeployerConfig) (*TencentCloudSSLDeployDeployer, error) {
return NewWithLogger(config, logger.NewNilLogger())
}
func NewWithLogger(config *TencentCloudSSLDeployDeployerConfig, logger logger.Logger) (*TencentCloudSSLDeployDeployer, error) {
if config == nil {
return nil, errors.New("config is nil")
}
if logger == nil {
return nil, errors.New("logger is nil")
}
client, err := createSdkClient(config.SecretId, config.SecretKey, config.Region)
if err != nil {
return nil, xerrors.Wrap(err, "failed to create sdk client")
}
uploader, err := uploaderp.New(&uploaderp.TencentCloudSSLUploaderConfig{
SecretId: config.SecretId,
SecretKey: config.SecretKey,
})
if err != nil {
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
}
return &TencentCloudSSLDeployDeployer{
logger: logger,
config: config,
sdkClient: client,
sslUploader: uploader,
}, nil
}
func (d *TencentCloudSSLDeployDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
if d.config.ResourceType == "" {
return nil, errors.New("config `resourceType` is required")
}
if len(d.config.ResourceIds) == 0 {
return nil, errors.New("config `resourceIds` is required")
}
// 上传证书到 SSL
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file")
}
d.logger.Logt("certificate file uploaded", upres)
// 证书部署到云资源实例列表
// REF: https://cloud.tencent.com/document/product/400/91667
deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest()
deployCertificateInstanceReq.CertificateId = common.StringPtr(upres.CertId)
deployCertificateInstanceReq.ResourceType = common.StringPtr(d.config.ResourceType)
deployCertificateInstanceReq.InstanceIdList = common.StringPtrs(d.config.ResourceIds)
deployCertificateInstanceReq.Status = common.Int64Ptr(1)
deployCertificateInstanceResp, err := d.sdkClient.DeployCertificateInstance(deployCertificateInstanceReq)
if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'")
} else if deployCertificateInstanceResp.Response == nil || deployCertificateInstanceResp.Response.DeployRecordId == nil {
return nil, errors.New("failed to create deploy record")
}
d.logger.Logt("已部署证书到云资源实例", deployCertificateInstanceResp.Response)
// 循环获取部署任务详情,等待任务状态变更
// REF: https://cloud.tencent.com.cn/document/api/400/91658
for {
if ctx.Err() != nil {
return nil, ctx.Err()
}
describeHostDeployRecordDetailReq := tcSsl.NewDescribeHostDeployRecordDetailRequest()
describeHostDeployRecordDetailReq.DeployRecordId = common.StringPtr(fmt.Sprintf("%d", *deployCertificateInstanceResp.Response.DeployRecordId))
describeHostDeployRecordDetailReq.Limit = common.Uint64Ptr(100)
describeHostDeployRecordDetailResp, err := d.sdkClient.DescribeHostDeployRecordDetail(describeHostDeployRecordDetailReq)
if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DescribeHostDeployRecordDetail'")
}
if describeHostDeployRecordDetailResp.Response.TotalCount == nil {
return nil, errors.New("部署任务状态异常")
} else {
acc := int64(0)
if describeHostDeployRecordDetailResp.Response.SuccessTotalCount != nil {
acc += *describeHostDeployRecordDetailResp.Response.SuccessTotalCount
}
if describeHostDeployRecordDetailResp.Response.FailedTotalCount != nil {
acc += *describeHostDeployRecordDetailResp.Response.FailedTotalCount
}
if acc == *describeHostDeployRecordDetailResp.Response.TotalCount {
d.logger.Logt("已获取部署任务详情", describeHostDeployRecordDetailResp)
break
}
}
d.logger.Logt("部署任务未完成 ...")
time.Sleep(time.Second * 5)
}
return &deployer.DeployResult{}, nil
}
func createSdkClient(secretId, secretKey, region string) (*tcSsl.Client, error) {
credential := common.NewCredential(secretId, secretKey)
client, err := tcSsl.NewClient(credential, region, profile.NewClientProfile())
if err != nil {
return nil, err
}
return client, nil
}