mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-10 22:49:51 +00:00
refactor: extend huaweicloud cdn sdk
This commit is contained in:
parent
be495839b6
commit
ce55365292
@ -15,13 +15,14 @@ import (
|
|||||||
"github.com/usual2970/certimate/internal/domain"
|
"github.com/usual2970/certimate/internal/domain"
|
||||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||||
"github.com/usual2970/certimate/internal/pkg/utils/cast"
|
"github.com/usual2970/certimate/internal/pkg/utils/cast"
|
||||||
|
hcCdnEx "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-cdn-sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HuaweiCloudCDNDeployer struct {
|
type HuaweiCloudCDNDeployer struct {
|
||||||
option *DeployerOption
|
option *DeployerOption
|
||||||
infos []string
|
infos []string
|
||||||
|
|
||||||
sdkClient *hcCdn.CdnClient
|
sdkClient *hcCdnEx.Client
|
||||||
sslUploader uploader.Uploader
|
sslUploader uploader.Uploader
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +41,6 @@ func NewHuaweiCloudCDNDeployer(option *DeployerOption) (Deployer, error) {
|
|||||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: SCM 服务与 DNS 服务所支持的区域可能不一致,这里暂时不传而是使用默认值,仅支持华为云国内版
|
|
||||||
uploader, err := uploader.NewHuaweiCloudSCMUploader(&uploader.HuaweiCloudSCMUploaderConfig{
|
uploader, err := uploader.NewHuaweiCloudSCMUploader(&uploader.HuaweiCloudSCMUploaderConfig{
|
||||||
AccessKeyId: access.AccessKeyId,
|
AccessKeyId: access.AccessKeyId,
|
||||||
SecretAccessKey: access.SecretAccessKey,
|
SecretAccessKey: access.SecretAccessKey,
|
||||||
@ -82,10 +82,9 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error {
|
|||||||
// 更新加速域名配置
|
// 更新加速域名配置
|
||||||
// REF: https://support.huaweicloud.com/api-cdn/UpdateDomainMultiCertificates.html
|
// REF: https://support.huaweicloud.com/api-cdn/UpdateDomainMultiCertificates.html
|
||||||
// REF: https://support.huaweicloud.com/usermanual-cdn/cdn_01_0306.html
|
// REF: https://support.huaweicloud.com/usermanual-cdn/cdn_01_0306.html
|
||||||
updateDomainMultiCertificatesReqBodyContent := &huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent{}
|
updateDomainMultiCertificatesReqBodyContent := &hcCdnEx.UpdateDomainMultiCertificatesExRequestBodyContent{}
|
||||||
updateDomainMultiCertificatesReqBodyContent.DomainName = d.option.DeployConfig.GetConfigAsString("domain")
|
updateDomainMultiCertificatesReqBodyContent.DomainName = d.option.DeployConfig.GetConfigAsString("domain")
|
||||||
updateDomainMultiCertificatesReqBodyContent.HttpsSwitch = 1
|
updateDomainMultiCertificatesReqBodyContent.HttpsSwitch = 1
|
||||||
var updateDomainMultiCertificatesResp *hcCdnModel.UpdateDomainMultiCertificatesResponse
|
|
||||||
if d.option.DeployConfig.GetConfigAsBool("useSCM") {
|
if d.option.DeployConfig.GetConfigAsBool("useSCM") {
|
||||||
// 上传证书到 SCM
|
// 上传证书到 SCM
|
||||||
upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
|
upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
|
||||||
@ -104,13 +103,13 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error {
|
|||||||
updateDomainMultiCertificatesReqBodyContent.Certificate = cast.StringPtr(d.option.Certificate.Certificate)
|
updateDomainMultiCertificatesReqBodyContent.Certificate = cast.StringPtr(d.option.Certificate.Certificate)
|
||||||
updateDomainMultiCertificatesReqBodyContent.PrivateKey = cast.StringPtr(d.option.Certificate.PrivateKey)
|
updateDomainMultiCertificatesReqBodyContent.PrivateKey = cast.StringPtr(d.option.Certificate.PrivateKey)
|
||||||
}
|
}
|
||||||
updateDomainMultiCertificatesReqBodyContent = mergeHuaweiCloudCDNConfig(showDomainFullConfigResp.Configs, updateDomainMultiCertificatesReqBodyContent)
|
updateDomainMultiCertificatesReqBodyContent = updateDomainMultiCertificatesReqBodyContent.MergeConfig(showDomainFullConfigResp.Configs)
|
||||||
updateDomainMultiCertificatesReq := &huaweicloudCDNUpdateDomainMultiCertificatesRequest{
|
updateDomainMultiCertificatesReq := &hcCdnEx.UpdateDomainMultiCertificatesExRequest{
|
||||||
Body: &huaweicloudCDNUpdateDomainMultiCertificatesRequestBody{
|
Body: &hcCdnEx.UpdateDomainMultiCertificatesExRequestBody{
|
||||||
Https: updateDomainMultiCertificatesReqBodyContent,
|
Https: updateDomainMultiCertificatesReqBodyContent,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
updateDomainMultiCertificatesResp, err = executeHuaweiCloudCDNUploadDomainMultiCertificates(d.sdkClient, updateDomainMultiCertificatesReq)
|
updateDomainMultiCertificatesResp, err := d.sdkClient.UploadDomainMultiCertificatesEx(updateDomainMultiCertificatesReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -120,7 +119,7 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *HuaweiCloudCDNDeployer) createSdkClient(accessKeyId, secretAccessKey, region string) (*hcCdn.CdnClient, error) {
|
func (d *HuaweiCloudCDNDeployer) createSdkClient(accessKeyId, secretAccessKey, region string) (*hcCdnEx.Client, error) {
|
||||||
if region == "" {
|
if region == "" {
|
||||||
region = "cn-north-1" // CDN 服务默认区域:华北一北京
|
region = "cn-north-1" // CDN 服务默认区域:华北一北京
|
||||||
}
|
}
|
||||||
@ -146,69 +145,6 @@ func (d *HuaweiCloudCDNDeployer) createSdkClient(accessKeyId, secretAccessKey, r
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
client := hcCdn.NewCdnClient(hcClient)
|
client := hcCdnEx.NewClient(hcClient)
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent struct {
|
|
||||||
hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent `json:",inline"`
|
|
||||||
|
|
||||||
SCMCertificateId *string `json:"scm_certificate_id,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type huaweicloudCDNUpdateDomainMultiCertificatesRequestBody struct {
|
|
||||||
Https *huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent `json:"https,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type huaweicloudCDNUpdateDomainMultiCertificatesRequest struct {
|
|
||||||
Body *huaweicloudCDNUpdateDomainMultiCertificatesRequestBody `json:"body,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func executeHuaweiCloudCDNUploadDomainMultiCertificates(client *hcCdn.CdnClient, request *huaweicloudCDNUpdateDomainMultiCertificatesRequest) (*hcCdnModel.UpdateDomainMultiCertificatesResponse, error) {
|
|
||||||
// 华为云官方 SDK 中目前提供的字段缺失,这里暂时先需自定义请求
|
|
||||||
// 可能需要等之后 SDK 更新
|
|
||||||
|
|
||||||
requestDef := hcCdn.GenReqDefForUpdateDomainMultiCertificates()
|
|
||||||
|
|
||||||
if resp, err := client.HcClient.Sync(request, requestDef); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return resp.(*hcCdnModel.UpdateDomainMultiCertificatesResponse), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergeHuaweiCloudCDNConfig(src *hcCdnModel.ConfigsGetBody, dest *huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent) *huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent {
|
|
||||||
if src == nil {
|
|
||||||
return dest
|
|
||||||
}
|
|
||||||
|
|
||||||
// 华为云 API 中不传的字段表示使用默认值、而非保留原值,因此这里需要把原配置中的参数重新赋值回去
|
|
||||||
// 而且蛋疼的是查询接口返回的数据结构和更新接口传入的参数结构不一致,需要做很多转化
|
|
||||||
|
|
||||||
if *src.OriginProtocol == "follow" {
|
|
||||||
dest.AccessOriginWay = cast.Int32Ptr(1)
|
|
||||||
} else if *src.OriginProtocol == "http" {
|
|
||||||
dest.AccessOriginWay = cast.Int32Ptr(2)
|
|
||||||
} else if *src.OriginProtocol == "https" {
|
|
||||||
dest.AccessOriginWay = cast.Int32Ptr(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
if src.ForceRedirect != nil {
|
|
||||||
dest.ForceRedirectConfig = &hcCdnModel.ForceRedirect{}
|
|
||||||
|
|
||||||
if src.ForceRedirect.Status == "on" {
|
|
||||||
dest.ForceRedirectConfig.Switch = 1
|
|
||||||
dest.ForceRedirectConfig.RedirectType = src.ForceRedirect.Type
|
|
||||||
} else {
|
|
||||||
dest.ForceRedirectConfig.Switch = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if src.Https != nil {
|
|
||||||
if *src.Https.Http2Status == "on" {
|
|
||||||
dest.Http2 = cast.Int32Ptr(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dest
|
|
||||||
}
|
|
||||||
|
22
internal/pkg/utils/x509/common.go
Normal file
22
internal/pkg/utils/x509/common.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package x509
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 比较两个 x509.Certificate 对象,判断它们是否是同一张证书。
|
||||||
|
// 注意,这不是精确比较,而只是基于证书序列号和数字签名的快速判断,但对于权威 CA 签发的证书来说不会存在误判。
|
||||||
|
//
|
||||||
|
// 入参:
|
||||||
|
// - a: 待比较的第一个 x509.Certificate 对象。
|
||||||
|
// - b: 待比较的第二个 x509.Certificate 对象。
|
||||||
|
//
|
||||||
|
// 出参:
|
||||||
|
// - 是否相同。
|
||||||
|
func EqualCertificate(a, b *x509.Certificate) bool {
|
||||||
|
return string(a.Signature) == string(b.Signature) &&
|
||||||
|
a.SignatureAlgorithm == b.SignatureAlgorithm &&
|
||||||
|
a.SerialNumber.String() == b.SerialNumber.String() &&
|
||||||
|
a.Issuer.SerialNumber == b.Issuer.SerialNumber &&
|
||||||
|
a.Subject.SerialNumber == b.Subject.SerialNumber
|
||||||
|
}
|
31
internal/pkg/utils/x509/converter.go
Normal file
31
internal/pkg/utils/x509/converter.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package x509
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
|
|
||||||
|
xerrors "github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 将 ecdsa.PrivateKey 对象转换为 PEM 编码的字符串。
|
||||||
|
//
|
||||||
|
// 入参:
|
||||||
|
// - privkey: ecdsa.PrivateKey 对象。
|
||||||
|
//
|
||||||
|
// 出参:
|
||||||
|
// - privkeyPem: 私钥 PEM 内容。
|
||||||
|
// - err: 错误。
|
||||||
|
func ConvertECPrivateKeyToPEM(privkey *ecdsa.PrivateKey) (privkeyPem string, err error) {
|
||||||
|
data, err := x509.MarshalECPrivateKey(privkey)
|
||||||
|
if err != nil {
|
||||||
|
return "", xerrors.Wrap(err, "failed to marshal EC private key")
|
||||||
|
}
|
||||||
|
|
||||||
|
block := &pem.Block{
|
||||||
|
Type: "EC PRIVATE KEY",
|
||||||
|
Bytes: data,
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(pem.EncodeToMemory(block)), nil
|
||||||
|
}
|
@ -10,23 +10,6 @@ import (
|
|||||||
xerrors "github.com/pkg/errors"
|
xerrors "github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 比较两个 x509.Certificate 对象,判断它们是否是同一张证书。
|
|
||||||
// 注意,这不是精确比较,而只是基于证书序列号和数字签名的快速判断,但对于权威 CA 签发的证书来说不会存在误判。
|
|
||||||
//
|
|
||||||
// 入参:
|
|
||||||
// - a: 待比较的第一个 x509.Certificate 对象。
|
|
||||||
// - b: 待比较的第二个 x509.Certificate 对象。
|
|
||||||
//
|
|
||||||
// 出参:
|
|
||||||
// - 是否相同。
|
|
||||||
func EqualCertificate(a, b *x509.Certificate) bool {
|
|
||||||
return string(a.Signature) == string(b.Signature) &&
|
|
||||||
a.SignatureAlgorithm == b.SignatureAlgorithm &&
|
|
||||||
a.SerialNumber.String() == b.SerialNumber.String() &&
|
|
||||||
a.Issuer.SerialNumber == b.Issuer.SerialNumber &&
|
|
||||||
a.Subject.SerialNumber == b.Subject.SerialNumber
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从 PEM 编码的证书字符串解析并返回一个 x509.Certificate 对象。
|
// 从 PEM 编码的证书字符串解析并返回一个 x509.Certificate 对象。
|
||||||
//
|
//
|
||||||
// 入参:
|
// 入参:
|
||||||
@ -98,25 +81,3 @@ func ParsePKCS1PrivateKeyFromPEM(privkeyPem string) (privkey *rsa.PrivateKey, er
|
|||||||
|
|
||||||
return privkey, nil
|
return privkey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 ecdsa.PrivateKey 对象转换为 PEM 编码的字符串。
|
|
||||||
//
|
|
||||||
// 入参:
|
|
||||||
// - privkey: ecdsa.PrivateKey 对象。
|
|
||||||
//
|
|
||||||
// 出参:
|
|
||||||
// - privkeyPem: 私钥 PEM 内容。
|
|
||||||
// - err: 错误。
|
|
||||||
func ConvertECPrivateKeyToPEM(privkey *ecdsa.PrivateKey) (privkeyPem string, err error) {
|
|
||||||
data, err := x509.MarshalECPrivateKey(privkey)
|
|
||||||
if err != nil {
|
|
||||||
return "", xerrors.Wrap(err, "failed to marshal EC private key")
|
|
||||||
}
|
|
||||||
|
|
||||||
block := &pem.Block{
|
|
||||||
Type: "EC PRIVATE KEY",
|
|
||||||
Bytes: data,
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(pem.EncodeToMemory(block)), nil
|
|
||||||
}
|
|
26
internal/pkg/vendors/huaweicloud-cdn-sdk/client.go
vendored
Normal file
26
internal/pkg/vendors/huaweicloud-cdn-sdk/client.go
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package huaweicloudcdnsdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core"
|
||||||
|
hcCdn "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
hcCdn.CdnClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(hcClient *core.HcHttpClient) *Client {
|
||||||
|
return &Client{
|
||||||
|
CdnClient: *hcCdn.NewCdnClient(hcClient),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UploadDomainMultiCertificatesEx(request *UpdateDomainMultiCertificatesExRequest) (*UpdateDomainMultiCertificatesExResponse, error) {
|
||||||
|
requestDef := hcCdn.GenReqDefForUpdateDomainMultiCertificates()
|
||||||
|
|
||||||
|
if resp, err := c.HcClient.Sync(request, requestDef); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return resp.(*UpdateDomainMultiCertificatesExResponse), nil
|
||||||
|
}
|
||||||
|
}
|
62
internal/pkg/vendors/huaweicloud-cdn-sdk/models.go
vendored
Normal file
62
internal/pkg/vendors/huaweicloud-cdn-sdk/models.go
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package huaweicloudcdnsdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
hcCdnModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/model"
|
||||||
|
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/utils/cast"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateDomainMultiCertificatesExRequestBodyContent struct {
|
||||||
|
hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent `json:",inline"`
|
||||||
|
|
||||||
|
// 华为云官方 SDK 中目前提供的字段缺失,这里暂时先需自定义请求,可能需要等之后 SDK 更新。
|
||||||
|
SCMCertificateId *string `json:"scm_certificate_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateDomainMultiCertificatesExRequestBody struct {
|
||||||
|
Https *UpdateDomainMultiCertificatesExRequestBodyContent `json:"https,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateDomainMultiCertificatesExRequest struct {
|
||||||
|
Body *UpdateDomainMultiCertificatesExRequestBody `json:"body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateDomainMultiCertificatesExResponse struct {
|
||||||
|
hcCdnModel.UpdateDomainMultiCertificatesResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UpdateDomainMultiCertificatesExRequestBodyContent) MergeConfig(src *hcCdnModel.ConfigsGetBody) *UpdateDomainMultiCertificatesExRequestBodyContent {
|
||||||
|
if src == nil {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// 华为云 API 中不传的字段表示使用默认值、而非保留原值,因此这里需要把原配置中的参数重新赋值回去。
|
||||||
|
// 而且蛋疼的是查询接口返回的数据结构和更新接口传入的参数结构不一致,需要做很多转化。
|
||||||
|
|
||||||
|
if *src.OriginProtocol == "follow" {
|
||||||
|
m.AccessOriginWay = cast.Int32Ptr(1)
|
||||||
|
} else if *src.OriginProtocol == "http" {
|
||||||
|
m.AccessOriginWay = cast.Int32Ptr(2)
|
||||||
|
} else if *src.OriginProtocol == "https" {
|
||||||
|
m.AccessOriginWay = cast.Int32Ptr(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
if src.ForceRedirect != nil {
|
||||||
|
m.ForceRedirectConfig = &hcCdnModel.ForceRedirect{}
|
||||||
|
|
||||||
|
if src.ForceRedirect.Status == "on" {
|
||||||
|
m.ForceRedirectConfig.Switch = 1
|
||||||
|
m.ForceRedirectConfig.RedirectType = src.ForceRedirect.Type
|
||||||
|
} else {
|
||||||
|
m.ForceRedirectConfig.Switch = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if src.Https != nil {
|
||||||
|
if *src.Https.Http2Status == "on" {
|
||||||
|
m.Http2 = cast.Int32Ptr(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user