mirror of
https://github.com/certimate-go/certimate.git
synced 2026-09-24 23:10:13 +08:00
feat(provider): new deployment provider: yandexcloud certificatemanager
This commit is contained in:
@@ -82,6 +82,9 @@ require (
|
||||
github.com/volcengine/volcengine-go-sdk v1.2.42
|
||||
github.com/wneessen/go-mail v0.8.1
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0
|
||||
github.com/yandex-cloud/go-genproto v0.99.0
|
||||
github.com/yandex-cloud/go-sdk/services/certificatemanager v0.0.81
|
||||
github.com/yandex-cloud/go-sdk/v2 v2.142.0
|
||||
github.com/yunify/qingcloud-sdk-go v2.0.0-alpha.38+incompatible
|
||||
github.com/zenlayer/zenlayercloud-sdk-go v0.2.46
|
||||
gitlab.ecloud.com/ecloud/ecloudsdkcloudcore v1.0.0
|
||||
@@ -257,9 +260,7 @@ require (
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/tinylib/msgp v1.6.4 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/yandex-cloud/go-genproto v0.84.0 // indirect
|
||||
github.com/yandex-cloud/go-sdk/services/dns v0.0.65 // indirect
|
||||
github.com/yandex-cloud/go-sdk/v2 v2.114.0 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
github.com/zeebo/xxh3 v1.1.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
|
||||
@@ -953,12 +953,14 @@ github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
github.com/yandex-cloud/go-genproto v0.84.0 h1:lzptMyo1wleGBGNkkEb8bzpgbnW3xPlha0f94g4prBE=
|
||||
github.com/yandex-cloud/go-genproto v0.84.0/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
|
||||
github.com/yandex-cloud/go-genproto v0.99.0 h1:mRJPHWj186U0Ww1sE8E0U727MvWM2gv1MqUjBbiVgjE=
|
||||
github.com/yandex-cloud/go-genproto v0.99.0/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
|
||||
github.com/yandex-cloud/go-sdk/services/certificatemanager v0.0.81 h1:tMdRkO7LakoH2PsUixoGuCt5cdQDUdFo+7sxaItNUjA=
|
||||
github.com/yandex-cloud/go-sdk/services/certificatemanager v0.0.81/go.mod h1:VKW98WxZFwD04FSgniL5uObKaguR9zBhvwv770Ot2SM=
|
||||
github.com/yandex-cloud/go-sdk/services/dns v0.0.65 h1:7jhZMHsK1GThGzAKC7Mjq8wu/Xbr/TbhRUoNFzot4K4=
|
||||
github.com/yandex-cloud/go-sdk/services/dns v0.0.65/go.mod h1:Qm5HbUbmFI2Y8eDv8tcwr7OHgNumHuN/RtK3icd3bYU=
|
||||
github.com/yandex-cloud/go-sdk/v2 v2.114.0 h1:gx03giWYrzMhgpFK4NJNuOnASSgdCuv4nkLUFejnCSs=
|
||||
github.com/yandex-cloud/go-sdk/v2 v2.114.0/go.mod h1:XrF79/a3olVf0YUUCMYePI8Ik0m4KDcQlTooHGGZJB0=
|
||||
github.com/yandex-cloud/go-sdk/v2 v2.142.0 h1:4l02xAC/B0GNWLs+SAWiLNX2iah/DHb7t1k62mYl8tU=
|
||||
github.com/yandex-cloud/go-sdk/v2 v2.142.0/go.mod h1:cvtog6S0f82ju6ZqzQ6eMYz96P4cflml6R+W4/wDFEE=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/yandexcloud-certificatemanager"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeYandexCloudCertificateManager, func(options *ProviderFactoryOptions) (core.Deployer, error) {
|
||||
credentials := domain.AccessConfigForYandexCloud{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
|
||||
FolderId: credentials.FolderId,
|
||||
ServiceAccountKey: credentials.ServiceAccountKey,
|
||||
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -467,6 +467,7 @@ const (
|
||||
DeploymentProviderTypeWangsuCDNPro = DeploymentProviderType(AccessProviderTypeWangsu + "-cdnpro")
|
||||
DeploymentProviderTypeWangsuCertificate = DeploymentProviderType(AccessProviderTypeWangsu + "-certificate")
|
||||
DeploymentProviderTypeWebhook = DeploymentProviderType(AccessProviderTypeWebhook)
|
||||
DeploymentProviderTypeYandexCloudCertificateManager = DeploymentProviderType(AccessProviderTypeYandexCloud + "-certificatemanager")
|
||||
DeploymentProviderTypeZenlayerCDN = DeploymentProviderType(AccessProviderTypeZenlayer + "-cdn")
|
||||
DeploymentProviderTypeZenlayerGA = DeploymentProviderType(AccessProviderTypeZenlayer + "-ga")
|
||||
)
|
||||
|
||||
+10
@@ -1,6 +1,7 @@
|
||||
package googlecloudcertificatemanager_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
impl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/googlecloud-certificatemanager"
|
||||
@@ -11,12 +12,14 @@ var (
|
||||
fp = tester.Args("GOOGLECLOUDCERTIFICATEMANAGER_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fProjectId string
|
||||
fServiceAccountKey string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fProjectId, "PROJECTID")
|
||||
fp.DefineString(&fServiceAccountKey, "SERVICEACCOUNTKEY")
|
||||
}
|
||||
|
||||
@@ -26,13 +29,20 @@ Shell command to run this test:
|
||||
go test -v ./googlecloud_certificatemanager_test.go -args \
|
||||
--GOOGLECLOUDCERTIFICATEMANAGER_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--GOOGLECLOUDCERTIFICATEMANAGER_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--GOOGLECLOUDCERTIFICATEMANAGER_PROJECTID="your-project-id" \
|
||||
--GOOGLECLOUDCERTIFICATEMANAGER_SERVICEACCOUNTKEY="{...}"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
if fServiceAccountKeyStat, err := os.Stat(fServiceAccountKey); err == nil && !fServiceAccountKeyStat.IsDir() {
|
||||
fServiceAccountKeyBytes, _ := os.ReadFile(fServiceAccountKey)
|
||||
fServiceAccountKey = string(fServiceAccountKeyBytes)
|
||||
}
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
provider, err := impl.NewCertmgr(&impl.CertmgrConfig{
|
||||
ProjectId: fProjectId,
|
||||
ServiceAccountKey: fServiceAccountKey,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
package yandexcloudcertificatemanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
yccertificatemanagerproto "github.com/yandex-cloud/go-genproto/yandex/cloud/certificatemanager/v1"
|
||||
yccertificatemanager "github.com/yandex-cloud/go-sdk/services/certificatemanager/v1"
|
||||
ycsdk "github.com/yandex-cloud/go-sdk/v2"
|
||||
yccreds "github.com/yandex-cloud/go-sdk/v2/credentials"
|
||||
yciamkey "github.com/yandex-cloud/go-sdk/v2/pkg/iamkey"
|
||||
ycoptions "github.com/yandex-cloud/go-sdk/v2/pkg/options"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Certmgr
|
||||
UploadResult = core.CertmgrUploadResult
|
||||
ReplaceResult = core.CertmgrReplaceResult
|
||||
)
|
||||
|
||||
type CertmgrConfig struct {
|
||||
// Yandex Cloud 文件夹 ID。
|
||||
FolderId string `json:"folderId"`
|
||||
// Yandex Cloud 服务账号授权密钥。
|
||||
ServiceAccountKey string `json:"serviceAccountKey"`
|
||||
}
|
||||
|
||||
type Certmgr struct {
|
||||
config *CertmgrConfig
|
||||
logger *slog.Logger
|
||||
sdkClient yccertificatemanager.CertificateClient
|
||||
}
|
||||
|
||||
var _ Provider = (*Certmgr)(nil)
|
||||
|
||||
func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the certmgr provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.ServiceAccountKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
return &Certmgr{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Certmgr) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
c.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
c.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*UploadResult, error) {
|
||||
// 解析证书内容
|
||||
certX509, err := xcert.ParseCertificateFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 提取服务器证书和中间证书
|
||||
serverCertPEM, issuerCertPEM, err := xcert.ExtractCertificatesFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract certs: %w", err)
|
||||
}
|
||||
|
||||
// 获取证书列表,避免重复上传
|
||||
// REF: https://yandex.cloud/en/docs/certificate-manager/api-ref/Certificate/list
|
||||
listCertificatesPageToken := ""
|
||||
listCertificatesPageSize := 100
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
listCertificatesReq := &yccertificatemanagerproto.ListCertificatesRequest{
|
||||
FolderId: c.config.FolderId,
|
||||
PageSize: int64(listCertificatesPageSize),
|
||||
PageToken: listCertificatesPageToken,
|
||||
}
|
||||
listCertificatesResp, err := c.sdkClient.List(ctx, listCertificatesReq)
|
||||
c.logger.Debug("sdk request 'certificatemanager.certificate.list'", slog.Any("request", listCertificatesReq), slog.Any("response", listCertificatesResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'certificatemanager.certificate.list': %w", err)
|
||||
}
|
||||
|
||||
for _, certItem := range listCertificatesResp.Certificates {
|
||||
// 对比证书备用名称
|
||||
if !strings.EqualFold(strings.Join(certX509.DNSNames, ","), strings.Join(certItem.Domains, ",")) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 对比证书主题 DN
|
||||
if certX509.Subject.String() != certItem.Subject {
|
||||
continue
|
||||
}
|
||||
|
||||
// 对比证书颁发者 DN
|
||||
if certX509.Issuer.String() != certItem.Issuer {
|
||||
continue
|
||||
}
|
||||
|
||||
// 对比证书序列号
|
||||
if !strings.EqualFold(certX509.SerialNumber.Text(16), certItem.Serial) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 对比证书有效期
|
||||
if certItem.NotBefore != nil && certX509.NotBefore.Unix() != certItem.NotBefore.AsTime().Unix() {
|
||||
continue
|
||||
} else if certItem.NotAfter != nil && certX509.NotAfter.Unix() != certItem.NotAfter.AsTime().Unix() {
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果以上信息都一致,则视为已存在相同证书,直接返回
|
||||
c.logger.Info("ssl certificate already exists")
|
||||
return &UploadResult{
|
||||
CertId: certItem.Id,
|
||||
CertName: certItem.Name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if len(listCertificatesResp.Certificates) == 0 || listCertificatesResp.NextPageToken == "" {
|
||||
break
|
||||
}
|
||||
|
||||
listCertificatesPageToken = listCertificatesResp.NextPageToken
|
||||
}
|
||||
|
||||
// 创建证书
|
||||
// REF: https://yandex.cloud/en/docs/certificate-manager/api-ref/Certificate/create
|
||||
createCertificateReq := &yccertificatemanagerproto.CreateCertificateRequest{
|
||||
FolderId: c.config.FolderId,
|
||||
Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
|
||||
Description: "upload from Certimate",
|
||||
Certificate: serverCertPEM,
|
||||
Chain: issuerCertPEM,
|
||||
PrivateKey: privkeyPEM,
|
||||
}
|
||||
createCertificateResp, err := c.sdkClient.Create(ctx, createCertificateReq)
|
||||
c.logger.Debug("sdk request 'certificatemanager.certificate.create'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'certificatemanager.certificate.create': %w", err)
|
||||
}
|
||||
|
||||
return &UploadResult{
|
||||
CertId: createCertificateResp.Response().Id,
|
||||
CertName: createCertificateResp.Response().Name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, privkeyPEM string) (*ReplaceResult, error) {
|
||||
// 提取服务器证书和中间证书
|
||||
serverCertPEM, issuerCertPEM, err := xcert.ExtractCertificatesFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract certs: %w", err)
|
||||
}
|
||||
|
||||
// 获取证书
|
||||
// REF: https://yandex.cloud/en/docs/certificate-manager/api-ref/Certificate/get
|
||||
getCertificateReq := &yccertificatemanagerproto.GetCertificateRequest{
|
||||
CertificateId: certIdOrName,
|
||||
View: yccertificatemanagerproto.CertificateView_BASIC,
|
||||
}
|
||||
getCertificateResp, err := c.sdkClient.Get(ctx, getCertificateReq)
|
||||
c.logger.Debug("sdk request 'certificatemanager.certificate.get'", slog.Any("request", getCertificateReq), slog.Any("response", getCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'certificatemanager.certificate.get': %w", err)
|
||||
}
|
||||
|
||||
// 更新证书
|
||||
// REF: https://yandex.cloud/en/docs/certificate-manager/api-ref/Certificate/update
|
||||
updateCertificateReq := &yccertificatemanagerproto.UpdateCertificateRequest{
|
||||
CertificateId: certIdOrName,
|
||||
Name: getCertificateResp.Name,
|
||||
Description: getCertificateResp.Description,
|
||||
Labels: getCertificateResp.Labels,
|
||||
Certificate: serverCertPEM,
|
||||
Chain: issuerCertPEM,
|
||||
PrivateKey: privkeyPEM,
|
||||
DeletionProtection: getCertificateResp.DeletionProtection,
|
||||
}
|
||||
updateCertificateResp, err := c.sdkClient.Update(ctx, updateCertificateReq)
|
||||
c.logger.Debug("sdk request 'certificatemanager.certificate.update'", slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'certificatemanager.certificate.update': %w", err)
|
||||
}
|
||||
|
||||
return &ReplaceResult{}, nil
|
||||
}
|
||||
|
||||
func createSDKClient(serviceAccountKey string) (yccertificatemanager.CertificateClient, error) {
|
||||
saKey := []byte(serviceAccountKey)
|
||||
saConf := &yciamkey.Key{}
|
||||
if err := json.Unmarshal(saKey, saConf); err != nil {
|
||||
return nil, fmt.Errorf("unable to acquire service account config: %w", err)
|
||||
}
|
||||
|
||||
creds, err := yccreds.ServiceAccountKey(saConf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sdk, err := ycsdk.Build(context.Background(), ycoptions.WithCredentials(creds))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := yccertificatemanager.NewCertificateClient(sdk)
|
||||
return client, nil
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package yandexcloudcertificatemanager_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
impl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/yandexcloud-certificatemanager"
|
||||
tester "github.com/certimate-go/certimate/pkg/core/certmgr/testing"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.Args("YANDEXCLOUDCERTIFICATEMANAGER_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fFolderId string
|
||||
fServiceAccountKey string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fFolderId, "FOLDERID")
|
||||
fp.DefineString(&fServiceAccountKey, "SERVICEACCOUNTKEY")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./yandexcloud_certificatemanager_test.go -args \
|
||||
--YANDEXCLOUDCERTIFICATEMANAGER_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--YANDEXCLOUDCERTIFICATEMANAGER_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--YANDEXCLOUDCERTIFICATEMANAGER_FOLDERID="your-folder-id" \
|
||||
--YANDEXCLOUDCERTIFICATEMANAGER_SERVICEACCOUNTKEY="{...}"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
if fServiceAccountKeyStat, err := os.Stat(fServiceAccountKey); err == nil && !fServiceAccountKeyStat.IsDir() {
|
||||
fServiceAccountKeyBytes, _ := os.ReadFile(fServiceAccountKey)
|
||||
fServiceAccountKey = string(fServiceAccountKeyBytes)
|
||||
}
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
provider, err := impl.NewCertmgr(&impl.CertmgrConfig{
|
||||
FolderId: fFolderId,
|
||||
ServiceAccountKey: fServiceAccountKey,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
tester.TestUpload(t, provider, tester.TestUploadArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package k8ssecret_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/k8s-secret"
|
||||
@@ -11,6 +12,7 @@ var (
|
||||
fp = tester.Args("K8SSECRET_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fKubeConfig string
|
||||
fNamespace string
|
||||
fSecretName string
|
||||
fSecretDataKeyForCrt string
|
||||
@@ -20,6 +22,7 @@ var (
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fKubeConfig, "KUBECONFIG")
|
||||
fp.DefineString(&fNamespace, "NAMESPACE", "default")
|
||||
fp.DefineString(&fSecretName, "SECRETNAME")
|
||||
fp.DefineString(&fSecretDataKeyForCrt, "SECRETDATAKEYFORCRT", "tls.crt")
|
||||
@@ -32,6 +35,7 @@ Shell command to run this test:
|
||||
go test -v ./k8s_secret_test.go -args \
|
||||
--K8SSECRET_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--K8SSECRET_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--K8SSECRET_KUBECONFIG="..." \
|
||||
--K8SSECRET_NAMESPACE="default" \
|
||||
--K8SSECRET_SECRETNAME="secret" \
|
||||
--K8SSECRET_SECRETDATAKEYFORCRT="tls.crt" \
|
||||
@@ -40,8 +44,14 @@ Shell command to run this test:
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
if fKubeConfigStat, err := os.Stat(fKubeConfig); err == nil && !fKubeConfigStat.IsDir() {
|
||||
fKubeConfigBytes, _ := os.ReadFile(fKubeConfig)
|
||||
fKubeConfig = string(fKubeConfigBytes)
|
||||
}
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
KubeConfig: fKubeConfig,
|
||||
Namespace: fNamespace,
|
||||
SecretName: fSecretName,
|
||||
SecretDataKeyForCrt: fSecretDataKeyForCrt,
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package yandexcloudcertificatemanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/yandexcloud-certificatemanager"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// Yandex Cloud 文件夹 ID。
|
||||
FolderId string `json:"folderId"`
|
||||
// Yandex Cloud 服务账号授权密钥。
|
||||
ServiceAccountKey string `json:"serviceAccountKey"`
|
||||
// 证书管理器证书 ID。
|
||||
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkCertmgr core.Certmgr
|
||||
}
|
||||
|
||||
var _ Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
|
||||
}
|
||||
|
||||
pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
|
||||
FolderId: config.FolderId,
|
||||
ServiceAccountKey: config.ServiceAccountKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create certmgr: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkCertmgr: pcertmgr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
d.sdkCertmgr.SetLogger(logger)
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
if d.config.CertificateId == "" {
|
||||
// 上传证书
|
||||
upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
} else {
|
||||
// 替换证书
|
||||
rplres, err := d.sdkCertmgr.Replace(ctx, d.config.CertificateId, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to replace certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate replaced", slog.Any("result", rplres))
|
||||
}
|
||||
}
|
||||
|
||||
return &DeployResult{}, nil
|
||||
}
|
||||
@@ -144,6 +144,7 @@ import BizDeployNodeConfigFieldsProviderWangsuCDN from "./BizDeployNodeConfigFie
|
||||
import BizDeployNodeConfigFieldsProviderWangsuCDNPro from "./BizDeployNodeConfigFieldsProviderWangsuCDNPro";
|
||||
import BizDeployNodeConfigFieldsProviderWangsuCertificate from "./BizDeployNodeConfigFieldsProviderWangsuCertificate";
|
||||
import BizDeployNodeConfigFieldsProviderWebhook from "./BizDeployNodeConfigFieldsProviderWebhook";
|
||||
import BizDeployNodeConfigFieldsProviderYandexCloudCertificateManager from "./BizDeployNodeConfigFieldsProviderYandexCloudCertificateManager";
|
||||
import BizDeployNodeConfigFieldsProviderZenlayerCDN from "./BizDeployNodeConfigFieldsProviderZenlayerCDN";
|
||||
import BizDeployNodeConfigFieldsProviderZenlayerGA from "./BizDeployNodeConfigFieldsProviderZenlayerGA";
|
||||
|
||||
@@ -294,6 +295,7 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
|
||||
[DEPLOYMENT_PROVIDERS.WANGSU_CDNPRO]: BizDeployNodeConfigFieldsProviderWangsuCDNPro,
|
||||
[DEPLOYMENT_PROVIDERS.WANGSU_CERTIFICATE]: BizDeployNodeConfigFieldsProviderWangsuCertificate,
|
||||
[DEPLOYMENT_PROVIDERS.WEBHOOK]: BizDeployNodeConfigFieldsProviderWebhook,
|
||||
[DEPLOYMENT_PROVIDERS.YANDEXCLOUD_CERTIFICATEMANAGER]: BizDeployNodeConfigFieldsProviderYandexCloudCertificateManager,
|
||||
[DEPLOYMENT_PROVIDERS.ZENLAYER_CDN]: BizDeployNodeConfigFieldsProviderZenlayerCDN,
|
||||
[DEPLOYMENT_PROVIDERS.ZENLAYER_GA]: BizDeployNodeConfigFieldsProviderZenlayerGA,
|
||||
};
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderYandexCloudCertificateManager = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.yandexcloud_certificatemanager_certificate_id.label")}
|
||||
extra={t("workflow_node.deploy.form.yandexcloud_certificatemanager_certificate_id.help")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.yandexcloud_certificatemanager_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t: _ } = i18n;
|
||||
|
||||
return z.object({
|
||||
certificateId: z.string().nullish(),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderYandexCloudCertificateManager, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -184,6 +184,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
|
||||
[ACCESS_PROVIDERS.DIGITALOCEAN, "provider.digitalocean", "/imgs/providers/digitalocean.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.GCORE, "provider.gcore", "/imgs/providers/gcore.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.LINODE, "provider.linode", "/imgs/providers/linode.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.YANDEXCLOUD, "provider.yandexcloud", "/imgs/providers/yandexcloud.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.BAIDUCLOUD, "provider.baiducloud", "/imgs/providers/baiducloud.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.CMCCCLOUD, "provider.cmcccloud", "/imgs/providers/cmcccloud.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.CTCCCLOUD, "provider.ctcccloud", "/imgs/providers/ctcccloud.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
@@ -258,7 +259,6 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
|
||||
[ACCESS_PROVIDERS.SIMPLYCOM, "provider.simplycom", "/imgs/providers/simplycom.png", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS.SPACESHIP, "provider.spaceship", "/imgs/providers/spaceship.png", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS.VULTR, "provider.vultr", "/imgs/providers/vultr.svg", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS.YANDEXCLOUD, "provider.yandexcloud", "/imgs/providers/yandexcloud.svg", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS["35CN"], "provider.35cn", "/imgs/providers/35cn.png", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS["51DNSCOM"], "provider.51dnscom", "/imgs/providers/51dnscom.png", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS.DNSLA, "provider.dnsla", "/imgs/providers/dnsla.svg", [ACCESS_USAGES.DNS]],
|
||||
@@ -756,6 +756,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
|
||||
WANGSU_CDNPRO: `${ACCESS_PROVIDERS.WANGSU}-cdnpro`,
|
||||
WANGSU_CERTIFICATE: `${ACCESS_PROVIDERS.WANGSU}-certificate`,
|
||||
WEBHOOK: `${ACCESS_PROVIDERS.WEBHOOK}`,
|
||||
YANDEXCLOUD_CERTIFICATEMANAGER: `${ACCESS_PROVIDERS.YANDEXCLOUD}-certificatemanager`,
|
||||
ZENLAYER_CDN: `${ACCESS_PROVIDERS.ZENLAYER}-cdn`,
|
||||
ZENLAYER_GA: `${ACCESS_PROVIDERS.ZENLAYER}-ga`,
|
||||
} as const);
|
||||
@@ -876,6 +877,7 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
|
||||
[DEPLOYMENT_PROVIDERS.FLYIO, "provider.flyio", DEPLOYMENT_CATEGORIES.WEBSITE],
|
||||
[DEPLOYMENT_PROVIDERS.NETLIFY, "provider.netlify", DEPLOYMENT_CATEGORIES.WEBSITE],
|
||||
[DEPLOYMENT_PROVIDERS.VERCEL, "provider.vercel", DEPLOYMENT_CATEGORIES.WEBSITE],
|
||||
[DEPLOYMENT_PROVIDERS.YANDEXCLOUD_CERTIFICATEMANAGER, "provider.yandexcloud_certificatemanager", DEPLOYMENT_CATEGORIES.SSL],
|
||||
[DEPLOYMENT_PROVIDERS.ZENLAYER_CDN, "provider.zenlayer_cdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.ZENLAYER_GA, "provider.zenlayer_ga", DEPLOYMENT_CATEGORIES.ACCELERATOR],
|
||||
[DEPLOYMENT_PROVIDERS.BAIDUCLOUD_CDN, "provider.baiducloud_cdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
|
||||
@@ -299,6 +299,7 @@
|
||||
"westcn": "West.cn",
|
||||
"xinnet": "Xinnet.com",
|
||||
"yandexcloud": "Yandex Cloud",
|
||||
"yandexcloud_certificatemanager": "Yandex Cloud - Certificate Manager",
|
||||
"yandexcloud_dns": "Yandex Cloud - DNS",
|
||||
"zerossl": "ZeroSSL",
|
||||
"zenlayer": "Zenlayer",
|
||||
|
||||
@@ -963,7 +963,7 @@
|
||||
"aws_acm_certificate_arn": {
|
||||
"label": "AWS ACM certificate ARN (Optional)",
|
||||
"placeholder": "Please enter AWS ACM certificate ARN",
|
||||
"help": "Notes: Leave it blank to import a new certificate."
|
||||
"help": "Notes: Leave it blank to import a new certificate; otherwise, to replace the existing one."
|
||||
},
|
||||
"aws_alb_region": {
|
||||
"label": "AWS Region",
|
||||
@@ -2904,6 +2904,11 @@
|
||||
"placeholder": "Please enter Webhook timeout",
|
||||
"unit": "seconds"
|
||||
},
|
||||
"yandexcloud_certificatemanager_certificate_id": {
|
||||
"label": "Yandex Cloud Certificate Manager certificate ID (Optional)",
|
||||
"placeholder": "Please enter Yandex Cloud Certificate Manager certificate ID",
|
||||
"help": "Notes: Leave it blank to import a new certificate; otherwise, to replace the existing one."
|
||||
},
|
||||
"zenlayer_cdn_deploy_target": {
|
||||
"option": {
|
||||
"domain": {
|
||||
|
||||
@@ -299,6 +299,7 @@
|
||||
"westcn": "西部数码",
|
||||
"xinnet": "新网数码",
|
||||
"yandexcloud": "Yandex Cloud",
|
||||
"yandexcloud_certificatemanager": "Yandex Cloud - 证书管理器",
|
||||
"yandexcloud_dns": "Yandex Cloud - DNS",
|
||||
"zerossl": "ZeroSSL",
|
||||
"zenlayer": "Zenlayer",
|
||||
|
||||
@@ -2903,6 +2903,11 @@
|
||||
"placeholder": "请输入 Webhook 超时时间",
|
||||
"unit": "秒"
|
||||
},
|
||||
"yandexcloud_certificatemanager_certificate_id": {
|
||||
"label": "Yandex Cloud 证书管理器证书 ID(可选)",
|
||||
"placeholder": "请输入 Yandex Cloud 证书管理器证书 ID",
|
||||
"help": "提示:不填写时,将上传新证书;否则,将替换原证书。"
|
||||
},
|
||||
"zenlayer_cdn_deploy_target": {
|
||||
"option": {
|
||||
"domain": {
|
||||
|
||||
Reference in New Issue
Block a user