feat: deploy server certificate or intermedia certificate

This commit is contained in:
Fu Diwei
2025-05-15 01:40:37 +08:00
parent 178c62512d
commit 6c6bb78568
12 changed files with 210 additions and 70 deletions

View File

@@ -57,7 +57,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
// 提取 Edgio 所需的服务端证书和中间证书内容
privateCertPEM, intermediateCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
if err != nil {
return nil, err
}
@@ -66,8 +66,8 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
// REF: https://docs.edg.io/rest_api/#tag/tls-certs/operation/postConfigV01TlsCerts
uploadTlsCertReq := edgiodtos.UploadTlsCertRequest{
EnvironmentID: d.config.EnvironmentId,
PrimaryCert: privateCertPEM,
IntermediateCert: intermediateCertPEM,
PrimaryCert: serverCertPEM,
IntermediateCert: intermediaCertPEM,
PrivateKey: privkeyPEM,
}
uploadTlsCertResp, err := d.sdkClient.UploadTlsCert(uploadTlsCertReq)

View File

@@ -25,6 +25,12 @@ type DeployerConfig struct {
OutputFormat OutputFormatType `json:"outputFormat,omitempty"`
// 输出证书文件路径。
OutputCertPath string `json:"outputCertPath,omitempty"`
// 输出服务器证书文件路径。
// 选填。
OutputServerCertPath string `json:"outputServerCertPath,omitempty"`
// 输出中间证书文件路径。
// 选填。
OutputIntermediaCertPath string `json:"outputIntermediaCertPath,omitempty"`
// 输出私钥文件路径。
OutputKeyPath string `json:"outputKeyPath,omitempty"`
// PFX 导出密码。
@@ -69,6 +75,12 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
}
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
// 提取服务器证书和中间证书
serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
if err != nil {
return nil, fmt.Errorf("failed to extract certs: %w", err)
}
// 执行前置命令
if d.config.PreCommand != "" {
stdout, stderr, err := execCommand(d.config.ShellEnv, d.config.PreCommand)
@@ -86,6 +98,20 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
}
d.logger.Info("ssl certificate file saved", slog.String("path", d.config.OutputCertPath))
if d.config.OutputServerCertPath != "" {
if err := fileutil.WriteString(d.config.OutputServerCertPath, serverCertPEM); err != nil {
return nil, fmt.Errorf("failed to save server certificate file: %w", err)
}
d.logger.Info("ssl server certificate file saved", slog.String("path", d.config.OutputServerCertPath))
}
if d.config.OutputIntermediaCertPath != "" {
if err := fileutil.WriteString(d.config.OutputIntermediaCertPath, intermediaCertPEM); err != nil {
return nil, fmt.Errorf("failed to save intermedia certificate file: %w", err)
}
d.logger.Info("ssl intermedia certificate file saved", slog.String("path", d.config.OutputIntermediaCertPath))
}
if err := fileutil.WriteString(d.config.OutputKeyPath, privkeyPEM); err != nil {
return nil, fmt.Errorf("failed to save private key file: %w", err)
}

View File

@@ -41,6 +41,12 @@ type DeployerConfig struct {
OutputFormat OutputFormatType `json:"outputFormat,omitempty"`
// 输出证书文件路径。
OutputCertPath string `json:"outputCertPath,omitempty"`
// 输出服务器证书文件路径。
// 选填。
OutputServerCertPath string `json:"outputServerCertPath,omitempty"`
// 输出中间证书文件路径。
// 选填。
OutputIntermediaCertPath string `json:"outputIntermediaCertPath,omitempty"`
// 输出私钥文件路径。
OutputKeyPath string `json:"outputKeyPath,omitempty"`
// PFX 导出密码。
@@ -85,6 +91,12 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
}
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
// 提取服务器证书和中间证书
serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
if err != nil {
return nil, fmt.Errorf("failed to extract certs: %w", err)
}
// 连接
client, err := createSshClient(
d.config.SshHost,
@@ -118,6 +130,20 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
}
d.logger.Info("ssl certificate file uploaded", slog.String("path", d.config.OutputCertPath))
if d.config.OutputServerCertPath != "" {
if err := writeFileString(client, d.config.UseSCP, d.config.OutputServerCertPath, serverCertPEM); err != nil {
return nil, fmt.Errorf("failed to save server certificate file: %w", err)
}
d.logger.Info("ssl server certificate file uploaded", slog.String("path", d.config.OutputServerCertPath))
}
if d.config.OutputIntermediaCertPath != "" {
if err := writeFileString(client, d.config.UseSCP, d.config.OutputIntermediaCertPath, intermediaCertPEM); err != nil {
return nil, fmt.Errorf("failed to save intermedia certificate file: %w", err)
}
d.logger.Info("ssl intermedia certificate file uploaded", slog.String("path", d.config.OutputIntermediaCertPath))
}
if err := writeFileString(client, d.config.UseSCP, d.config.OutputKeyPath, privkeyPEM); err != nil {
return nil, fmt.Errorf("failed to upload private key file: %w", err)
}

View File

@@ -75,6 +75,12 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
return nil, fmt.Errorf("failed to parse x509: %w", err)
}
// 提取服务器证书和中间证书
serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
if err != nil {
return nil, fmt.Errorf("failed to extract certs: %w", err)
}
// 处理 Webhook URL
webhookUrl, err := url.Parse(d.config.WebhookUrl)
if err != nil {
@@ -134,6 +140,8 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
replaceJsonValueRecursively(webhookData, "${DOMAIN}", certX509.Subject.CommonName)
replaceJsonValueRecursively(webhookData, "${DOMAINS}", strings.Join(certX509.DNSNames, ";"))
replaceJsonValueRecursively(webhookData, "${CERTIFICATE}", certPEM)
replaceJsonValueRecursively(webhookData, "${SERVER_CERTIFICATE}", serverCertPEM)
replaceJsonValueRecursively(webhookData, "${INTERMEDIA_CERTIFICATE}", intermediaCertPEM)
replaceJsonValueRecursively(webhookData, "${PRIVATE_KEY}", privkeyPEM)
if webhookMethod == http.MethodGet || webhookContentType == CONTENT_TYPE_FORM || webhookContentType == CONTENT_TYPE_MULTIPART {

View File

@@ -12,9 +12,9 @@ import (
//
// 出参:
// - serverCertPEM: 服务器证书的 PEM 内容。
// - interCertPEM: 中间证书的 PEM 内容。
// - intermediaCertPEM: 中间证书的 PEM 内容。
// - err: 错误。
func ExtractCertificatesFromPEM(certPEM string) (serverCertPEM string, interCertPEM string, err error) {
func ExtractCertificatesFromPEM(certPEM string) (serverCertPEM string, intermediaCertPEM string, err error) {
pemBlocks := make([]*pem.Block, 0)
pemData := []byte(certPEM)
for {
@@ -28,7 +28,7 @@ func ExtractCertificatesFromPEM(certPEM string) (serverCertPEM string, interCert
}
serverCertPEM = ""
interCertPEM = ""
intermediaCertPEM = ""
if len(pemBlocks) == 0 {
return "", "", errors.New("failed to decode PEM block")
@@ -40,9 +40,9 @@ func ExtractCertificatesFromPEM(certPEM string) (serverCertPEM string, interCert
if len(pemBlocks) > 1 {
for i := 1; i < len(pemBlocks); i++ {
interCertPEM += string(pem.EncodeToMemory(pemBlocks[i]))
intermediaCertPEM += string(pem.EncodeToMemory(pemBlocks[i]))
}
}
return serverCertPEM, interCertPEM, nil
return serverCertPEM, intermediaCertPEM, nil
}