From c559eefadb4fe469d54ebe5f6916a36fafb1ccfa Mon Sep 17 00:00:00 2001 From: Aditya Kashyap Date: Mon, 2 Mar 2026 15:55:13 -0800 Subject: [PATCH] fix: Migrate AWS SDK Go v1 to v2 - Replace github.com/aws/aws-sdk-go with github.com/aws/aws-sdk-go-v2 - Update session.NewSession to config.LoadDefaultConfig - Add context.Context to all AWS API calls - Update credentials handling for SDK v2 - Update Go version to 1.25.7 This addresses the AWS SDK Go v1 EOL (July 2025) security concern. --- go.mod | 30 +++++++++--- go.sum | 60 ++++++++++++++++------- plugin.go | 143 +++++++++++++++++++++++++++--------------------------- 3 files changed, 137 insertions(+), 96 deletions(-) diff --git a/go.mod b/go.mod index 67625cd..015db32 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,35 @@ module github.com/drone-plugins/drone-s3 go 1.25.7 require ( - github.com/aws/aws-sdk-go v1.48.0 + github.com/aws/aws-sdk-go-v2 v1.41.2 + github.com/aws/aws-sdk-go-v2/config v1.32.10 + github.com/aws/aws-sdk-go-v2/credentials v1.19.10 + github.com/aws/aws-sdk-go-v2/service/s3 v1.96.2 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.7 github.com/joho/godotenv v1.4.0 github.com/mattn/go-zglob v0.0.4 + github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 github.com/urfave/cli v1.22.10 ) require ( - github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/pkg/errors v0.9.1 - github.com/russross/blackfriday/v2 v2.1.0 // indirect - golang.org/x/sys v0.1.0 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.18 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.10 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.18 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.6 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.11 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 // indirect + github.com/aws/smithy-go v1.24.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect ) diff --git a/go.sum b/go.sum index 1ee51fa..2773e57 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,47 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/aws/aws-sdk-go v1.48.0 h1:1SeJ8agckRDQvnSCt1dGZYAwUaoD2Ixj6IaXB4LCv8Q= -github.com/aws/aws-sdk-go v1.48.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.41.2 h1:LuT2rzqNQsauaGkPK/7813XxcZ3o3yePY0Iy891T2ls= +github.com/aws/aws-sdk-go-v2 v1.41.2/go.mod h1:IvvlAZQXvTXznUPfRVfryiG1fbzE2NGK6m9u39YQ+S4= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5 h1:zWFmPmgw4sveAYi1mRqG+E/g0461cJ5M4bJ8/nc6d3Q= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5/go.mod h1:nVUlMLVV8ycXSb7mSkcNu9e3v/1TJq2RTlrPwhYWr5c= +github.com/aws/aws-sdk-go-v2/config v1.32.10 h1:9DMthfO6XWZYLfzZglAgW5Fyou2nRI5CuV44sTedKBI= +github.com/aws/aws-sdk-go-v2/config v1.32.10/go.mod h1:2rUIOnA2JaiqYmSKYmRJlcMWy6qTj1vuRFscppSBMcw= +github.com/aws/aws-sdk-go-v2/credentials v1.19.10 h1:EEhmEUFCE1Yhl7vDhNOI5OCL/iKMdkkYFTRpZXNw7m8= +github.com/aws/aws-sdk-go-v2/credentials v1.19.10/go.mod h1:RnnlFCAlxQCkN2Q379B67USkBMu1PipEEiibzYN5UTE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 h1:Ii4s+Sq3yDfaMLpjrJsqD6SmG/Wq/P5L/hw2qa78UAY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18/go.mod h1:6x81qnY++ovptLE6nWQeWrpXxbnlIex+4H4eYYGcqfc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18 h1:F43zk1vemYIqPAwhjTjYIz0irU2EY7sOb/F5eJ3HuyM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18/go.mod h1:w1jdlZXrGKaJcNoL+Nnrj+k5wlpGXqnNrKoP22HvAug= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18 h1:xCeWVjj0ki0l3nruoyP2slHsGArMxeiiaoPN5QZH6YQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18/go.mod h1:r/eLGuGCBw6l36ZRWiw6PaZwPXb6YOj+i/7MizNl5/k= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.18 h1:eZioDaZGJ0tMM4gzmkNIO2aAoQd+je7Ug7TkvAzlmkU= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.18/go.mod h1:CCXwUKAJdoWr6/NcxZ+zsiPr6oH/Q5aTooRGYieAyj4= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5 h1:CeY9LUdur+Dxoeldqoun6y4WtJ3RQtzk0JMP2gfUay0= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5/go.mod h1:AZLZf2fMaahW5s/wMRciu1sYbdsikT/UHwbUjOdEVTc= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.10 h1:fJvQ5mIBVfKtiyx0AHY6HeWcRX5LGANLpq8SVR+Uazs= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.10/go.mod h1:Kzm5e6OmNH8VMkgK9t+ry5jEih4Y8whqs+1hrkxim1I= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18 h1:LTRCYFlnnKFlKsyIQxKhJuDuA3ZkrDQMRYm6rXiHlLY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18/go.mod h1:XhwkgGG6bHSd00nO/mexWTcTjgd6PjuvWQMqSn2UaEk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.18 h1:/A/xDuZAVD2BpsS2fftFRo/NoEKQJ8YTnJDEHBy2Gtg= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.18/go.mod h1:hWe9b4f+djUQGmyiGEeOnZv69dtMSgpDRIvNMvuvzvY= +github.com/aws/aws-sdk-go-v2/service/s3 v1.96.2 h1:M1A9AjcFwlxTLuf0Faj88L8Iqw0n/AJHjpZTQzMMsSc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.96.2/go.mod h1:KsdTV6Q9WKUZm2mNJnUFmIoXfZux91M3sr/a4REX8e0= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.6 h1:MzORe+J94I+hYu2a6XmV5yC9huoTv8NRcCrUNedDypQ= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.6/go.mod h1:hXzcHLARD7GeWnifd8j9RWqtfIgxj4/cAtIVIK7hg8g= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.11 h1:7oGD8KPfBOJGXiCoRKrrrQkbvCp8N++u36hrLMPey6o= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.11/go.mod h1:0DO9B5EUJQlIDif+XJRWCljZRKsAFKh3gpFz7UnDtOo= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 h1:edCcNp9eGIUDUCrzoCu1jWAXLGFIizeqkdkKgRlJwWc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15/go.mod h1:lyRQKED9xWfgkYC/wmmYfv7iVIM68Z5OQ88ZdcV1QbU= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.7 h1:NITQpgo9A5NrDZ57uOWj+abvXSb83BbyggcUBVksN7c= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.7/go.mod h1:sks5UWBhEuWYDPdwlnRFn1w7xWdH29Jcpe+/PJQefEs= +github.com/aws/smithy-go v1.24.1 h1:VbyeNfmYkWoxMVpGUAbQumkODcYmfMRfZ8yQiH30SK0= +github.com/aws/smithy-go v1.24.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/mattn/go-zglob v0.0.4 h1:LQi2iOm0/fGgu80AioIJ/1j9w9Oh+9DZ39J4VAGzHQM= @@ -19,9 +50,9 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -30,16 +61,9 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/urfave/cli v1.22.10 h1:p8Fspmz3iTctJstry1PYS3HVdllxnEzTEsgIgtxTrCk= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/plugin.go b/plugin.go index 499a235..3a9bc9c 100644 --- a/plugin.go +++ b/plugin.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "io" "mime" @@ -8,14 +9,14 @@ import ( "path/filepath" "regexp" "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/credentials/stscreds" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/sts" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/credentials/stscreds" + "github.com/aws/aws-sdk-go-v2/service/s3" + s3Types "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/mattn/go-zglob" "github.com/pkg/errors" log "github.com/sirupsen/logrus" @@ -109,6 +110,8 @@ type Plugin struct { // Exec runs the plugin func (p *Plugin) Exec() error { + ctx := context.Background() + if p.Download { p.Source = normalizePath(p.Source) p.Target = normalizePath(p.Target) @@ -117,13 +120,13 @@ func (p *Plugin) Exec() error { } // create the client - client := p.createS3Client() + client := p.createS3Client(ctx) // If in download mode, call the downloadS3Objects method if p.Download { sourceDir := normalizePath(p.Source) - return p.downloadS3Objects(client, sourceDir) + return p.downloadS3Objects(ctx, client, sourceDir) } // find the bucket @@ -276,8 +279,8 @@ func (p *Plugin) Exec() error { putObjectInput := &s3.PutObjectInput{ Body: f, - Bucket: &(p.Bucket), - Key: &target, + Bucket: aws.String(p.Bucket), + Key: aws.String(target), } if contentType != "" { @@ -293,18 +296,18 @@ func (p *Plugin) Exec() error { } if p.Encryption != "" { - putObjectInput.ServerSideEncryption = aws.String(p.Encryption) + putObjectInput.ServerSideEncryption = s3Types.ServerSideEncryption(p.Encryption) } if p.StorageClass != "" { - putObjectInput.StorageClass = &(p.StorageClass) + putObjectInput.StorageClass = s3Types.StorageClass(p.StorageClass) } if p.Access != "" { - putObjectInput.ACL = &(p.Access) + putObjectInput.ACL = s3Types.ObjectCannedACL(p.Access) } - _, err = client.PutObject(putObjectInput) + _, err = client.PutObject(ctx, putObjectInput) if err != nil { log.WithFields(log.Fields{ @@ -380,25 +383,17 @@ func matchExtension(match string, stringMap map[string]string) string { return "" } -func assumeRole(roleArn, roleSessionName, externalID string) *credentials.Credentials { +func assumeRole(ctx context.Context, cfg aws.Config, roleArn, roleSessionName, externalID string) aws.CredentialsProvider { + stsClient := sts.NewFromConfig(cfg) - sess, _ := session.NewSession() - client := sts.New(sess) - duration := time.Hour * 1 - stsProvider := &stscreds.AssumeRoleProvider{ - Client: client, - Duration: duration, - RoleARN: roleArn, - RoleSessionName: roleSessionName, - } - - if externalID != "" { - stsProvider.ExternalID = &externalID + opts := func(o *stscreds.AssumeRoleOptions) { + o.RoleSessionName = roleSessionName + if externalID != "" { + o.ExternalID = aws.String(externalID) + } } - creds := credentials.NewCredentials(stsProvider) - - return creds + return stscreds.NewAssumeRoleProvider(stsClient, roleArn, opts) } // resolveKey is a helper function that returns s3 object key where file present at srcPath is uploaded to. @@ -447,15 +442,15 @@ func normalizePath(path string) string { } // downloadS3Object downloads a single object from S3 -func (p *Plugin) downloadS3Object(client *s3.S3, sourceDir, key, target string) error { +func (p *Plugin) downloadS3Object(ctx context.Context, client *s3.Client, sourceDir, key, target string) error { log.WithFields(log.Fields{ "bucket": p.Bucket, "key": key, }).Info("Getting S3 object") - obj, err := client.GetObject(&s3.GetObjectInput{ - Bucket: &p.Bucket, - Key: &key, + obj, err := client.GetObject(ctx, &s3.GetObjectInput{ + Bucket: aws.String(p.Bucket), + Key: aws.String(key), }) if err != nil { log.WithFields(log.Fields{ @@ -501,15 +496,15 @@ func (p *Plugin) downloadS3Object(client *s3.S3, sourceDir, key, target string) } // downloadS3Objects downloads all objects in the specified S3 bucket path -func (p *Plugin) downloadS3Objects(client *s3.S3, sourceDir string) error { +func (p *Plugin) downloadS3Objects(ctx context.Context, client *s3.Client, sourceDir string) error { log.WithFields(log.Fields{ "bucket": p.Bucket, "dir": sourceDir, }).Info("Listing S3 directory") - list, err := client.ListObjectsV2(&s3.ListObjectsV2Input{ - Bucket: &p.Bucket, - Prefix: &sourceDir, + list, err := client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ + Bucket: aws.String(p.Bucket), + Prefix: aws.String(sourceDir), }) if err != nil { log.WithFields(log.Fields{ @@ -526,7 +521,7 @@ func (p *Plugin) downloadS3Objects(client *s3.S3, sourceDir string) error { // and appending the stripPrefix. target := resolveSource(sourceDir, *item.Key, p.StripPrefix) - if err := p.downloadS3Object(client, sourceDir, *item.Key, target); err != nil { + if err := p.downloadS3Object(ctx, client, sourceDir, *item.Key, target); err != nil { return err } } @@ -535,75 +530,79 @@ func (p *Plugin) downloadS3Objects(client *s3.S3, sourceDir string) error { } // createS3Client creates and returns an S3 client based on the plugin configuration -func (p *Plugin) createS3Client() *s3.S3 { +func (p *Plugin) createS3Client(ctx context.Context) *s3.Client { + // Build config options + var optFns []func(*config.LoadOptions) error - conf := &aws.Config{ - Region: aws.String(p.Region), - Endpoint: &p.Endpoint, - DisableSSL: aws.Bool(strings.HasPrefix(p.Endpoint, "http://")), - S3ForcePathStyle: aws.Bool(p.PathStyle), - } + optFns = append(optFns, config.WithRegion(p.Region)) - // Create initial session - sess, err := session.NewSession(conf) + // Load base config + cfg, err := config.LoadDefaultConfig(ctx, optFns...) if err != nil { - log.Fatalf("failed to create AWS session: %v", err) + log.Fatalf("failed to load AWS config: %v", err) } + // Set up credentials if p.Key != "" && p.Secret != "" { - conf.Credentials = credentials.NewStaticCredentials(p.Key, p.Secret, "") + cfg.Credentials = credentials.NewStaticCredentialsProvider(p.Key, p.Secret, "") } else if p.IdToken != "" && p.AssumeRole != "" { - creds, err := assumeRoleWithWebIdentity(sess, p.AssumeRole, p.AssumeRoleSessionName, p.IdToken) + creds, err := assumeRoleWithWebIdentity(ctx, cfg, p.AssumeRole, p.AssumeRoleSessionName, p.IdToken) if err != nil { log.Fatalf("failed to assume role with web identity: %v", err) } - conf.Credentials = creds + cfg.Credentials = creds } else if p.AssumeRole != "" { - conf.Credentials = assumeRole(p.AssumeRole, p.AssumeRoleSessionName, p.ExternalID) + cfg.Credentials = assumeRole(ctx, cfg, p.AssumeRole, p.AssumeRoleSessionName, p.ExternalID) } else { log.Warn("AWS Key and/or Secret not provided (falling back to ec2 instance profile)") } - // Create session with primary credentials - sess, err = session.NewSession(conf) - if err != nil { - log.Fatalf("failed to create AWS session: %v", err) + // Build S3 client options + s3Opts := func(o *s3.Options) { + if p.Endpoint != "" { + o.BaseEndpoint = aws.String(p.Endpoint) + } + o.UsePathStyle = p.PathStyle } - // Initialize client with the session - client := s3.New(sess) + // Create S3 client + client := s3.NewFromConfig(cfg, s3Opts) // Handle secondary role assumption if UserRoleArn is provided if len(p.UserRoleArn) > 0 { log.WithField("UserRoleArn", p.UserRoleArn).Info("Using user role ARN") - // Create credentials using the existing session for role assumption - // by assuming the UserRoleArn (with ExternalID when provided) - creds := stscreds.NewCredentials(sess, p.UserRoleArn, func(provider *stscreds.AssumeRoleProvider) { + stsClient := sts.NewFromConfig(cfg) + creds := stscreds.NewAssumeRoleProvider(stsClient, p.UserRoleArn, func(o *stscreds.AssumeRoleOptions) { if p.UserRoleExternalID != "" { - provider.ExternalID = aws.String(p.UserRoleExternalID) + o.ExternalID = aws.String(p.UserRoleExternalID) } }) - // Create new client with same config but updated credentials - client = s3.New(sess, &aws.Config{Credentials: creds}) + cfg.Credentials = creds + client = s3.NewFromConfig(cfg, s3Opts) } return client } -func assumeRoleWithWebIdentity(sess *session.Session, roleArn, roleSessionName, idToken string) (*credentials.Credentials, error) { - svc := sts.New(sess) +func assumeRoleWithWebIdentity(ctx context.Context, cfg aws.Config, roleArn, roleSessionName, idToken string) (aws.CredentialsProvider, error) { + stsClient := sts.NewFromConfig(cfg) + input := &sts.AssumeRoleWithWebIdentityInput{ RoleArn: aws.String(roleArn), RoleSessionName: aws.String(roleSessionName), WebIdentityToken: aws.String(idToken), } - result, err := svc.AssumeRoleWithWebIdentity(input) + result, err := stsClient.AssumeRoleWithWebIdentity(ctx, input) if err != nil { - log.Fatalf("failed to assume role with web identity: %v", err) + return nil, fmt.Errorf("failed to assume role with web identity: %v", err) } - return credentials.NewStaticCredentials(*result.Credentials.AccessKeyId, *result.Credentials.SecretAccessKey, *result.Credentials.SessionToken), nil + return credentials.NewStaticCredentialsProvider( + *result.Credentials.AccessKeyId, + *result.Credentials.SecretAccessKey, + *result.Credentials.SessionToken, + ), nil } // validateStripPrefix validates a strip prefix pattern with wildcards