Merge pull request #955 from fudiwei/dev

This commit is contained in:
RHQYZ
2025-09-06 01:01:53 +08:00
committed by GitHub
8 changed files with 92 additions and 60 deletions
@@ -0,0 +1,30 @@
package deployers
import (
"fmt"
"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
huaweicloudobs "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/huaweicloud-obs"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)
func init() {
if err := Registries.Register(domain.DeploymentProviderTypeHuaweiCloudOBS, func(options *ProviderFactoryOptions) (core.SSLDeployer, error) {
credentials := domain.AccessConfigForHuaweiCloud{}
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
provider, err := huaweicloudobs.NewSSLDeployerProvider(&huaweicloudobs.SSLDeployerProviderConfig{
AccessKeyId: credentials.AccessKeyId,
SecretAccessKey: credentials.SecretAccessKey,
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
Bucket: xmaps.GetString(options.ProviderExtendedConfig, "bucket"),
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
})
return provider, err
}); err != nil {
panic(err)
}
}
@@ -11,7 +11,6 @@ import (
"fmt"
"log/slog"
"net/http"
"strings"
"time"
"github.com/certimate-go/certimate/pkg/core"
@@ -22,11 +21,11 @@ type SSLDeployerProviderConfig struct {
AccessKeyId string `json:"accessKeyId"`
// 华为云 SecretAccessKey。
SecretAccessKey string `json:"secretAccessKey"`
// 华为云 Bucket 对应的 Endpoint。
Endpoint string `json:"endpoint"`
// 华为云 OBS 桶名。
// 华为云区域。
Region string `json:"region"`
// 存储桶名。
Bucket string `json:"bucket"`
// 自定义域名。
// 自定义域名(不支持泛域名)。
Domain string `json:"domain"`
}
@@ -42,8 +41,6 @@ func NewSSLDeployerProvider(config *SSLDeployerProviderConfig) (*SSLDeployerProv
return nil, errors.New("the configuration of the ssl deployer provider is nil")
}
config.Endpoint = strings.TrimPrefix(strings.TrimPrefix(config.Endpoint, "http://"), "https://")
return &SSLDeployerProvider{
config: config,
logger: slog.Default(),
@@ -58,14 +55,20 @@ func (d *SSLDeployerProvider) SetLogger(logger *slog.Logger) {
}
}
// REF: https://support.huaweicloud.com/usermanual-obs/obs_06_3200.html
// REF: https://support.huaweicloud.com/api-obs/obs_04_0059.html
func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLDeployResult, error) {
if d.config.Region == "" {
return nil, fmt.Errorf("config `region` is required")
}
if d.config.Bucket == "" {
return nil, fmt.Errorf("config `bucket` is required")
}
if d.config.Domain == "" {
return nil, fmt.Errorf("config `domain` is required")
}
url := fmt.Sprintf("https://%s.%s/?customdomain=%s", d.config.Bucket, d.config.Endpoint, d.config.Domain)
// REF: https://support.huaweicloud.com/usermanual-obs/obs_06_3200.html
// REF: https://support.huaweicloud.com/api-obs/obs_04_0059.html
url := fmt.Sprintf("https://%s.obs.%s.myhuaweicloud.com/?customdomain=%s", d.config.Bucket, d.config.Region, d.config.Domain)
bodyXML := fmt.Sprintf(`
<CustomDomainConfiguration>
<Name>%s</Name>
@@ -78,16 +81,14 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
// 计算 Content-MD5(Base64 编码)
md5sum := md5.Sum([]byte(bodyXML))
contentMD5 := base64.StdEncoding.EncodeToString(md5sum[:])
// 日期
date := time.Now().UTC().Format(http.TimeFormat)
md5sumEncoded := base64.StdEncoding.EncodeToString(md5sum[:])
// 构造签名字符串
date := time.Now().UTC().Format(http.TimeFormat)
method := "PUT"
contentType := "application/xml"
canonicalizedResource := fmt.Sprintf("/%s/?customdomain=%s", d.config.Bucket, d.config.Domain)
stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s\n%s", method, contentMD5, contentType, date, canonicalizedResource)
stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s\n%s", method, md5sumEncoded, contentType, date, canonicalizedResource)
// HMAC-SHA1 签名
h := hmac.New(sha1.New, []byte(d.config.SecretAccessKey))
@@ -100,25 +101,26 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
// 创建请求
req, err := http.NewRequest(method, url, bytes.NewBuffer([]byte(bodyXML)))
if err != nil {
return nil, err
return nil, fmt.Errorf("huaweicloud obs api error: %w", err)
}
req.Header.Set("Date", date)
req.Header.Set("Authorization", authHeader)
req.Header.Set("Content-MD5", contentMD5)
req.Header.Set("Content-MD5", md5sumEncoded)
req.Header.Set("Content-Type", contentType)
// 请求
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
return nil, fmt.Errorf("huaweicloud obs api error: %w", err)
}
defer resp.Body.Close()
// 响应
if resp.StatusCode != http.StatusOK {
body := new(bytes.Buffer)
body := &bytes.Buffer{}
body.ReadFrom(resp.Body)
return nil, fmt.Errorf("HTTP request failed with status %d: %s", resp.StatusCode, body.String())
return nil, fmt.Errorf("huaweicloud obs api error: unexpected status code: %d, resp: %s", resp.StatusCode, body.String())
}
return &core.SSLDeployResult{}, nil
}
@@ -16,19 +16,19 @@ var (
fInputKeyPath string
fAccessKeyId string
fSecretAccessKey string
fEndpoint string
fRegion string
fBucket string
fDomain string
)
func init() {
argsPrefix := "CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_"
argsPrefix := "CERTIMATE_SSLDEPLOYER_HUAWEICLOUDOBS_"
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
flag.StringVar(&fEndpoint, argsPrefix+"ENDPOINT", "", "")
flag.StringVar(&fRegion, argsPrefix+"REGION", "", "")
flag.StringVar(&fBucket, argsPrefix+"BUCKET", "", "")
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
}
@@ -37,13 +37,13 @@ func init() {
Shell command to run this test:
go test -v ./huaweicloud_obs_test.go -args \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_ACCESSKEYID="your-access-key-id" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_SECRETACCESSKEY="your-secret-access-key" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_ENDPOINT="https://your-endpoint" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_BUCKET="your-bucket" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_DOMAIN="example.com"
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDOBS_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDOBS_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDOBS_ACCESSKEYID="your-access-key-id" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDOBS_SECRETACCESSKEY="your-secret-access-key" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDOBS_REGION="cn-north-4" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDOBS_BUCKET="your-bucket" \
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDOBS_DOMAIN="example.com"
*/
func TestDeploy(t *testing.T) {
flag.Parse()
@@ -55,7 +55,7 @@ func TestDeploy(t *testing.T) {
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
fmt.Sprintf("ENDPOINT: %v", fEndpoint),
fmt.Sprintf("REGION: %v", fRegion),
fmt.Sprintf("BUCKET: %v", fBucket),
fmt.Sprintf("DOMAIN: %v", fDomain),
}, "\n"))
@@ -63,7 +63,7 @@ func TestDeploy(t *testing.T) {
deployer, err := provider.NewSSLDeployerProvider(&provider.SSLDeployerProviderConfig{
AccessKeyId: fAccessKeyId,
SecretAccessKey: fSecretAccessKey,
Endpoint: fEndpoint,
Region: fRegion,
Bucket: fBucket,
Domain: fDomain,
})
@@ -20,13 +20,13 @@ const BizDeployNodeConfigFieldsProviderHuaweiCloudOBS = () => {
return (
<>
<Form.Item
name={[parentNamePath, "endpoint"]}
initialValue={initialValues.endpoint}
label={t("workflow_node.deploy.form.huaweicloud_obs_endpoint.label")}
name={[parentNamePath, "region"]}
initialValue={initialValues.region}
label={t("workflow_node.deploy.form.huaweicloud_obs_region.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.huaweicloud_obs_endpoint.tooltip") }}></span>}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.huaweicloud_obs_region.tooltip") }}></span>}
>
<Input placeholder={t("workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder")} />
<Input placeholder={t("workflow_node.deploy.form.huaweicloud_obs_region.placeholder")} />
</Form.Item>
<Form.Item
@@ -54,7 +54,7 @@ const BizDeployNodeConfigFieldsProviderHuaweiCloudOBS = () => {
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
return {
endpoint: "",
region: "",
bucket: "",
domain: "",
};
@@ -64,9 +64,9 @@ const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> })
const { t } = i18n;
return z.object({
endpoint: z
.string(t("workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder"))
.nonempty(t("workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder")),
region: z
.string(t("workflow_node.deploy.form.huaweicloud_obs_region.placeholder"))
.nonempty(t("workflow_node.deploy.form.huaweicloud_obs_region.placeholder")),
bucket: z
.string(t("workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder"))
.nonempty(t("workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder")),
+1 -1
View File
@@ -95,8 +95,8 @@
"provider.huaweicloud.cdn": "Huawei Cloud - CDN (Content Delivery Network)",
"provider.huaweicloud.dns": "Huawei Cloud - DNS",
"provider.huaweicloud.elb": "Huawei Cloud - ELB (Elastic Load Balance)",
"provider.huaweicloud.scm_upload": "Huawei Cloud - Upload to SCM (SSL Certificate Manager)",
"provider.huaweicloud.obs": "Huawei Cloud - OBS (Object Storage Service)",
"provider.huaweicloud.scm_upload": "Huawei Cloud - Upload to SCM (SSL Certificate Manager)",
"provider.huaweicloud.waf": "Huawei Cloud - WAF (Web Application Firewall)",
"provider.jdcloud": "JD Cloud",
"provider.jdcloud.alb": "JD Cloud - ALB (Application Load Balancer)",
@@ -518,15 +518,15 @@
"workflow_node.deploy.form.huaweicloud_cdn_domain.label": "Huawei Cloud CDN domain",
"workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder": "Please enter Huawei Cloud CDN domain name",
"workflow_node.deploy.form.huaweicloud_cdn_domain.tooltip": "For more information, see <a href=\"https://console-intl.huaweicloud.com/cdn\" target=\"_blank\">https://console-intl.huaweicloud.com/cdn</a>",
"workflow_node.deploy.form.huaweicloud_obs_endpoint.label": "Huawei Cloud OBS Endpoint",
"workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder": "Please enter the Huawei Cloud OBS endpoint (e.g., obs.cn-north-4.myhuaweicloud.com)",
"workflow_node.deploy.form.huaweicloud_obs_endpoint.tooltip": "What is this? Please refer to <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0152.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0152.html</a>",
"workflow_node.deploy.form.huaweicloud_obs_bucket.label": "Huawei Cloud COS Bucket Name",
"workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder": "Please enter the Huawei Cloud COS bucket name",
"workflow_node.deploy.form.huaweicloud_obs_bucket.tooltip": "What is this? Please refer to <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
"workflow_node.deploy.form.huaweicloud_obs_domain.label": "Huawei Cloud COS Custom Domain",
"workflow_node.deploy.form.huaweicloud_obs_domain.placeholder": "Please enter the Huawei Cloud COS custom domain",
"workflow_node.deploy.form.huaweicloud_obs_domain.tooltip": "What is this? Please refer to <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
"workflow_node.deploy.form.huaweicloud_obs_region.label": "Huawei Cloud OBS region",
"workflow_node.deploy.form.huaweicloud_obs_region.placeholder": "Please enter the Huawei Cloud OBS region (e.g. cn-north-1)",
"workflow_node.deploy.form.huaweicloud_obs_region.tooltip": "For more information, see <a href=\"https://console-intl.huaweicloud.com/apiexplorer/#/endpoint?locale=en-us\" target=\"_blank\">https://console-intl.huaweicloud.com/apiexplorer/#/endpoint</a>",
"workflow_node.deploy.form.huaweicloud_obs_bucket.label": "Huawei Cloud OBS bucket name",
"workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder": "Please enter the Huawei Cloud OBS bucket name",
"workflow_node.deploy.form.huaweicloud_obs_bucket.tooltip": "For more information, see <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
"workflow_node.deploy.form.huaweicloud_obs_domain.label": "Huawei Cloud OBS custom domain",
"workflow_node.deploy.form.huaweicloud_obs_domain.placeholder": "Please enter the Huawei Cloud OBS custom domain name",
"workflow_node.deploy.form.huaweicloud_obs_domain.tooltip": "For more information, see <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
"workflow_node.deploy.form.huaweicloud_elb_region.label": "Huawei Cloud ELB region",
"workflow_node.deploy.form.huaweicloud_elb_region.placeholder": "Please enter Huawei Cloud ELB region (e.g. cn-north-1)",
"workflow_node.deploy.form.huaweicloud_elb_region.tooltip": "For more information, see <a href=\"https://console-intl.huaweicloud.com/apiexplorer/#/endpoint?locale=en-us\" target=\"_blank\">https://console-intl.huaweicloud.com/apiexplorer/#/endpoint</a>",
+1 -1
View File
@@ -95,8 +95,8 @@
"provider.huaweicloud.cdn": "华为云 - 内容分发网络 CDN",
"provider.huaweicloud.dns": "华为云 - 云解析 DNS",
"provider.huaweicloud.elb": "华为云 - 弹性负载均衡 ELB",
"provider.huaweicloud.obs": "华为云 - 对象储存服务 OBS",
"provider.huaweicloud.scm_upload": "华为云 - 上传到云证书管理服务 SCM",
"provider.huaweicloud.obs": "华为云 - 对象储存 OBS",
"provider.huaweicloud.waf": "华为云 - Web 应用防火墙 WAF",
"provider.jdcloud": "京东云",
"provider.jdcloud.alb": "京东云 - 应用负载均衡 ALB",
@@ -516,14 +516,14 @@
"workflow_node.deploy.form.huaweicloud_cdn_domain.label": "华为云 CDN 加速域名",
"workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder": "请输入华为云 CDN 加速域名(支持泛域名)",
"workflow_node.deploy.form.huaweicloud_cdn_domain.tooltip": "这是什么?请参阅 <a href=\"https://console.huaweicloud.com/cdn\" target=\"_blank\">https://console.huaweicloud.com/cdn</a>",
"workflow_node.deploy.form.huaweicloud_obs_endpoint.label": "华为云 OBS 接口端点",
"workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder": "请输入华为云 OBS 接口端点(例如:obs.cn-north-4.myhuaweicloud.com)",
"workflow_node.deploy.form.huaweicloud_obs_endpoint.tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0152.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0152.html</a>",
"workflow_node.deploy.form.huaweicloud_obs_bucket.label": "华为云 COS 存储桶名",
"workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder": "请输入华为云 COS 存储桶名",
"workflow_node.deploy.form.huaweicloud_obs_region.label": "华为云 OBS 服务区域",
"workflow_node.deploy.form.huaweicloud_obs_region.placeholder": "请输入华为云 OBS 服务区域(例如:cn-north-1)",
"workflow_node.deploy.form.huaweicloud_obs_region.tooltip": "这是什么?请参阅 <a href=\"https://console.huaweicloud.com/apiexplorer/#/endpoint\" target=\"_blank\">https://console.huaweicloud.com/apiexplorer/#/endpoint</a>",
"workflow_node.deploy.form.huaweicloud_obs_bucket.label": "华为云 OBS 存储桶名",
"workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder": "请输入华为云 OBS 存储桶名",
"workflow_node.deploy.form.huaweicloud_obs_bucket.tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
"workflow_node.deploy.form.huaweicloud_obs_domain.label": "华为云 COS 自定义域名",
"workflow_node.deploy.form.huaweicloud_obs_domain.placeholder": "请输入华为云 COS 自定义域名",
"workflow_node.deploy.form.huaweicloud_obs_domain.label": "华为云 OBS 自定义域名",
"workflow_node.deploy.form.huaweicloud_obs_domain.placeholder": "请输入华为云 OBS 自定义域名",
"workflow_node.deploy.form.huaweicloud_obs_domain.tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
"workflow_node.deploy.form.huaweicloud_elb_region.label": "华为云 ELB 服务区域",
"workflow_node.deploy.form.huaweicloud_elb_region.placeholder": "请输入华为云 ELB 服务区域(例如:cn-north-1)",