mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-08 05:29:51 +00:00
feat: support replacing old certificate on deployment to aws acm
This commit is contained in:
parent
cd93a2d72c
commit
9e08cfd1d1
@ -306,6 +306,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
|
||||
CertificateArn: maputil.GetString(options.ProviderExtendedConfig, "certificateArn"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
|
@ -5,9 +5,15 @@ import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
aws "github.com/aws/aws-sdk-go-v2/aws"
|
||||
awscfg "github.com/aws/aws-sdk-go-v2/config"
|
||||
awscred "github.com/aws/aws-sdk-go-v2/credentials"
|
||||
awsacm "github.com/aws/aws-sdk-go-v2/service/acm"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
|
||||
certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
@ -17,11 +23,15 @@ type DeployerConfig struct {
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// AWS 区域。
|
||||
Region string `json:"region"`
|
||||
// ACM 证书 ARN。
|
||||
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||
CertificateArn string `json:"certificateArn,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *awsacm.Client
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
@ -32,6 +42,11 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
@ -44,6 +59,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
@ -59,6 +75,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
if d.config.CertificateArn == "" {
|
||||
// 上传证书到 ACM
|
||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
@ -66,6 +83,40 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
} else {
|
||||
// 提取服务器证书
|
||||
serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract certs: %w", err)
|
||||
}
|
||||
|
||||
// 导入证书
|
||||
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ImportCertificate.html
|
||||
importCertificateReq := &awsacm.ImportCertificateInput{
|
||||
CertificateArn: aws.String(d.config.CertificateArn),
|
||||
Certificate: ([]byte)(serverCertPEM),
|
||||
CertificateChain: ([]byte)(intermediaCertPEM),
|
||||
PrivateKey: ([]byte)(privkeyPEM),
|
||||
}
|
||||
importCertificateResp, err := d.sdkClient.ImportCertificate(context.TODO(), importCertificateReq)
|
||||
d.logger.Debug("sdk request 'acm.ImportCertificate'", slog.Any("request", importCertificateReq), slog.Any("response", importCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'acm.ImportCertificate': %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, secretAccessKey, region string) (*awsacm.Client, error) {
|
||||
cfg, err := awscfg.LoadDefaultConfig(context.TODO())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := awsacm.NewFromConfig(cfg, func(o *awsacm.Options) {
|
||||
o.Region = region
|
||||
o.Credentials = aws.NewCredentialsCache(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, ""))
|
||||
})
|
||||
return client, nil
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ type DeployerConfig struct {
|
||||
// Key Vault 名称。
|
||||
KeyVaultName string `json:"keyvaultName"`
|
||||
// Key Vault 证书名称。
|
||||
// 选填。
|
||||
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||
CertificateName string `json:"certificateName,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ type DeployerConfig struct {
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
// 证书 ID。
|
||||
// 选填。
|
||||
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 上传证书
|
||||
// REF: https://api.cachefly.com/api/2.5/docs#tag/Certificates/paths/~1certificates/post
|
||||
createCertificateReq := &cfsdk.CreateCertificateRequest{
|
||||
Certificate: certPEM,
|
||||
CertificateKey: privkeyPEM,
|
||||
|
@ -56,10 +56,10 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 提取 Edgio 所需的服务端证书和中间证书内容
|
||||
// 提取服务器证书和中间证书
|
||||
serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to extract certs: %w", err)
|
||||
}
|
||||
|
||||
// 上传 TLS 证书
|
||||
|
@ -24,7 +24,7 @@ type DeployerConfig struct {
|
||||
// CDN 资源 ID。
|
||||
ResourceId int64 `json:"resourceId"`
|
||||
// 证书 ID。
|
||||
// 选填。
|
||||
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||
CertificateId int64 `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ type DeployerConfig struct {
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
// 证书 ID。
|
||||
// 选填。
|
||||
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
// Webhook ID。
|
||||
// 选填。
|
||||
|
@ -65,9 +65,11 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 生成 AWS 业务参数
|
||||
scertPEM, _ := certutil.ConvertCertificateToPEM(certX509)
|
||||
bcertPEM := certPEM
|
||||
// 提取服务器证书
|
||||
serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract certs: %w", err)
|
||||
}
|
||||
|
||||
// 获取证书列表,避免重复上传
|
||||
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ListCertificates.html
|
||||
@ -145,8 +147,8 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE
|
||||
// 导入证书
|
||||
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ImportCertificate.html
|
||||
importCertificateReq := &awsacm.ImportCertificateInput{
|
||||
Certificate: ([]byte)(scertPEM),
|
||||
CertificateChain: ([]byte)(bcertPEM),
|
||||
Certificate: ([]byte)(serverCertPEM),
|
||||
CertificateChain: ([]byte)(intermediaCertPEM),
|
||||
PrivateKey: ([]byte)(privkeyPEM),
|
||||
}
|
||||
importCertificateResp, err := u.sdkClient.ImportCertificate(context.TODO(), importCertificateReq)
|
||||
|
@ -5,6 +5,7 @@ import { z } from "zod";
|
||||
|
||||
type DeployNodeConfigFormAWSACMConfigFieldValues = Nullish<{
|
||||
region: string;
|
||||
certificateArn?: string;
|
||||
}>;
|
||||
|
||||
export type DeployNodeConfigFormAWSACMConfigProps = {
|
||||
@ -27,6 +28,7 @@ const DeployNodeConfigFormAWSACMConfig = ({ form: formInst, formName, disabled,
|
||||
.string({ message: t("workflow_node.deploy.form.aws_acm_region.placeholder") })
|
||||
.nonempty(t("workflow_node.deploy.form.aws_acm_region.placeholder"))
|
||||
.trim(),
|
||||
certificateArn: z.string({ message: t("workflow_node.deploy.form.aws_acm_certificate_arn.placeholder") }).nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
@ -51,6 +53,15 @@ const DeployNodeConfigFormAWSACMConfig = ({ form: formInst, formName, disabled,
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aws_acm_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="certificateArn"
|
||||
label={t("workflow_node.deploy.form.aws_acm_certificate_arn.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aws_acm_certificate_arn.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.aws_acm_certificate_arn.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
@ -37,7 +37,7 @@ const DeployNodeConfigFormAzureKeyVaultConfig = ({
|
||||
certificateName: z
|
||||
.string({ message: t("workflow_node.deploy.form.azure_keyvault_certificate_name.placeholder") })
|
||||
.nullish()
|
||||
.refine((v) =>{
|
||||
.refine((v) => {
|
||||
if (!v) return true;
|
||||
return /^[a-zA-Z0-9-]{1,127}$/.test(v);
|
||||
}, t("workflow_node.deploy.form.azure_keyvault_certificate_name.errmsg.invalid")),
|
||||
|
@ -261,6 +261,9 @@
|
||||
"workflow_node.deploy.form.aws_acm_region.label": "AWS ACM Region",
|
||||
"workflow_node.deploy.form.aws_acm_region.placeholder": "Please enter AWS ACM region (e.g. us-east-1)",
|
||||
"workflow_node.deploy.form.aws_acm_region.tooltip": "For more information, see <a href=\"https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints\" target=\"_blank\">https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints</a>",
|
||||
"workflow_node.deploy.form.aws_acm_certificate_arn.label": "AWS ACM certificate ARN (Optional)",
|
||||
"workflow_node.deploy.form.aws_acm_certificate_arn.placeholder": "Please enter AWS ACM certificate ARN",
|
||||
"workflow_node.deploy.form.aws_acm_certificate_arn.tooltip": "Leave it blank to import a new certificate.",
|
||||
"workflow_node.deploy.form.aws_cloudfront_region.label": "AWS CloudFront Region",
|
||||
"workflow_node.deploy.form.aws_cloudfront_region.placeholder": "Please enter AWS CloudFront region (e.g. us-east-1)",
|
||||
"workflow_node.deploy.form.aws_cloudfront_region.tooltip": "For more information, see <a href=\"https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints\" target=\"_blank\">https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints</a>",
|
||||
|
@ -260,6 +260,9 @@
|
||||
"workflow_node.deploy.form.aws_acm_region.label": "AWS ACM 服务区域",
|
||||
"workflow_node.deploy.form.aws_acm_region.placeholder": "请输入 AWS ACM 服务区域(例如:us-east-1)",
|
||||
"workflow_node.deploy.form.aws_acm_region.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints</a>",
|
||||
"workflow_node.deploy.form.aws_acm_certificate_arn.label": "AWS ACM 证书 ARN(可选)",
|
||||
"workflow_node.deploy.form.aws_acm_certificate_arn.placeholder": "请输入 AWS ACM 证书 ARN",
|
||||
"workflow_node.deploy.form.aws_acm_certificate_arn.tooltip": "不填写时,将导入为新证书。",
|
||||
"workflow_node.deploy.form.aws_cloudfront_region.label": "AWS CloudFront 服务区域",
|
||||
"workflow_node.deploy.form.aws_cloudfront_region.placeholder": "请输入 AWS CloudFront 服务区域(例如:us-east-1)",
|
||||
"workflow_node.deploy.form.aws_cloudfront_region.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints</a>",
|
||||
|
Loading…
x
Reference in New Issue
Block a user