From 4e7b1a0758670d547bcc6eef11002ff159ccf710 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 30 Jul 2026 16:29:03 +0800 Subject: [PATCH] feat: add support for aws imds credentials --- .../certacme/certifiers/sp_aws_lightsail.go | 1 + .../certacme/certifiers/sp_aws_route53.go | 1 + internal/certmgmt/deployers/sp_aws_acm.go | 1 + internal/certmgmt/deployers/sp_aws_alb.go | 1 + internal/certmgmt/deployers/sp_aws_amplify.go | 1 + .../certmgmt/deployers/sp_aws_apigateway.go | 1 + internal/certmgmt/deployers/sp_aws_clb.go | 1 + .../certmgmt/deployers/sp_aws_cloudfront.go | 1 + internal/certmgmt/deployers/sp_aws_iam.go | 1 + internal/certmgmt/deployers/sp_aws_nlb.go | 1 + internal/domain/access.go | 1 + migrations/1785384000_upgrade_v0.4.29.go | 63 ++++++++++++ .../dns01/aws-lightsail/aws_lightsail.go | 19 +++- .../challengers/dns01/aws-lightsail/consts.go | 10 ++ .../dns01/aws-lightsail/internal/lego.go | 20 ++-- .../dns01/aws-route53/aws_route53.go | 1 + .../challengers/dns01/aws-route53/consts.go | 6 ++ .../dns01/oraclecloud/oraclecloud.go | 2 +- pkg/core/certmgr/providers/aws-acm/aws_acm.go | 31 +++++- pkg/core/certmgr/providers/aws-acm/consts.go | 10 ++ pkg/core/certmgr/providers/aws-iam/aws_iam.go | 31 +++++- pkg/core/certmgr/providers/aws-iam/consts.go | 6 ++ .../deployer/providers/aws-acm/aws_acm.go | 5 + pkg/core/deployer/providers/aws-acm/consts.go | 10 ++ .../deployer/providers/aws-alb/aws_alb.go | 33 ++++++- pkg/core/deployer/providers/aws-alb/consts.go | 9 ++ .../providers/aws-amplify/aws_amplify.go | 32 +++++- .../deployer/providers/aws-amplify/consts.go | 9 ++ .../aws-apigateway/aws_apigateway.go | 32 +++++- .../providers/aws-apigateway/consts.go | 9 ++ .../deployer/providers/aws-clb/aws_clb.go | 33 ++++++- pkg/core/deployer/providers/aws-clb/consts.go | 9 ++ .../aws-cloudfront/aws_cloudfront.go | 33 ++++++- .../providers/aws-cloudfront/consts.go | 9 ++ .../deployer/providers/aws-iam/aws_iam.go | 5 + pkg/core/deployer/providers/aws-iam/consts.go | 10 ++ .../deployer/providers/aws-nlb/aws_nlb.go | 33 ++++++- pkg/core/deployer/providers/aws-nlb/consts.go | 9 ++ .../providers/nginxproxymanager/consts.go | 8 +- .../nginxproxymanager/nginxproxymanager.go | 6 +- .../forms/AccessConfigFieldsProviderAWS.tsx | 97 +++++++++++++++---- ui/src/i18n/resources/en/nls.access.json | 13 +++ ui/src/i18n/resources/zh/nls.access.json | 13 +++ .../i18n/resources/zh/nls.workflow.nodes.json | 2 +- 44 files changed, 551 insertions(+), 78 deletions(-) create mode 100644 migrations/1785384000_upgrade_v0.4.29.go create mode 100644 pkg/core/certifier/challengers/dns01/aws-lightsail/consts.go create mode 100644 pkg/core/certifier/challengers/dns01/aws-route53/consts.go create mode 100644 pkg/core/certmgr/providers/aws-acm/consts.go create mode 100644 pkg/core/certmgr/providers/aws-iam/consts.go create mode 100644 pkg/core/deployer/providers/aws-acm/consts.go create mode 100644 pkg/core/deployer/providers/aws-iam/consts.go diff --git a/internal/certacme/certifiers/sp_aws_lightsail.go b/internal/certacme/certifiers/sp_aws_lightsail.go index f200d829e..6de0ea33e 100644 --- a/internal/certacme/certifiers/sp_aws_lightsail.go +++ b/internal/certacme/certifiers/sp_aws_lightsail.go @@ -17,6 +17,7 @@ func init() { } provider, err := chlgimpl.NewChallenger(&chlgimpl.ChallengerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/certacme/certifiers/sp_aws_route53.go b/internal/certacme/certifiers/sp_aws_route53.go index 7ee7b6c4f..6c74c05c7 100644 --- a/internal/certacme/certifiers/sp_aws_route53.go +++ b/internal/certacme/certifiers/sp_aws_route53.go @@ -17,6 +17,7 @@ func init() { } provider, err := chlgimpl.NewChallenger(&chlgimpl.ChallengerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/certmgmt/deployers/sp_aws_acm.go b/internal/certmgmt/deployers/sp_aws_acm.go index 59f38e585..23d9c5e24 100644 --- a/internal/certmgmt/deployers/sp_aws_acm.go +++ b/internal/certmgmt/deployers/sp_aws_acm.go @@ -17,6 +17,7 @@ func init() { } provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/certmgmt/deployers/sp_aws_alb.go b/internal/certmgmt/deployers/sp_aws_alb.go index 38b016bc6..208688a30 100644 --- a/internal/certmgmt/deployers/sp_aws_alb.go +++ b/internal/certmgmt/deployers/sp_aws_alb.go @@ -17,6 +17,7 @@ func init() { } provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/certmgmt/deployers/sp_aws_amplify.go b/internal/certmgmt/deployers/sp_aws_amplify.go index 8ed35ea57..9331331d5 100644 --- a/internal/certmgmt/deployers/sp_aws_amplify.go +++ b/internal/certmgmt/deployers/sp_aws_amplify.go @@ -17,6 +17,7 @@ func init() { } provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/certmgmt/deployers/sp_aws_apigateway.go b/internal/certmgmt/deployers/sp_aws_apigateway.go index 2ef965589..d7ab82e96 100644 --- a/internal/certmgmt/deployers/sp_aws_apigateway.go +++ b/internal/certmgmt/deployers/sp_aws_apigateway.go @@ -17,6 +17,7 @@ func init() { } provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/certmgmt/deployers/sp_aws_clb.go b/internal/certmgmt/deployers/sp_aws_clb.go index 7f2a72f5a..7412afa4e 100644 --- a/internal/certmgmt/deployers/sp_aws_clb.go +++ b/internal/certmgmt/deployers/sp_aws_clb.go @@ -17,6 +17,7 @@ func init() { } provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/certmgmt/deployers/sp_aws_cloudfront.go b/internal/certmgmt/deployers/sp_aws_cloudfront.go index f94ce20ac..ae9c5404e 100644 --- a/internal/certmgmt/deployers/sp_aws_cloudfront.go +++ b/internal/certmgmt/deployers/sp_aws_cloudfront.go @@ -17,6 +17,7 @@ func init() { } provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/certmgmt/deployers/sp_aws_iam.go b/internal/certmgmt/deployers/sp_aws_iam.go index dbe824c30..240dfbdb3 100644 --- a/internal/certmgmt/deployers/sp_aws_iam.go +++ b/internal/certmgmt/deployers/sp_aws_iam.go @@ -17,6 +17,7 @@ func init() { } provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/certmgmt/deployers/sp_aws_nlb.go b/internal/certmgmt/deployers/sp_aws_nlb.go index 3eed44e4d..5e13a618f 100644 --- a/internal/certmgmt/deployers/sp_aws_nlb.go +++ b/internal/certmgmt/deployers/sp_aws_nlb.go @@ -17,6 +17,7 @@ func init() { } provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{ + AuthMethod: credentials.AuthMethod, AccessKeyId: credentials.AccessKeyId, SecretAccessKey: credentials.SecretAccessKey, Region: xmaps.GetString(options.ProviderExtendedConfig, "region"), diff --git a/internal/domain/access.go b/internal/domain/access.go index 13a130e58..a7fb37b22 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -82,6 +82,7 @@ type AccessConfigForArvanCloud struct { } type AccessConfigForAWS struct { + AuthMethod string `json:"authMethod"` AccessKeyId string `json:"accessKeyId"` SecretAccessKey string `json:"secretAccessKey"` } diff --git a/migrations/1785384000_upgrade_v0.4.29.go b/migrations/1785384000_upgrade_v0.4.29.go new file mode 100644 index 000000000..f406c6525 --- /dev/null +++ b/migrations/1785384000_upgrade_v0.4.29.go @@ -0,0 +1,63 @@ +package migrations + +import ( + "errors" + + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +func init() { + m.Register(func(app core.App) error { + tracer := NewTracer("v0.4.29") + tracer.Printf("go ...") + + // update collection `access` + // - modify field `config` schema + { + collection, err := app.FindCollectionByNameOrId("4yzbv8urny5ja1e") + if err != nil { + return err + } + + records, err := app.FindAllRecords(collection) + if err != nil { + return err + } + + for _, record := range records { + changed := false + + provider := record.GetString("provider") + config := make(map[string]any) + if err := record.UnmarshalJSONField("config", &config); err != nil { + return err + } + + switch provider { + case "aws": + { + if _, ok := config["authMethod"]; !ok { + config["authMethod"] = "accesskey" + record.Set("config", config) + changed = true + } + } + } + + if changed { + if err := app.Save(record); err != nil { + return err + } + + tracer.Printf("record #%s in collection '%s' updated", record.Id, collection.Name) + } + } + } + + tracer.Printf("done") + return nil + }, func(app core.App) error { + return errors.ErrUnsupported + }) +} diff --git a/pkg/core/certifier/challengers/dns01/aws-lightsail/aws_lightsail.go b/pkg/core/certifier/challengers/dns01/aws-lightsail/aws_lightsail.go index c7fe406c9..bcf3d2fa2 100644 --- a/pkg/core/certifier/challengers/dns01/aws-lightsail/aws_lightsail.go +++ b/pkg/core/certifier/challengers/dns01/aws-lightsail/aws_lightsail.go @@ -4,11 +4,16 @@ import ( "fmt" "time" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds" + "github.com/certimate-go/certimate/pkg/core" "github.com/certimate-go/certimate/pkg/core/certifier/challengers/dns01/aws-lightsail/internal" ) type ChallengerConfig struct { + AuthMethod string `json:"authMethod"` AccessKeyId string `json:"accessKeyId"` SecretAccessKey string `json:"secretAccessKey"` Region string `json:"region"` @@ -22,8 +27,18 @@ func NewChallenger(config *ChallengerConfig) (core.ACMEChallenger, error) { } providerConfig := internal.NewDefaultConfig() - providerConfig.AccessKeyID = config.AccessKeyId - providerConfig.SecretAccessKey = config.SecretAccessKey + switch config.AuthMethod { + case "": + if config.AccessKeyId != "" && config.SecretAccessKey != "" { + providerConfig.AWSCredentialsProvider = credentials.NewStaticCredentialsProvider(config.AccessKeyId, config.SecretAccessKey, "") + } + case AUTH_METHOD_ACCESSKEY: + providerConfig.AWSCredentialsProvider = credentials.NewStaticCredentialsProvider(config.AccessKeyId, config.SecretAccessKey, "") + case AUTH_METHOD_IMDS: + providerConfig.AWSCredentialsProvider = aws.NewCredentialsCache(ec2rolecreds.New()) + default: + return nil, fmt.Errorf("unsupported auth method '%s'", config.AuthMethod) + } providerConfig.Region = config.Region if config.DnsPropagationTimeout != 0 { providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second diff --git a/pkg/core/certifier/challengers/dns01/aws-lightsail/consts.go b/pkg/core/certifier/challengers/dns01/aws-lightsail/consts.go new file mode 100644 index 000000000..cb8e35c9a --- /dev/null +++ b/pkg/core/certifier/challengers/dns01/aws-lightsail/consts.go @@ -0,0 +1,10 @@ +package awslightsail + +import ( + route53 "github.com/certimate-go/certimate/pkg/core/certifier/challengers/dns01/aws-route53" +) + +const ( + AUTH_METHOD_ACCESSKEY = route53.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = route53.AUTH_METHOD_IMDS +) diff --git a/pkg/core/certifier/challengers/dns01/aws-lightsail/internal/lego.go b/pkg/core/certifier/challengers/dns01/aws-lightsail/internal/lego.go index 9f36596b9..cf558189e 100644 --- a/pkg/core/certifier/challengers/dns01/aws-lightsail/internal/lego.go +++ b/pkg/core/certifier/challengers/dns01/aws-lightsail/internal/lego.go @@ -8,7 +8,6 @@ import ( 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" "github.com/aws/aws-sdk-go-v2/service/lightsail" "github.com/aws/aws-sdk-go-v2/service/lightsail/types" "github.com/go-acme/lego/v5/challenge" @@ -25,15 +24,11 @@ const ( EnvPollingInterval = envNamespace + "POLLING_INTERVAL" ) -const maxRetries = 5 - var _ challenge.ProviderTimeout = (*DNSProvider)(nil) type Config struct { - AccessKeyID string - SecretAccessKey string - SessionToken string - Region string + AWSCredentialsProvider aws.CredentialsProvider + Region string PropagationTimeout time.Duration PollingInterval time.Duration @@ -65,11 +60,14 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { return nil, fmt.Errorf("lightsail: the configuration of the DNS provider is nil") } - ctx := context.Background() - cfg, err := awscfg.LoadDefaultConfig(ctx, - awscfg.WithCredentialsProvider(awscred.NewStaticCredentialsProvider(config.AccessKeyID, config.SecretAccessKey, config.SessionToken)), + opts := []func(options *awscfg.LoadOptions) error{ awscfg.WithRegion(config.Region), - ) + } + if config.AWSCredentialsProvider != nil { + opts = append(opts, awscfg.WithCredentialsProvider(config.AWSCredentialsProvider)) + } + + cfg, err := awscfg.LoadDefaultConfig(context.Background(), opts...) if err != nil { return nil, err } diff --git a/pkg/core/certifier/challengers/dns01/aws-route53/aws_route53.go b/pkg/core/certifier/challengers/dns01/aws-route53/aws_route53.go index 8a2bcfd8a..84af1bbfd 100644 --- a/pkg/core/certifier/challengers/dns01/aws-route53/aws_route53.go +++ b/pkg/core/certifier/challengers/dns01/aws-route53/aws_route53.go @@ -10,6 +10,7 @@ import ( ) type ChallengerConfig struct { + AuthMethod string `json:"authMethod"` // not used for now AccessKeyId string `json:"accessKeyId"` SecretAccessKey string `json:"secretAccessKey"` Region string `json:"region"` diff --git a/pkg/core/certifier/challengers/dns01/aws-route53/consts.go b/pkg/core/certifier/challengers/dns01/aws-route53/consts.go new file mode 100644 index 000000000..70ae522bb --- /dev/null +++ b/pkg/core/certifier/challengers/dns01/aws-route53/consts.go @@ -0,0 +1,6 @@ +package awsroute53 + +const ( + AUTH_METHOD_ACCESSKEY = "accesskey" + AUTH_METHOD_IMDS = "imds" +) diff --git a/pkg/core/certifier/challengers/dns01/oraclecloud/oraclecloud.go b/pkg/core/certifier/challengers/dns01/oraclecloud/oraclecloud.go index e4ce9805d..a0affb283 100644 --- a/pkg/core/certifier/challengers/dns01/oraclecloud/oraclecloud.go +++ b/pkg/core/certifier/challengers/dns01/oraclecloud/oraclecloud.go @@ -32,7 +32,7 @@ func NewChallenger(config *ChallengerConfig) (core.ACMEChallenger, error) { providerConfig := oraclecloud.NewDefaultConfig() providerConfig.CompartmentID = config.CompartmentOcid switch config.AuthMethod { - case AUTH_METHOD_APIKEY: + case "", AUTH_METHOD_APIKEY: pkpwd := (*string)(nil) if config.PrivateKeyPassphrase != "" { pkpwd = &config.PrivateKeyPassphrase diff --git a/pkg/core/certmgr/providers/aws-acm/aws_acm.go b/pkg/core/certmgr/providers/aws-acm/aws_acm.go index da6084b1a..83c295d79 100644 --- a/pkg/core/certmgr/providers/aws-acm/aws_acm.go +++ b/pkg/core/certmgr/providers/aws-acm/aws_acm.go @@ -10,6 +10,7 @@ import ( 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" + "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go-v2/service/acm" "github.com/aws/smithy-go" @@ -24,6 +25,10 @@ type ( ) type CertmgrConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -45,7 +50,7 @@ func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) { return nil, fmt.Errorf("the configuration of the certmgr provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AuthMethod, config.AccessKeyId, config.SecretAccessKey, config.Region) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -194,11 +199,27 @@ func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, pri return &ReplaceResult{}, nil } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*acm.Client, error) { - cfg, err := awscfg.LoadDefaultConfig(context.Background(), - awscfg.WithCredentialsProvider(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")), +func createSDKClient(authMethod, accessKeyId, secretAccessKey, region string) (*acm.Client, error) { + opts := []func(options *awscfg.LoadOptions) error{ awscfg.WithRegion(region), - ) + } + + staticCredsProvider := awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "") + imdsCredsProvider := aws.NewCredentialsCache(ec2rolecreds.New()) + switch authMethod { + case "": + if accessKeyId != "" && secretAccessKey != "" { + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + } + case AUTH_METHOD_ACCESSKEY: + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + case AUTH_METHOD_IMDS: + opts = append(opts, awscfg.WithCredentialsProvider(imdsCredsProvider)) + default: + return nil, fmt.Errorf("unsupported auth method '%s'", authMethod) + } + + cfg, err := awscfg.LoadDefaultConfig(context.Background(), opts...) if err != nil { return nil, err } diff --git a/pkg/core/certmgr/providers/aws-acm/consts.go b/pkg/core/certmgr/providers/aws-acm/consts.go new file mode 100644 index 000000000..f9528cd2d --- /dev/null +++ b/pkg/core/certmgr/providers/aws-acm/consts.go @@ -0,0 +1,10 @@ +package awsacm + +import ( + iam "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aws-iam" +) + +const ( + AUTH_METHOD_ACCESSKEY = iam.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = iam.AUTH_METHOD_IMDS +) diff --git a/pkg/core/certmgr/providers/aws-iam/aws_iam.go b/pkg/core/certmgr/providers/aws-iam/aws_iam.go index 08a88329c..e4f99cc4c 100644 --- a/pkg/core/certmgr/providers/aws-iam/aws_iam.go +++ b/pkg/core/certmgr/providers/aws-iam/aws_iam.go @@ -11,6 +11,7 @@ import ( 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" + "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/smithy-go" "github.com/samber/lo" @@ -26,6 +27,10 @@ type ( ) type CertmgrConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -50,7 +55,7 @@ func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) { return nil, fmt.Errorf("the configuration of the certmgr provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AuthMethod, config.AccessKeyId, config.SecretAccessKey, config.Region) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -187,11 +192,27 @@ func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, pri return nil, core.ErrUnsupported } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*iam.Client, error) { - cfg, err := awscfg.LoadDefaultConfig(context.Background(), - awscfg.WithCredentialsProvider(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")), +func createSDKClient(authMethod, accessKeyId, secretAccessKey, region string) (*iam.Client, error) { + opts := []func(options *awscfg.LoadOptions) error{ awscfg.WithRegion(region), - ) + } + + staticCredsProvider := awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "") + imdsCredsProvider := aws.NewCredentialsCache(ec2rolecreds.New()) + switch authMethod { + case "": + if accessKeyId != "" && secretAccessKey != "" { + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + } + case AUTH_METHOD_ACCESSKEY: + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + case AUTH_METHOD_IMDS: + opts = append(opts, awscfg.WithCredentialsProvider(imdsCredsProvider)) + default: + return nil, fmt.Errorf("unsupported auth method '%s'", authMethod) + } + + cfg, err := awscfg.LoadDefaultConfig(context.Background(), opts...) if err != nil { return nil, err } diff --git a/pkg/core/certmgr/providers/aws-iam/consts.go b/pkg/core/certmgr/providers/aws-iam/consts.go new file mode 100644 index 000000000..e34125139 --- /dev/null +++ b/pkg/core/certmgr/providers/aws-iam/consts.go @@ -0,0 +1,6 @@ +package awsiam + +const ( + AUTH_METHOD_ACCESSKEY = "accesskey" + AUTH_METHOD_IMDS = "imds" +) diff --git a/pkg/core/deployer/providers/aws-acm/aws_acm.go b/pkg/core/deployer/providers/aws-acm/aws_acm.go index 3dc8021f7..12f340b2e 100644 --- a/pkg/core/deployer/providers/aws-acm/aws_acm.go +++ b/pkg/core/deployer/providers/aws-acm/aws_acm.go @@ -15,6 +15,10 @@ type ( ) type DeployerConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -40,6 +44,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { } pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, diff --git a/pkg/core/deployer/providers/aws-acm/consts.go b/pkg/core/deployer/providers/aws-acm/consts.go new file mode 100644 index 000000000..4cc635750 --- /dev/null +++ b/pkg/core/deployer/providers/aws-acm/consts.go @@ -0,0 +1,10 @@ +package awsacm + +import ( + cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aws-acm" +) + +const ( + AUTH_METHOD_ACCESSKEY = cmgrimpl.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = cmgrimpl.AUTH_METHOD_IMDS +) diff --git a/pkg/core/deployer/providers/aws-alb/aws_alb.go b/pkg/core/deployer/providers/aws-alb/aws_alb.go index e117c7084..15a784e79 100644 --- a/pkg/core/deployer/providers/aws-alb/aws_alb.go +++ b/pkg/core/deployer/providers/aws-alb/aws_alb.go @@ -8,6 +8,7 @@ import ( 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" + "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" @@ -22,6 +23,10 @@ type ( ) type DeployerConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -53,7 +58,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { return nil, fmt.Errorf("the configuration of the deployer provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AuthMethod, config.AccessKeyId, config.SecretAccessKey, config.Region) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -62,6 +67,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { switch config.CertificateSource { case CERTIFICATE_SOURCE_ACM: pcertmgr, err = cmgrimplacm.NewCertmgr(&cmgrimplacm.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -72,6 +78,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { case CERTIFICATE_SOURCE_IAM: pcertmgr, err = cmgrimpliam.NewCertmgr(&cmgrimpliam.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -220,11 +227,27 @@ func (d *Deployer) updateListenerSniCertificate(ctx context.Context, cloudListen return nil } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*elasticloadbalancingv2.Client, error) { - cfg, err := awscfg.LoadDefaultConfig(context.Background(), - awscfg.WithCredentialsProvider(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")), +func createSDKClient(authMethod, accessKeyId, secretAccessKey, region string) (*elasticloadbalancingv2.Client, error) { + opts := []func(options *awscfg.LoadOptions) error{ awscfg.WithRegion(region), - ) + } + + staticCredsProvider := awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "") + imdsCredsProvider := aws.NewCredentialsCache(ec2rolecreds.New()) + switch authMethod { + case "": + if accessKeyId != "" && secretAccessKey != "" { + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + } + case AUTH_METHOD_ACCESSKEY: + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + case AUTH_METHOD_IMDS: + opts = append(opts, awscfg.WithCredentialsProvider(imdsCredsProvider)) + default: + return nil, fmt.Errorf("unsupported auth method '%s'", authMethod) + } + + cfg, err := awscfg.LoadDefaultConfig(context.Background(), opts...) if err != nil { return nil, err } diff --git a/pkg/core/deployer/providers/aws-alb/consts.go b/pkg/core/deployer/providers/aws-alb/consts.go index e018c00e3..71fd35a38 100644 --- a/pkg/core/deployer/providers/aws-alb/consts.go +++ b/pkg/core/deployer/providers/aws-alb/consts.go @@ -1,5 +1,14 @@ package awsalb +import ( + cmgrimplacm "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aws-acm" +) + +const ( + AUTH_METHOD_ACCESSKEY = cmgrimplacm.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = cmgrimplacm.AUTH_METHOD_IMDS +) + const ( CERTIFICATE_SOURCE_ACM = "ACM" CERTIFICATE_SOURCE_IAM = "IAM" diff --git a/pkg/core/deployer/providers/aws-amplify/aws_amplify.go b/pkg/core/deployer/providers/aws-amplify/aws_amplify.go index 0e299792d..f2ec9459b 100644 --- a/pkg/core/deployer/providers/aws-amplify/aws_amplify.go +++ b/pkg/core/deployer/providers/aws-amplify/aws_amplify.go @@ -8,6 +8,7 @@ import ( 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" + "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go-v2/service/amplify" "github.com/aws/aws-sdk-go-v2/service/amplify/types" @@ -21,6 +22,10 @@ type ( ) type DeployerConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -50,7 +55,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { return nil, fmt.Errorf("the configuration of the deployer provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AuthMethod, config.AccessKeyId, config.SecretAccessKey, config.Region) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -59,6 +64,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { switch config.CertificateSource { case CERTIFICATE_SOURCE_ACM: pcertmgr, err = cmgrimplacm.NewCertmgr(&cmgrimplacm.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -124,11 +130,27 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep return &DeployResult{}, nil } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*amplify.Client, error) { - cfg, err := awscfg.LoadDefaultConfig(context.Background(), - awscfg.WithCredentialsProvider(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")), +func createSDKClient(authMethod, accessKeyId, secretAccessKey, region string) (*amplify.Client, error) { + opts := []func(options *awscfg.LoadOptions) error{ awscfg.WithRegion(region), - ) + } + + staticCredsProvider := awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "") + imdsCredsProvider := aws.NewCredentialsCache(ec2rolecreds.New()) + switch authMethod { + case "": + if accessKeyId != "" && secretAccessKey != "" { + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + } + case AUTH_METHOD_ACCESSKEY: + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + case AUTH_METHOD_IMDS: + opts = append(opts, awscfg.WithCredentialsProvider(imdsCredsProvider)) + default: + return nil, fmt.Errorf("unsupported auth method '%s'", authMethod) + } + + cfg, err := awscfg.LoadDefaultConfig(context.Background(), opts...) if err != nil { return nil, err } diff --git a/pkg/core/deployer/providers/aws-amplify/consts.go b/pkg/core/deployer/providers/aws-amplify/consts.go index 86879f14d..ff15255b2 100644 --- a/pkg/core/deployer/providers/aws-amplify/consts.go +++ b/pkg/core/deployer/providers/aws-amplify/consts.go @@ -1,5 +1,14 @@ package awsamplify +import ( + cmgrimplacm "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aws-acm" +) + +const ( + AUTH_METHOD_ACCESSKEY = cmgrimplacm.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = cmgrimplacm.AUTH_METHOD_IMDS +) + const ( CERTIFICATE_SOURCE_ACM = "ACM" ) diff --git a/pkg/core/deployer/providers/aws-apigateway/aws_apigateway.go b/pkg/core/deployer/providers/aws-apigateway/aws_apigateway.go index 469715e71..2448ea729 100644 --- a/pkg/core/deployer/providers/aws-apigateway/aws_apigateway.go +++ b/pkg/core/deployer/providers/aws-apigateway/aws_apigateway.go @@ -8,6 +8,7 @@ import ( 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" + "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go-v2/service/apigatewayv2" "github.com/aws/aws-sdk-go-v2/service/apigatewayv2/types" @@ -21,6 +22,10 @@ type ( ) type DeployerConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -48,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { return nil, fmt.Errorf("the configuration of the deployer provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AuthMethod, config.AccessKeyId, config.SecretAccessKey, config.Region) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -57,6 +62,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { switch config.CertificateSource { case CERTIFICATE_SOURCE_ACM: pcertmgr, err = cmgrimplacm.NewCertmgr(&cmgrimplacm.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -119,11 +125,27 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep return &DeployResult{}, nil } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*apigatewayv2.Client, error) { - cfg, err := awscfg.LoadDefaultConfig(context.Background(), - awscfg.WithCredentialsProvider(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")), +func createSDKClient(authMethod, accessKeyId, secretAccessKey, region string) (*apigatewayv2.Client, error) { + opts := []func(options *awscfg.LoadOptions) error{ awscfg.WithRegion(region), - ) + } + + staticCredsProvider := awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "") + imdsCredsProvider := aws.NewCredentialsCache(ec2rolecreds.New()) + switch authMethod { + case "": + if accessKeyId != "" && secretAccessKey != "" { + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + } + case AUTH_METHOD_ACCESSKEY: + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + case AUTH_METHOD_IMDS: + opts = append(opts, awscfg.WithCredentialsProvider(imdsCredsProvider)) + default: + return nil, fmt.Errorf("unsupported auth method '%s'", authMethod) + } + + cfg, err := awscfg.LoadDefaultConfig(context.Background(), opts...) if err != nil { return nil, err } diff --git a/pkg/core/deployer/providers/aws-apigateway/consts.go b/pkg/core/deployer/providers/aws-apigateway/consts.go index 0ec6d7e10..51a48ad39 100644 --- a/pkg/core/deployer/providers/aws-apigateway/consts.go +++ b/pkg/core/deployer/providers/aws-apigateway/consts.go @@ -1,5 +1,14 @@ package awsapigateway +import ( + cmgrimplacm "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aws-acm" +) + +const ( + AUTH_METHOD_ACCESSKEY = cmgrimplacm.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = cmgrimplacm.AUTH_METHOD_IMDS +) + const ( CERTIFICATE_SOURCE_ACM = "ACM" ) diff --git a/pkg/core/deployer/providers/aws-clb/aws_clb.go b/pkg/core/deployer/providers/aws-clb/aws_clb.go index e8643c2d5..a0f52cf89 100644 --- a/pkg/core/deployer/providers/aws-clb/aws_clb.go +++ b/pkg/core/deployer/providers/aws-clb/aws_clb.go @@ -8,6 +8,7 @@ import ( 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" + "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" "github.com/certimate-go/certimate/pkg/core" @@ -21,6 +22,10 @@ type ( ) type DeployerConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -50,7 +55,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { return nil, fmt.Errorf("the configuration of the deployer provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AuthMethod, config.AccessKeyId, config.SecretAccessKey, config.Region) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -59,6 +64,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { switch config.CertificateSource { case CERTIFICATE_SOURCE_ACM: pcertmgr, err = cmgrimplacm.NewCertmgr(&cmgrimplacm.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -69,6 +75,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { case CERTIFICATE_SOURCE_IAM: pcertmgr, err = cmgrimpliam.NewCertmgr(&cmgrimpliam.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -132,11 +139,27 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep return &DeployResult{}, nil } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*elasticloadbalancing.Client, error) { - cfg, err := awscfg.LoadDefaultConfig(context.Background(), - awscfg.WithCredentialsProvider(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")), +func createSDKClient(authMethod, accessKeyId, secretAccessKey, region string) (*elasticloadbalancing.Client, error) { + opts := []func(options *awscfg.LoadOptions) error{ awscfg.WithRegion(region), - ) + } + + staticCredsProvider := awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "") + imdsCredsProvider := aws.NewCredentialsCache(ec2rolecreds.New()) + switch authMethod { + case "": + if accessKeyId != "" && secretAccessKey != "" { + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + } + case AUTH_METHOD_ACCESSKEY: + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + case AUTH_METHOD_IMDS: + opts = append(opts, awscfg.WithCredentialsProvider(imdsCredsProvider)) + default: + return nil, fmt.Errorf("unsupported auth method '%s'", authMethod) + } + + cfg, err := awscfg.LoadDefaultConfig(context.Background(), opts...) if err != nil { return nil, err } diff --git a/pkg/core/deployer/providers/aws-clb/consts.go b/pkg/core/deployer/providers/aws-clb/consts.go index c0e3fec6f..afa8a136b 100644 --- a/pkg/core/deployer/providers/aws-clb/consts.go +++ b/pkg/core/deployer/providers/aws-clb/consts.go @@ -1,5 +1,14 @@ package awsclb +import ( + cmgrimplacm "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aws-acm" +) + +const ( + AUTH_METHOD_ACCESSKEY = cmgrimplacm.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = cmgrimplacm.AUTH_METHOD_IMDS +) + const ( CERTIFICATE_SOURCE_ACM = "ACM" CERTIFICATE_SOURCE_IAM = "IAM" diff --git a/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go b/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go index 60f454518..b2c737102 100644 --- a/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go +++ b/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go @@ -8,6 +8,7 @@ import ( 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" + "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go-v2/service/cloudfront" "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" @@ -22,6 +23,10 @@ type ( ) type DeployerConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -49,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { return nil, fmt.Errorf("the configuration of the deployer provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AuthMethod, config.AccessKeyId, config.SecretAccessKey, config.Region) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -58,6 +63,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { switch config.CertificateSource { case CERTIFICATE_SOURCE_ACM: pcertmgr, err = cmgrimplacm.NewCertmgr(&cmgrimplacm.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -68,6 +74,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { case CERTIFICATE_SOURCE_IAM: pcertmgr, err = cmgrimpliam.NewCertmgr(&cmgrimpliam.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -158,11 +165,27 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep return &DeployResult{}, nil } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*cloudfront.Client, error) { - cfg, err := awscfg.LoadDefaultConfig(context.Background(), - awscfg.WithCredentialsProvider(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")), +func createSDKClient(authMethod, accessKeyId, secretAccessKey, region string) (*cloudfront.Client, error) { + opts := []func(options *awscfg.LoadOptions) error{ awscfg.WithRegion(region), - ) + } + + staticCredsProvider := awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "") + imdsCredsProvider := aws.NewCredentialsCache(ec2rolecreds.New()) + switch authMethod { + case "": + if accessKeyId != "" && secretAccessKey != "" { + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + } + case AUTH_METHOD_ACCESSKEY: + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + case AUTH_METHOD_IMDS: + opts = append(opts, awscfg.WithCredentialsProvider(imdsCredsProvider)) + default: + return nil, fmt.Errorf("unsupported auth method '%s'", authMethod) + } + + cfg, err := awscfg.LoadDefaultConfig(context.Background(), opts...) if err != nil { return nil, err } diff --git a/pkg/core/deployer/providers/aws-cloudfront/consts.go b/pkg/core/deployer/providers/aws-cloudfront/consts.go index ee940c580..442dd83e1 100644 --- a/pkg/core/deployer/providers/aws-cloudfront/consts.go +++ b/pkg/core/deployer/providers/aws-cloudfront/consts.go @@ -1,5 +1,14 @@ package awscloudfront +import ( + cmgrimplacm "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aws-acm" +) + +const ( + AUTH_METHOD_ACCESSKEY = cmgrimplacm.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = cmgrimplacm.AUTH_METHOD_IMDS +) + const ( CERTIFICATE_SOURCE_ACM = "ACM" CERTIFICATE_SOURCE_IAM = "IAM" diff --git a/pkg/core/deployer/providers/aws-iam/aws_iam.go b/pkg/core/deployer/providers/aws-iam/aws_iam.go index d5bcf644c..0d52f3cbe 100644 --- a/pkg/core/deployer/providers/aws-iam/aws_iam.go +++ b/pkg/core/deployer/providers/aws-iam/aws_iam.go @@ -15,6 +15,10 @@ type ( ) type DeployerConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -40,6 +44,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { } pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, diff --git a/pkg/core/deployer/providers/aws-iam/consts.go b/pkg/core/deployer/providers/aws-iam/consts.go new file mode 100644 index 000000000..0e8d1c90b --- /dev/null +++ b/pkg/core/deployer/providers/aws-iam/consts.go @@ -0,0 +1,10 @@ +package awsiam + +import ( + cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aws-iam" +) + +const ( + AUTH_METHOD_ACCESSKEY = cmgrimpl.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = cmgrimpl.AUTH_METHOD_IMDS +) diff --git a/pkg/core/deployer/providers/aws-nlb/aws_nlb.go b/pkg/core/deployer/providers/aws-nlb/aws_nlb.go index fcb67ae24..5ce06ff26 100644 --- a/pkg/core/deployer/providers/aws-nlb/aws_nlb.go +++ b/pkg/core/deployer/providers/aws-nlb/aws_nlb.go @@ -8,6 +8,7 @@ import ( 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" + "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" @@ -22,6 +23,10 @@ type ( ) type DeployerConfig struct { + // AWS API 认证方式。 + // 可取值 "accesskey"、"imds"。 + // 零值时默认值 [AUTH_METHOD_ACCESSKEY]。 + AuthMethod string `json:"authMethod,omitempty"` // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -53,7 +58,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { return nil, fmt.Errorf("the configuration of the deployer provider is nil") } - client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region) + client, err := createSDKClient(config.AuthMethod, config.AccessKeyId, config.SecretAccessKey, config.Region) if err != nil { return nil, fmt.Errorf("could not create client: %w", err) } @@ -62,6 +67,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { switch config.CertificateSource { case CERTIFICATE_SOURCE_ACM: pcertmgr, err = cmgrimplacm.NewCertmgr(&cmgrimplacm.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -72,6 +78,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) { case CERTIFICATE_SOURCE_IAM: pcertmgr, err = cmgrimpliam.NewCertmgr(&cmgrimpliam.CertmgrConfig{ + AuthMethod: config.AuthMethod, AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -220,11 +227,27 @@ func (d *Deployer) updateListenerSniCertificate(ctx context.Context, cloudListen return nil } -func createSDKClient(accessKeyId, secretAccessKey, region string) (*elasticloadbalancingv2.Client, error) { - cfg, err := awscfg.LoadDefaultConfig(context.Background(), - awscfg.WithCredentialsProvider(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")), +func createSDKClient(authMethod, accessKeyId, secretAccessKey, region string) (*elasticloadbalancingv2.Client, error) { + opts := []func(options *awscfg.LoadOptions) error{ awscfg.WithRegion(region), - ) + } + + staticCredsProvider := awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "") + imdsCredsProvider := aws.NewCredentialsCache(ec2rolecreds.New()) + switch authMethod { + case "": + if accessKeyId != "" && secretAccessKey != "" { + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + } + case AUTH_METHOD_ACCESSKEY: + opts = append(opts, awscfg.WithCredentialsProvider(staticCredsProvider)) + case AUTH_METHOD_IMDS: + opts = append(opts, awscfg.WithCredentialsProvider(imdsCredsProvider)) + default: + return nil, fmt.Errorf("unsupported auth method '%s'", authMethod) + } + + cfg, err := awscfg.LoadDefaultConfig(context.Background(), opts...) if err != nil { return nil, err } diff --git a/pkg/core/deployer/providers/aws-nlb/consts.go b/pkg/core/deployer/providers/aws-nlb/consts.go index 301893d47..2a382cf86 100644 --- a/pkg/core/deployer/providers/aws-nlb/consts.go +++ b/pkg/core/deployer/providers/aws-nlb/consts.go @@ -1,5 +1,14 @@ package awsnlb +import ( + cmgrimplacm "github.com/certimate-go/certimate/pkg/core/certmgr/providers/aws-acm" +) + +const ( + AUTH_METHOD_ACCESSKEY = cmgrimplacm.AUTH_METHOD_ACCESSKEY + AUTH_METHOD_IMDS = cmgrimplacm.AUTH_METHOD_IMDS +) + const ( CERTIFICATE_SOURCE_ACM = "ACM" CERTIFICATE_SOURCE_IAM = "IAM" diff --git a/pkg/core/deployer/providers/nginxproxymanager/consts.go b/pkg/core/deployer/providers/nginxproxymanager/consts.go index 137959b5e..b63476ad8 100644 --- a/pkg/core/deployer/providers/nginxproxymanager/consts.go +++ b/pkg/core/deployer/providers/nginxproxymanager/consts.go @@ -1,8 +1,12 @@ package nginxproxymanager +import ( + cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/nginxproxymanager" +) + const ( - AUTH_METHOD_PASSWORD = "password" - AUTH_METHOD_TOKEN = "token" + AUTH_METHOD_PASSWORD = cmgrimpl.AUTH_METHOD_PASSWORD + AUTH_METHOD_TOKEN = cmgrimpl.AUTH_METHOD_TOKEN ) const ( diff --git a/pkg/core/deployer/providers/nginxproxymanager/nginxproxymanager.go b/pkg/core/deployer/providers/nginxproxymanager/nginxproxymanager.go index 596c47548..99bc4bff0 100644 --- a/pkg/core/deployer/providers/nginxproxymanager/nginxproxymanager.go +++ b/pkg/core/deployer/providers/nginxproxymanager/nginxproxymanager.go @@ -383,14 +383,16 @@ func createSDKClient(serverUrl, authMethod, username, password, apiToken string, switch authMethod { case "", AUTH_METHOD_PASSWORD: { - client, err = npmsdk.NewClient(serverUrl, + client, err = npmsdk.NewClient( + serverUrl, npmsdk.WithLogins(username, password), ) } case AUTH_METHOD_TOKEN: { - client, err = npmsdk.NewClient(serverUrl, + client, err = npmsdk.NewClient( + serverUrl, npmsdk.WithJwtToken(apiToken), ) } diff --git a/ui/src/components/access/forms/AccessConfigFieldsProviderAWS.tsx b/ui/src/components/access/forms/AccessConfigFieldsProviderAWS.tsx index a7f1e53ba..68724414d 100644 --- a/ui/src/components/access/forms/AccessConfigFieldsProviderAWS.tsx +++ b/ui/src/components/access/forms/AccessConfigFieldsProviderAWS.tsx @@ -1,10 +1,16 @@ import { getI18n, useTranslation } from "react-i18next"; -import { Form, Input } from "antd"; +import { Form, Input, Radio } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; +import Show from "@/components/Show"; +import Tips from "@/components/Tips"; + import { useFormNestedFieldsContext } from "./_context"; +const AUTH_METHOD_ACCESSKEY = "accesskey" as const; +const AUTH_METHOD_IMDS = "imds" as const; + const AccessConfigFormFieldsProviderAWS = () => { const { i18n, t } = useTranslation(); @@ -13,35 +19,59 @@ const AccessConfigFormFieldsProviderAWS = () => { [parentNamePath]: getSchema({ i18n }), }); const formRule = createSchemaFieldRule(formSchema); + const formInst = Form.useFormInstance>(); const initialValues = getInitialValues(); + const fieldAuthMethod = Form.useWatch([parentNamePath, "authMethod"], formInst); + return ( <> } > - + + {t("access.form.aws_auth_method.option.accesskey.label")} + {t("access.form.aws_auth_method.option.imds.label")} + - } - > - - + + } + > + + + + } + > + + + + + + + } /> + + ); }; const getInitialValues = (): Nullish>> => { return { + authMethod: AUTH_METHOD_ACCESSKEY, accessKeyId: "", secretAccessKey: "", }; @@ -50,10 +80,39 @@ const getInitialValues = (): Nullish>> => { const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType }) => { const { t: _ } = i18n; - return z.object({ - accessKeyId: z.string().nonempty(), - secretAccessKey: z.string().nonempty(), - }); + return z + .object({ + authMethod: z.enum([AUTH_METHOD_ACCESSKEY, AUTH_METHOD_IMDS]), + accessKeyId: z.string().nullish(), + secretAccessKey: z.string().nullish(), + }) + .superRefine((values, ctx) => { + switch (values.authMethod) { + case AUTH_METHOD_ACCESSKEY: + { + const scAccessKeyId = z.string().nonempty(); + const spAccessKeyId = scAccessKeyId.safeParse(values.accessKeyId); + if (!spAccessKeyId.success) { + ctx.addIssue({ + code: "custom", + message: z.treeifyError(spAccessKeyId.error).errors.join(), + path: ["accessKeyId"], + }); + } + + const scSecretAccessKey = z.string().nonempty(); + const spSecretAccessKey = scSecretAccessKey.safeParse(values.secretAccessKey); + if (!spSecretAccessKey.success) { + ctx.addIssue({ + code: "custom", + message: z.treeifyError(spSecretAccessKey.error).errors.join(), + path: ["secretAccessKey"], + }); + } + } + break; + } + }); }; const _default = Object.assign(AccessConfigFormFieldsProviderAWS, { diff --git a/ui/src/i18n/resources/en/nls.access.json b/ui/src/i18n/resources/en/nls.access.json index e3d71dcbb..08274d70f 100644 --- a/ui/src/i18n/resources/en/nls.access.json +++ b/ui/src/i18n/resources/en/nls.access.json @@ -220,6 +220,19 @@ "placeholder": "Please enter ArvanCloud API key", "tooltip": "For more information, see https://docs.arvancloud.ir/en/developer-tools/api/api-key" }, + "aws_auth_method": { + "label": "AWS API authentication method", + "placeholder": "Please select AWS API authentication method", + "option": { + "accesskey": { + "label": "Access key" + }, + "imds": { + "label": "IMDS", + "guide": "If you are running Certimate in Docker, please ensure that the metadata option http-put-response-hop-limit is configured correctly for the EC2 instance. Learn more about this:
https://docs.aws.amazon.com/en_us/AWSEC2/latest/UserGuide/ec2-instance-metadata.html" + } + } + }, "aws_access_key_id": { "label": "AWS AccessKeyID", "placeholder": "Please enter AWS AccessKeyID", diff --git a/ui/src/i18n/resources/zh/nls.access.json b/ui/src/i18n/resources/zh/nls.access.json index 59b6497dd..60dffd138 100644 --- a/ui/src/i18n/resources/zh/nls.access.json +++ b/ui/src/i18n/resources/zh/nls.access.json @@ -220,6 +220,19 @@ "placeholder": "请输入 ArvanCloud API 密钥", "tooltip": "这是什么?请参阅 https://docs.arvancloud.ir/en/developer-tools/api/api-key" }, + "aws_auth_method": { + "label": "AWS API 认证方式", + "placeholder": "请选择 AWS API 认证方式", + "option": { + "accesskey": { + "label": "访问密钥" + }, + "imds": { + "label": "EC2 IMDS", + "guide": "如果你正在使用容器化运行 Certimate,请确保已为 EC2 实例配置了正确的 http-put-response-hop-limit 元数据。点击下方链接了解更多:
https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/ec2-instance-metadata.html" + } + } + }, "aws_access_key_id": { "label": "AWS AccessKeyID", "placeholder": "请输入 AWS AccessKeyID", diff --git a/ui/src/i18n/resources/zh/nls.workflow.nodes.json b/ui/src/i18n/resources/zh/nls.workflow.nodes.json index 7f3a79a2a..d419af9cc 100644 --- a/ui/src/i18n/resources/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/resources/zh/nls.workflow.nodes.json @@ -1903,7 +1903,7 @@ "placeholder": "请输入 Linode 对象存储桶名" }, "local": { - "guide": "如果你正在使用 Docker 运行 Certimate,「本地」指的是容器内而非宿主机。" + "guide": "如果你正在使用容器化运行 Certimate,「本地」指的是容器内而非宿主机。" }, "local_shell_env": { "label": "命令执行环境",