From d9507d3bb27dfb6815e9a7b3fdf12c5e00bc2015 Mon Sep 17 00:00:00 2001 From: Christos Vontas <1437125+cv711@users.noreply.github.com> Date: Fri, 6 Mar 2026 13:36:17 +0000 Subject: [PATCH 1/3] refactor: getAWSKeysWithAssumeRole returns aws.creds instead of minio.creds --- internal/snapshot/s3.go | 6 +++--- internal/snapshot/service.go | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/internal/snapshot/s3.go b/internal/snapshot/s3.go index 0d5c5b0..09bc952 100644 --- a/internal/snapshot/s3.go +++ b/internal/snapshot/s3.go @@ -145,7 +145,7 @@ func (s *SnapshotService) createAssetBackup( var wg sync.WaitGroup errChan := make(chan error, 2) - cred, err := getAWSKeysWithAsumeRole(ctx, cfg.S3) + cred, err := getAWSKeysWithAsumeRoleForMinio(ctx, cfg.S3) if err != nil { return fmt.Errorf("failed to get AWS credentials: %w", err) } @@ -352,7 +352,7 @@ func (s *SnapshotService) uploadToS3(ctx context.Context, cfg *config.SnapshotCo return fmt.Errorf("failed to parse S3 URL: %w", err) } - cred, err := getAWSKeysWithAsumeRole(ctx, cfg.S3) + cred, err := getAWSKeysWithAsumeRoleForMinio(ctx, cfg.S3) if err != nil { return fmt.Errorf("failed to get AWS credentials: %w", err) } @@ -386,7 +386,7 @@ func (s *SnapshotService) downloadFromS3(ctx context.Context, cfg *config.Snapsh return nil, fmt.Errorf("failed to parse S3 URL: %w", err) } - cred, err := getAWSKeysWithAsumeRole(ctx, cfg.S3) + cred, err := getAWSKeysWithAsumeRoleForMinio(ctx, cfg.S3) if err != nil { return nil, fmt.Errorf("failed to get AWS credentials: %w", err) } diff --git a/internal/snapshot/service.go b/internal/snapshot/service.go index 22593a5..65b32a0 100644 --- a/internal/snapshot/service.go +++ b/internal/snapshot/service.go @@ -7,6 +7,7 @@ import ( "net/url" "strings" + "github.com/aws/aws-sdk-go-v2/aws" aconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/minio/minio-go/v7/pkg/credentials" v1 "github.com/shopware/shopware-operator/api/v1" @@ -41,7 +42,7 @@ func NewSnapshotService(cfg *config.SnapshotConfig) *SnapshotService { } func (s *SnapshotService) restoreS3(ctx context.Context, cfg config.S3Config, directory string) error { - cred, err := getAWSKeysWithAsumeRole(ctx, cfg) + cred, err := getAWSKeysWithAsumeRoleForMinio(ctx, cfg) if err != nil { return fmt.Errorf("failed to get AWS credentials: %w", err) } @@ -68,16 +69,16 @@ func (s *SnapshotService) restoreS3(ctx context.Context, cfg config.S3Config, di // AWS_STS_REGIONAL_ENDPOINTS=regional // AWS_DEFAULT_REGION=eu-central-1 // AWS_REGION=eu-central-1 -func getAWSKeysWithAsumeRole(ctx context.Context, cfg config.S3Config) (*credentials.Credentials, error) { +func getAWSKeysWithAsumeRole(ctx context.Context, cfg config.S3Config) (*aws.Credentials, error) { if cfg.AccessKeyID != "" && cfg.SecretAccessKey != "" { logging.FromContext(ctx). Infow("AccessKey and SecretAccessKey set, using provided AWS credentials, instead of assuming role") - return credentials.NewStaticV4( - cfg.AccessKeyID, - cfg.SecretAccessKey, - cfg.SessionToken, - ), nil + return &aws.Credentials{ + AccessKeyID: cfg.AccessKeyID, + SecretAccessKey: cfg.SecretAccessKey, + SessionToken: cfg.SessionToken, + }, nil } awsCfg, err := aconfig.LoadDefaultConfig(ctx) @@ -109,6 +110,14 @@ func getAWSKeysWithAsumeRole(ctx context.Context, cfg config.S3Config) (*credent return nil, fmt.Errorf("failed to retrieve AWS credentials: %w", err) } + return &creds, nil +} + +func getAWSKeysWithAsumeRoleForMinio(ctx context.Context, cfg config.S3Config) (*credentials.Credentials, error) { + creds, err := getAWSKeysWithAsumeRole(ctx, cfg) + if err != nil { + return nil, err + } return credentials.NewStaticV4( creds.AccessKeyID, creds.SecretAccessKey, From 91641da4b47f64a108bc2bb784882394aad1a4ed Mon Sep 17 00:00:00 2001 From: Christos Vontas <1437125+cv711@users.noreply.github.com> Date: Fri, 6 Mar 2026 13:37:17 +0000 Subject: [PATCH 2/3] feat: add uploadToS3WithAWSSDK implementation --- go.mod | 19 ++++++---- go.sum | 34 +++++++++++------ internal/snapshot/s3.go | 82 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 8084a4c..85cce08 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,10 @@ go 1.26.0 toolchain go1.26 require ( - github.com/aws/aws-sdk-go-v2 v1.37.2 + github.com/aws/aws-sdk-go-v2 v1.41.3 github.com/aws/aws-sdk-go-v2/config v1.27.36 + github.com/aws/aws-sdk-go-v2/credentials v1.17.34 + github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 github.com/cert-manager/cert-manager v1.17.1 github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf github.com/minio/minio-go/v7 v7.0.88 @@ -25,17 +27,20 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.34 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.23.0 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.31.0 // indirect - github.com/aws/smithy-go v1.22.5 // indirect + github.com/aws/smithy-go v1.24.2 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-ini/ini v1.67.0 // indirect diff --git a/go.sum b/go.sum index 03ceff6..aa03ea1 100644 --- a/go.sum +++ b/go.sum @@ -1,31 +1,41 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/aws/aws-sdk-go-v2 v1.37.2 h1:xkW1iMYawzcmYFYEV0UCMxc8gSsjCGEhBXQkdQywVbo= -github.com/aws/aws-sdk-go-v2 v1.37.2/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2 v1.41.3 h1:4kQ/fa22KjDt13QCy1+bYADvdgcxpfH18f0zP542kZA= +github.com/aws/aws-sdk-go-v2 v1.41.3/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 h1:N4lRUXZpZ1KVEUn6hxtco/1d2lgYhNn1fHkkl8WhlyQ= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI= github.com/aws/aws-sdk-go-v2/config v1.27.36 h1:4IlvHh6Olc7+61O1ktesh0jOcqmq/4WG6C2Aj5SKXy0= github.com/aws/aws-sdk-go-v2/config v1.27.36/go.mod h1:IiBpC0HPAGq9Le0Xxb1wpAKzEfAQ3XlYgJLYKEVYcfw= github.com/aws/aws-sdk-go-v2/credentials v1.17.34 h1:gmkk1l/cDGSowPRzkdxYi8edw+gN4HmVK151D/pqGNc= github.com/aws/aws-sdk-go-v2/credentials v1.17.34/go.mod h1:4R9OEV3tgFMsok4ZeFpExn7zQaZRa9MRGFYnI/xC/vs= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 h1:C/d03NAmh8C4BZXhuRNboF/DqhBkBCeDiJDcaqIT5pA= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14/go.mod h1:7I0Ju7p9mCIdlrfS+JCgqcYD0VXz/N4yozsox+0o078= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 h1:sPiRHLVUIIQcoVZTNwqQcdtjkqkPopyYmIX0M5ElRf4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2/go.mod h1:ik86P3sgV+Bk7c1tBFCwI3VxMoSEwl4YkRB9xn1s340= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 h1:ZdzDAg075H6stMZtbD2o+PyB933M/f20e9WmCBC17wA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2/go.mod h1:eE1IIzXG9sdZCB0pNNpMpsYTLl4YdOQD3njiVN1e/E4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 h1:/sECfyq2JTifMI2JPyZ4bdRN77zJmr6SrS1eL3augIA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19/go.mod h1:dMf8A5oAqr9/oxOfLkC/c2LU/uMcALP0Rgn2BD5LWn0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 h1:AWeJMk33GTBf6J20XJe6qZoRSJo0WfUhsMdUKhoODXE= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19/go.mod h1:+GWrYoaAsV7/4pNHpwh1kiNLXkKaSoppxQq9lbH8Ejw= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2 h1:oxmDEO14NBZJbK/M8y3brhMFEIGN4j8a6Aq8eY0sqlo= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.2/go.mod h1:4hH+8QCrk1uRWDPsVfsNDUup3taAjO8Dnx63au7smAU= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 h1:qi3e/dmpdONhj1RyIZdi6DKKpDXS5Lb8ftr3p7cyHJc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 h1:BYf7XNsJMzl4mObARUBUib+j2tf0U//JAAtTnYqvqCw= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11/go.mod h1:aEUS4WrNk/+FxkBZZa7tVgp4pGH+kFGW40Y8rCPqt5g= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 h1:X1Tow7suZk9UCJHE1Iw9GMZJJl0dAnKXXP1NaSDHwmw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 h1:JnQeStZvPHFHeyky/7LbMlyQjUa+jIBj36OlWm0pzIk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19/go.mod h1:HGyasyHvYdFQeJhvDHfH7HXkHh57htcJGKDZ+7z+I24= +github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 h1:4ExZyubQ6LQQVuF2Qp9OsfEvsTdAWh5Gfwf6PgIdLdk= +github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4/go.mod h1:NF3JcMGOiARAss1ld3WGORCw71+4ExDD2cbbdKS5PpA= github.com/aws/aws-sdk-go-v2/service/sso v1.23.0 h1:fHySkG0IGj2nepgGJPmmhZYL9ndnsq1Tvc6MeuVQCaQ= github.com/aws/aws-sdk-go-v2/service/sso v1.23.0/go.mod h1:XRlMvmad0ZNL+75C5FYdMvbbLkd6qiqz6foR1nA1PXY= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.0 h1:cU/OeQPNReyMj1JEBgjE29aclYZYtXcsPMXbTkVGMFk= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.0/go.mod h1:FnvDM4sfa+isJ3kDXIzAB9GAwVSzFzSy97uZ3IsHo4E= github.com/aws/aws-sdk-go-v2/service/sts v1.31.0 h1:GNVxIHBTi2EgwCxpNiozhNasMOK+ROUA2Z3X+cSBX58= github.com/aws/aws-sdk-go-v2/service/sts v1.31.0/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI= -github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= -github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= +github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cert-manager/cert-manager v1.17.1 h1:Aig+lWMoLsmpGd9TOlTvO4t0Ah3D+/vGB37x/f+ZKt0= diff --git a/internal/snapshot/s3.go b/internal/snapshot/s3.go index 09bc952..893631a 100644 --- a/internal/snapshot/s3.go +++ b/internal/snapshot/s3.go @@ -11,6 +11,10 @@ import ( "strings" "sync" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + awsv2config "github.com/aws/aws-sdk-go-v2/config" + awsv2credentials "github.com/aws/aws-sdk-go-v2/credentials" + awsv2s3 "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/minio/minio-go/v7" "github.com/shopware/shopware-operator/internal/config" "github.com/shopware/shopware-operator/internal/logging" @@ -380,6 +384,84 @@ func (s *SnapshotService) uploadToS3(ctx context.Context, cfg *config.SnapshotCo return nil } +func (s *SnapshotService) uploadToS3WithAWSSDK( + ctx context.Context, + cfg *config.SnapshotConfig, + s3Url string, + contentType string, + reader io.ReadCloser, +) error { + defer func() { + if err := reader.Close(); err != nil { + logging.FromContext(ctx).Warnw("failed to close AWS SDK upload reader", zap.Error(err)) + } + }() + + logging.FromContext(ctx).Infow("Uploading to S3 with AWS SDK") + + bucket, objectFile, err := parseS3URL(s3Url) + if err != nil { + return fmt.Errorf("failed to parse S3 URL: %w", err) + } + + creds, err := getAWSKeysWithAsumeRole(ctx, cfg.S3) + if err != nil { + return fmt.Errorf("failed to get AWS credentials: %w", err) + } + + region := cfg.S3.Region + if region == "" { + region = cfg.S3.DefaultRegion + } + if region == "" { + region = "eu-central-1" + } + + loadOptions := []func(*awsv2config.LoadOptions) error{ + awsv2config.WithRegion(region), + awsv2config.WithCredentialsProvider( + awsv2credentials.NewStaticCredentialsProvider( + creds.AccessKeyID, + creds.SecretAccessKey, + creds.SessionToken, + ), + ), + } + + customEndpoint := "" + if cfg.S3.Endpoint != "" { + customEndpoint = cfg.S3.Endpoint + if !strings.HasPrefix(customEndpoint, "http://") && !strings.HasPrefix(customEndpoint, "https://") { + customEndpoint = "https://" + customEndpoint + } + } + + awsCfg, err := awsv2config.LoadDefaultConfig(ctx, loadOptions...) + if err != nil { + return fmt.Errorf("failed to load AWS SDK config: %w", err) + } + + client := awsv2s3.NewFromConfig(awsCfg, func(o *awsv2s3.Options) { + if customEndpoint != "" { + o.BaseEndpoint = awsv2.String(customEndpoint) + o.UsePathStyle = true + } + }) + + _, err = client.PutObject(ctx, &awsv2s3.PutObjectInput{ + Bucket: awsv2.String(bucket), + Key: awsv2.String(objectFile), + Body: reader, + ContentType: awsv2.String(contentType), + Tagging: awsv2.String("object-type=store-snapshot-backup"), + }) + if err != nil { + return fmt.Errorf("failed to upload to s3 via aws sdk: %w", err) + } + + return nil +} + func (s *SnapshotService) downloadFromS3(ctx context.Context, cfg *config.SnapshotConfig, s3Url string) (io.ReadCloser, error) { bucket, objectFile, err := parseS3URL(s3Url) if err != nil { From 9af8b83b2bbe1a675ecb617dff2ee6620c809dbd Mon Sep 17 00:00:00 2001 From: Christos Vontas <1437125+cv711@users.noreply.github.com> Date: Fri, 6 Mar 2026 13:37:33 +0000 Subject: [PATCH 3/3] fix: switch archive func for evaluation --- internal/snapshot/archive.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/snapshot/archive.go b/internal/snapshot/archive.go index d244d44..9a91d9c 100644 --- a/internal/snapshot/archive.go +++ b/internal/snapshot/archive.go @@ -236,7 +236,7 @@ func (s *SnapshotService) createArchiveAndUploadToS3(ctx context.Context, cfg *c logger.Infow("Uploading archive to S3", zap.String("s3URL", snapshotCtx.BackupFile), zap.Int64("archiveSize", archiveInfo.Size())) - err = s.uploadToS3(ctx, cfg, snapshotCtx.BackupFile, "application/zip", archiveFile) + err = s.uploadToS3WithAWSSDK(ctx, cfg, snapshotCtx.BackupFile, "application/zip", archiveFile) if err != nil { return fmt.Errorf("failed to upload archive to S3: %w", err) }