diff --git a/go.mod b/go.mod
index 0f12bd45..bca64be5 100644
--- a/go.mod
+++ b/go.mod
@@ -85,6 +85,7 @@ require (
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
github.com/avast/retry-go v3.0.0+incompatible // indirect
+ github.com/aws/aws-sdk-go-v2/service/iam v1.42.0 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 // indirect
github.com/buger/goterm v1.0.4 // indirect
github.com/diskfs/go-diskfs v1.5.0 // indirect
diff --git a/go.sum b/go.sum
index 7bbf5848..404e21e4 100644
--- a/go.sum
+++ b/go.sum
@@ -235,6 +235,8 @@ github.com/aws/aws-sdk-go-v2/service/acm v1.32.0/go.mod h1:3sKYAgRbuBa2QMYGh/WEc
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1 h1:6xZNYtuVwzBs8k+TmraERt0vL68Ppg9aUi+aTQmPaVM=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1/go.mod h1:FIBJ48TS+qJb+Ne4qJ+0NeIhtPTVXItXooTeNeVI4Po=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
+github.com/aws/aws-sdk-go-v2/service/iam v1.42.0 h1:G6+UzGvubaet9QOh0664E9JeT+b6Zvop3AChozRqkrA=
+github.com/aws/aws-sdk-go-v2/service/iam v1.42.0/go.mod h1:mPJkGQzeCoPs82ElNILor2JzZgYENr4UaSKUT8K27+c=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go
index e67c29e0..6f02c97a 100644
--- a/internal/deployer/providers.go
+++ b/internal/deployer/providers.go
@@ -27,6 +27,7 @@ import (
pAliyunWAF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-waf"
pAWSACM "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-acm"
pAWSCloudFront "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-cloudfront"
+ pAWSIAM "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-iam"
pAzureKeyVault "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/azure-keyvault"
pBaiduCloudAppBLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baiducloud-appblb"
pBaiduCloudBLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baiducloud-blb"
@@ -331,7 +332,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
}
}
- case domain.DeploymentProviderTypeAWSACM, domain.DeploymentProviderTypeAWSCloudFront:
+ case domain.DeploymentProviderTypeAWSACM, domain.DeploymentProviderTypeAWSCloudFront, domain.DeploymentProviderTypeAWSIAM:
{
access := domain.AccessConfigForAWS{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@@ -350,10 +351,20 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
case domain.DeploymentProviderTypeAWSCloudFront:
deployer, err := pAWSCloudFront.NewDeployer(&pAWSCloudFront.DeployerConfig{
+ AccessKeyId: access.AccessKeyId,
+ SecretAccessKey: access.SecretAccessKey,
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ DistributionId: maputil.GetString(options.ProviderServiceConfig, "distributionId"),
+ CertificateSource: maputil.GetOrDefaultString(options.ProviderServiceConfig, "certificateSource", "ACM"),
+ })
+ return deployer, err
+
+ case domain.DeploymentProviderTypeAWSIAM:
+ deployer, err := pAWSIAM.NewDeployer(&pAWSIAM.DeployerConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
- DistributionId: maputil.GetString(options.ProviderServiceConfig, "distributionId"),
+ CertificatePath: maputil.GetOrDefaultString(options.ProviderServiceConfig, "certificatePath", "/"),
})
return deployer, err
diff --git a/internal/domain/provider.go b/internal/domain/provider.go
index 1a30bdad..560b08da 100644
--- a/internal/domain/provider.go
+++ b/internal/domain/provider.go
@@ -195,6 +195,7 @@ const (
DeploymentProviderTypeAliyunWAF = DeploymentProviderType(AccessProviderTypeAliyun + "-waf")
DeploymentProviderTypeAWSACM = DeploymentProviderType(AccessProviderTypeAWS + "-acm")
DeploymentProviderTypeAWSCloudFront = DeploymentProviderType(AccessProviderTypeAWS + "-cloudfront")
+ DeploymentProviderTypeAWSIAM = DeploymentProviderType(AccessProviderTypeAWS + "-iam")
DeploymentProviderTypeAzureKeyVault = DeploymentProviderType(AccessProviderTypeAzure + "-keyvault")
DeploymentProviderTypeBaiduCloudAppBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-appblb")
DeploymentProviderTypeBaiduCloudBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-blb")
diff --git a/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go b/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go
index 7ec17044..e5a3f0b2 100644
--- a/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go
+++ b/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go
@@ -14,7 +14,8 @@ import (
"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"
+ uploaderspacm "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
+ uploaderspiam "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-iam"
)
type DeployerConfig struct {
@@ -26,6 +27,9 @@ type DeployerConfig struct {
Region string `json:"region"`
// AWS CloudFront 分配 ID。
DistributionId string `json:"distributionId"`
+ // AWS CloudFront 证书来源。
+ // 可取值 "ACM"、"IAM"。
+ CertificateSource string `json:"certificateSource"`
}
type DeployerProvider struct {
@@ -47,13 +51,28 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
return nil, fmt.Errorf("failed to create sdk client: %w", err)
}
- uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
- AccessKeyId: config.AccessKeyId,
- SecretAccessKey: config.SecretAccessKey,
- Region: config.Region,
- })
- if err != nil {
- return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
+ var uploader uploader.Uploader
+ if config.CertificateSource == "ACM" {
+ uploader, err = uploaderspacm.NewUploader(&uploaderspacm.UploaderConfig{
+ AccessKeyId: config.AccessKeyId,
+ SecretAccessKey: config.SecretAccessKey,
+ Region: config.Region,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
+ }
+ } else if config.CertificateSource == "IAM" {
+ uploader, err = uploaderspiam.NewUploader(&uploaderspiam.UploaderConfig{
+ AccessKeyId: config.AccessKeyId,
+ SecretAccessKey: config.SecretAccessKey,
+ Region: config.Region,
+ CertificatePath: "/cloudfront/",
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
+ }
+ } else {
+ return nil, fmt.Errorf("unsupported certificate source: '%s'", config.CertificateSource)
}
return &DeployerProvider{
@@ -79,7 +98,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
return nil, errors.New("config `distribuitionId` is required")
}
- // 上传证书到 ACM
+ // 上传证书到 ACM/IAM
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
if err != nil {
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
@@ -109,7 +128,19 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
updateDistributionReq.DistributionConfig.ViewerCertificate = &types.ViewerCertificate{}
}
updateDistributionReq.DistributionConfig.ViewerCertificate.CloudFrontDefaultCertificate = aws.Bool(false)
- updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = aws.String(upres.CertId)
+ if d.config.CertificateSource == "ACM" {
+ updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = aws.String(upres.CertId)
+ updateDistributionReq.DistributionConfig.ViewerCertificate.IAMCertificateId = nil
+ } else if d.config.CertificateSource == "IAM" {
+ updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = nil
+ updateDistributionReq.DistributionConfig.ViewerCertificate.IAMCertificateId = aws.String(upres.CertId)
+ if updateDistributionReq.DistributionConfig.ViewerCertificate.MinimumProtocolVersion == "" {
+ updateDistributionReq.DistributionConfig.ViewerCertificate.MinimumProtocolVersion = types.MinimumProtocolVersionTLSv1
+ }
+ if updateDistributionReq.DistributionConfig.ViewerCertificate.SSLSupportMethod == "" {
+ updateDistributionReq.DistributionConfig.ViewerCertificate.SSLSupportMethod = types.SSLSupportMethodSniOnly
+ }
+ }
updateDistributionResp, err := d.sdkClient.UpdateDistribution(context.TODO(), updateDistributionReq)
d.logger.Debug("sdk request 'cloudfront.UpdateDistribution'", slog.Any("request", updateDistributionReq), slog.Any("response", updateDistributionResp))
if err != nil {
diff --git a/internal/pkg/core/deployer/providers/aws-iam/aws_iam.go b/internal/pkg/core/deployer/providers/aws-iam/aws_iam.go
new file mode 100644
index 00000000..ef6440d3
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/aws-iam/aws_iam.go
@@ -0,0 +1,75 @@
+package awsiam
+
+import (
+ "context"
+ "fmt"
+ "log/slog"
+
+ "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-iam"
+)
+
+type DeployerConfig struct {
+ // AWS AccessKeyId。
+ AccessKeyId string `json:"accessKeyId"`
+ // AWS SecretAccessKey。
+ SecretAccessKey string `json:"secretAccessKey"`
+ // AWS 区域。
+ Region string `json:"region"`
+ // IAM 证书路径。
+ // 选填。
+ CertificatePath string `json:"certificatePath,omitempty"`
+}
+
+type DeployerProvider struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ sslUploader uploader.Uploader
+}
+
+var _ deployer.Deployer = (*DeployerProvider)(nil)
+
+func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
+ AccessKeyId: config.AccessKeyId,
+ SecretAccessKey: config.SecretAccessKey,
+ Region: config.Region,
+ CertificatePath: config.CertificatePath,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
+ }
+
+ return &DeployerProvider{
+ config: config,
+ logger: slog.Default(),
+ sslUploader: uploader,
+ }, nil
+}
+
+func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
+ if logger == nil {
+ d.logger = slog.New(slog.DiscardHandler)
+ } else {
+ d.logger = logger
+ }
+ d.sslUploader.WithLogger(logger)
+ return d
+}
+
+func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
+ // 上传证书到 IAM
+ upres, err := d.sslUploader.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))
+ }
+
+ return &deployer.DeployResult{}, nil
+}
diff --git a/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go b/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go
index f68ebadc..4f215266 100644
--- a/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go
+++ b/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go
@@ -74,7 +74,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE
// 获取证书列表,避免重复上传
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ListCertificates.html
var listCertificatesNextToken *string = nil
- listCertificatesMaxItems := int32(1000)
+ var listCertificatesMaxItems int32 = 1000
for {
select {
case <-ctx.Done():
@@ -107,7 +107,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE
}
// 最后对比证书内容
- // REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ListTagsForCertificate.html
+ // REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_GetCertificate.html
getCertificateReq := &awsacm.GetCertificateInput{
CertificateArn: certSummary.CertificateArn,
}
@@ -115,11 +115,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'acm.GetCertificate': %w", err)
} else {
- oldCertPEM := aws.ToString(getCertificateResp.CertificateChain)
- if oldCertPEM == "" {
- oldCertPEM = aws.ToString(getCertificateResp.Certificate)
- }
-
+ oldCertPEM := aws.ToString(getCertificateResp.Certificate)
oldCertX509, err := certutil.ParseCertificateFromPEM(oldCertPEM)
if err != nil {
continue
@@ -158,7 +154,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE
}
return &uploader.UploadResult{
- CertId: *importCertificateResp.CertificateArn,
+ CertId: aws.ToString(importCertificateResp.CertificateArn),
}, nil
}
diff --git a/internal/pkg/core/uploader/providers/aws-iam/aws_iam.go b/internal/pkg/core/uploader/providers/aws-iam/aws_iam.go
new file mode 100644
index 00000000..10f1a174
--- /dev/null
+++ b/internal/pkg/core/uploader/providers/aws-iam/aws_iam.go
@@ -0,0 +1,185 @@
+package awsiam
+
+import (
+ "context"
+ "fmt"
+ "log/slog"
+ "time"
+
+ 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"
+ awsiam "github.com/aws/aws-sdk-go-v2/service/iam"
+
+ "github.com/usual2970/certimate/internal/pkg/core/uploader"
+ certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
+)
+
+type UploaderConfig struct {
+ // AWS AccessKeyId。
+ AccessKeyId string `json:"accessKeyId"`
+ // AWS SecretAccessKey。
+ SecretAccessKey string `json:"secretAccessKey"`
+ // AWS 区域。
+ Region string `json:"region"`
+ // IAM 证书路径。
+ // 选填。
+ CertificatePath string `json:"certificatePath,omitempty"`
+}
+
+type UploaderProvider struct {
+ config *UploaderConfig
+ logger *slog.Logger
+ sdkClient *awsiam.Client
+}
+
+var _ uploader.Uploader = (*UploaderProvider)(nil)
+
+func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
+ if config == nil {
+ 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)
+ }
+
+ return &UploaderProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ }, nil
+}
+
+func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader {
+ if logger == nil {
+ u.logger = slog.New(slog.DiscardHandler)
+ } else {
+ u.logger = logger
+ }
+ return u
+}
+
+func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (*uploader.UploadResult, error) {
+ // 解析证书内容
+ certX509, err := certutil.ParseCertificateFromPEM(certPEM)
+ if err != nil {
+ return nil, err
+ }
+
+ // 提取服务器证书
+ 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/IAM/latest/APIReference/API_ListServerCertificates.html
+ var listServerCertificatesMarker *string = nil
+ var listServerCertificatesMaxItems int32 = 1000
+ for {
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ default:
+ }
+
+ listServerCertificatesReq := &awsiam.ListServerCertificatesInput{
+ Marker: listServerCertificatesMarker,
+ MaxItems: aws.Int32(listServerCertificatesMaxItems),
+ }
+ if u.config.CertificatePath != "" {
+ listServerCertificatesReq.PathPrefix = aws.String(u.config.CertificatePath)
+ }
+ listServerCertificatesResp, err := u.sdkClient.ListServerCertificates(context.TODO(), listServerCertificatesReq)
+ u.logger.Debug("sdk request 'iam.ListServerCertificates'", slog.Any("request", listServerCertificatesReq), slog.Any("response", listServerCertificatesResp))
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'iam.ListServerCertificates': %w", err)
+ }
+
+ for _, certMeta := range listServerCertificatesResp.ServerCertificateMetadataList {
+ // 先对比证书路径
+ if u.config.CertificatePath != "" && aws.ToString(certMeta.Path) != u.config.CertificatePath {
+ continue
+ }
+
+ // 先对比证书有效期
+ if certMeta.Expiration == nil || !certMeta.Expiration.Equal(certX509.NotAfter) {
+ continue
+ }
+
+ // 最后对比证书内容
+ // REF: https://docs.aws.amazon.com/en_us/IAM/latest/APIReference/API_GetServerCertificate.html
+ getServerCertificateReq := &awsiam.GetServerCertificateInput{
+ ServerCertificateName: certMeta.ServerCertificateName,
+ }
+ getServerCertificateResp, err := u.sdkClient.GetServerCertificate(context.TODO(), getServerCertificateReq)
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'iam.GetServerCertificate': %w", err)
+ } else {
+ oldCertPEM := aws.ToString(getServerCertificateResp.ServerCertificate.CertificateBody)
+ oldCertX509, err := certutil.ParseCertificateFromPEM(oldCertPEM)
+ if err != nil {
+ continue
+ }
+
+ if !certutil.EqualCertificate(certX509, oldCertX509) {
+ continue
+ }
+ }
+
+ // 如果以上信息都一致,则视为已存在相同证书,直接返回
+ u.logger.Info("ssl certificate already exists")
+ return &uploader.UploadResult{
+ CertId: aws.ToString(certMeta.ServerCertificateId),
+ CertName: aws.ToString(certMeta.ServerCertificateName),
+ }, nil
+ }
+
+ if listServerCertificatesResp.Marker == nil || len(listServerCertificatesResp.ServerCertificateMetadataList) < int(listServerCertificatesMaxItems) {
+ break
+ } else {
+ listServerCertificatesMarker = listServerCertificatesResp.Marker
+ }
+ }
+
+ // 生成新证书名(需符合 AWS IAM 命名规则)
+ certName := fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
+
+ // 导入证书
+ // REF: https://docs.aws.amazon.com/en_us/IAM/latest/APIReference/API_UploadServerCertificate.html
+ uploadServerCertificateReq := &awsiam.UploadServerCertificateInput{
+ ServerCertificateName: aws.String(certName),
+ Path: aws.String(u.config.CertificatePath),
+ CertificateBody: aws.String(serverCertPEM),
+ CertificateChain: aws.String(intermediaCertPEM),
+ PrivateKey: aws.String(privkeyPEM),
+ }
+ if u.config.CertificatePath == "" {
+ uploadServerCertificateReq.Path = aws.String("/")
+ }
+ uploadServerCertificateResp, err := u.sdkClient.UploadServerCertificate(context.TODO(), uploadServerCertificateReq)
+ u.logger.Debug("sdk request 'iam.UploadServerCertificate'", slog.Any("request", uploadServerCertificateReq), slog.Any("response", uploadServerCertificateResp))
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'iam.UploadServerCertificate': %w", err)
+ }
+
+ return &uploader.UploadResult{
+ CertId: aws.ToString(uploadServerCertificateResp.ServerCertificateMetadata.ServerCertificateId),
+ CertName: certName,
+ }, nil
+}
+
+func createSdkClient(accessKeyId, secretAccessKey, region string) (*awsiam.Client, error) {
+ cfg, err := awscfg.LoadDefaultConfig(context.TODO())
+ if err != nil {
+ return nil, err
+ }
+
+ client := awsiam.NewFromConfig(cfg, func(o *awsiam.Options) {
+ o.Region = region
+ o.Credentials = aws.NewCredentialsCache(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, ""))
+ })
+ return client, nil
+}
diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx
index 33fefcf0..c0083298 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx
@@ -35,6 +35,7 @@ import DeployNodeConfigFormAliyunVODConfig from "./DeployNodeConfigFormAliyunVOD
import DeployNodeConfigFormAliyunWAFConfig from "./DeployNodeConfigFormAliyunWAFConfig";
import DeployNodeConfigFormAWSACMConfig from "./DeployNodeConfigFormAWSACMConfig";
import DeployNodeConfigFormAWSCloudFrontConfig from "./DeployNodeConfigFormAWSCloudFrontConfig";
+import DeployNodeConfigFormAWSIAMConfig from "./DeployNodeConfigFormAWSIAMConfig";
import DeployNodeConfigFormAzureKeyVaultConfig from "./DeployNodeConfigFormAzureKeyVaultConfig";
import DeployNodeConfigFormBaiduCloudAppBLBConfig from "./DeployNodeConfigFormBaiduCloudAppBLBConfig";
import DeployNodeConfigFormBaiduCloudBLBConfig from "./DeployNodeConfigFormBaiduCloudBLBConfig";
@@ -238,6 +239,8 @@ const DeployNodeConfigForm = forwardRef