Skip to content

Commit 2f6803e

Browse files
authored
feat: [CI-21342]: Aws migrated and vulnerabilities fixed (#505)
Made-with: Cursor
1 parent f5f11fa commit 2f6803e

3 files changed

Lines changed: 133 additions & 94 deletions

File tree

cmd/drone-ecr/main.go

Lines changed: 88 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,31 @@
11
package main
22

33
import (
4+
"context"
45
"encoding/base64"
6+
"errors"
57
"fmt"
6-
"io/ioutil"
78
"log"
89
"os"
910
"os/exec"
1011
"strconv"
1112
"strings"
1213

14+
"github.com/aws/aws-sdk-go-v2/aws"
15+
"github.com/aws/aws-sdk-go-v2/config"
16+
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
17+
"github.com/aws/aws-sdk-go-v2/service/ecr"
18+
ecrtypes "github.com/aws/aws-sdk-go-v2/service/ecr/types"
19+
"github.com/aws/aws-sdk-go-v2/service/sts"
1320
"github.com/joho/godotenv"
1421
"github.com/sirupsen/logrus"
1522

16-
"github.com/aws/aws-sdk-go/aws"
17-
"github.com/aws/aws-sdk-go/aws/awserr"
18-
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
19-
"github.com/aws/aws-sdk-go/aws/session"
20-
"github.com/aws/aws-sdk-go/service/ecr"
21-
2223
docker "github.com/drone-plugins/drone-docker"
2324
)
2425

25-
type ecrAPI interface {
26-
DescribeImages(*ecr.DescribeImagesInput) (*ecr.DescribeImagesOutput, error)
27-
}
28-
2926
const defaultRegion = "us-east-1"
3027

3128
func main() {
32-
// Load env-file if it exists first
3329
if env := os.Getenv("PLUGIN_ENV_FILE"); env != "" {
3430
godotenv.Load(env)
3531
}
@@ -50,7 +46,6 @@ func main() {
5046
skipPushIfTagExists = parseBoolOrDefault(false, getenv("PLUGIN_SKIP_PUSH_IF_TAG_EXISTS"))
5147
)
5248

53-
// set the region
5449
if region == "" {
5550
region = defaultRegion
5651
}
@@ -62,13 +57,15 @@ func main() {
6257
os.Setenv("AWS_SECRET_ACCESS_KEY", secret)
6358
}
6459

65-
sess, err := session.NewSession(&aws.Config{Region: &region})
60+
ctx := context.Background()
61+
62+
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region))
6663
if err != nil {
67-
log.Fatal(fmt.Sprintf("error creating aws session: %v", err))
64+
log.Fatal(fmt.Sprintf("error creating aws config: %v", err))
6865
}
6966

70-
svc := getECRClient(sess, assumeRole, externalId, idToken)
71-
username, password, defaultRegistry, err := getAuthInfo(svc)
67+
svc := getECRClient(cfg, assumeRole, externalId, idToken)
68+
username, password, defaultRegistry, err := getAuthInfo(ctx, svc)
7269

7370
if registry == "" {
7471
registry = defaultRegistry
@@ -83,32 +80,32 @@ func main() {
8380
}
8481

8582
if create {
86-
err = ensureRepoExists(svc, trimHostname(repo, registry), scanOnPush)
83+
err = ensureRepoExists(ctx, svc, trimHostname(repo, registry), scanOnPush)
8784
if err != nil {
8885
log.Fatal(fmt.Sprintf("error creating ECR repo: %v", err))
8986
}
90-
err = updateImageScannningConfig(svc, trimHostname(repo, registry), scanOnPush)
87+
err = updateImageScanningConfig(ctx, svc, trimHostname(repo, registry), scanOnPush)
9188
if err != nil {
9289
log.Fatal(fmt.Sprintf("error updating scan on push for ECR repo: %v", err))
9390
}
9491
}
9592

9693
if lifecyclePolicy != "" {
97-
p, err := ioutil.ReadFile(lifecyclePolicy)
94+
p, err := os.ReadFile(lifecyclePolicy)
9895
if err != nil {
9996
log.Fatal(err)
10097
}
101-
if err := uploadLifeCyclePolicy(svc, string(p), trimHostname(repo, registry)); err != nil {
98+
if err := uploadLifeCyclePolicy(ctx, svc, string(p), trimHostname(repo, registry)); err != nil {
10299
log.Fatal(fmt.Sprintf("error uploading ECR lifecycle policy: %v", err))
103100
}
104101
}
105102

106103
if repositoryPolicy != "" {
107-
p, err := ioutil.ReadFile(repositoryPolicy)
104+
p, err := os.ReadFile(repositoryPolicy)
108105
if err != nil {
109106
log.Fatal(err)
110107
}
111-
if err := uploadRepositoryPolicy(svc, string(p), trimHostname(repo, registry)); err != nil {
108+
if err := uploadRepositoryPolicy(ctx, svc, string(p), trimHostname(repo, registry)); err != nil {
112109
log.Fatal(fmt.Sprintf("error uploading ECR repository policy. %v", err))
113110
}
114111
}
@@ -119,7 +116,6 @@ func main() {
119116
os.Setenv("DOCKER_PASSWORD", password)
120117
os.Setenv("PLUGIN_REGISTRY_TYPE", "ECR")
121118

122-
// Skip if tag already exits for both mutable and immutable repos
123119
if skipPushIfTagExists {
124120
tagInput := getenv("PLUGIN_TAG", "PLUGIN_TAGS")
125121
var tags []string
@@ -136,7 +132,7 @@ func main() {
136132

137133
repositoryName := trimHostname(repo, registry)
138134
for _, t := range tags {
139-
exists, err := tagExists(svc, repositoryName, t)
135+
exists, err := tagExists(ctx, svc, repositoryName, t)
140136
if err != nil {
141137
logrus.Fatalf("Error checking if image exists for tag %s: %v", t, err)
142138
}
@@ -147,7 +143,6 @@ func main() {
147143
}
148144
}
149145

150-
// invoke the base docker plugin binary
151146
cmd := exec.Command(docker.GetDroneDockerExecCmd())
152147
cmd.Stdout = os.Stdout
153148
cmd.Stderr = os.Stderr
@@ -162,57 +157,63 @@ func trimHostname(repo, registry string) string {
162157
return repo
163158
}
164159

165-
func ensureRepoExists(svc *ecr.ECR, name string, scanOnPush bool) (err error) {
166-
input := &ecr.CreateRepositoryInput{}
167-
input.SetRepositoryName(name)
168-
input.SetImageScanningConfiguration(&ecr.ImageScanningConfiguration{ScanOnPush: &scanOnPush})
169-
_, err = svc.CreateRepository(input)
160+
func ensureRepoExists(ctx context.Context, svc *ecr.Client, name string, scanOnPush bool) error {
161+
_, err := svc.CreateRepository(ctx, &ecr.CreateRepositoryInput{
162+
RepositoryName: aws.String(name),
163+
ImageScanningConfiguration: &ecrtypes.ImageScanningConfiguration{
164+
ScanOnPush: scanOnPush,
165+
},
166+
})
170167
if err != nil {
171-
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == ecr.ErrCodeRepositoryAlreadyExistsException {
172-
// eat it, we skip checking for existing to save two requests
173-
err = nil
168+
var rae *ecrtypes.RepositoryAlreadyExistsException
169+
if errors.As(err, &rae) {
170+
return nil
174171
}
172+
return err
175173
}
176-
177-
return
174+
return nil
178175
}
179176

180-
func updateImageScannningConfig(svc *ecr.ECR, name string, scanOnPush bool) (err error) {
181-
input := &ecr.PutImageScanningConfigurationInput{}
182-
input.SetRepositoryName(name)
183-
input.SetImageScanningConfiguration(&ecr.ImageScanningConfiguration{ScanOnPush: &scanOnPush})
184-
_, err = svc.PutImageScanningConfiguration(input)
185-
177+
func updateImageScanningConfig(ctx context.Context, svc *ecr.Client, name string, scanOnPush bool) error {
178+
_, err := svc.PutImageScanningConfiguration(ctx, &ecr.PutImageScanningConfigurationInput{
179+
RepositoryName: aws.String(name),
180+
ImageScanningConfiguration: &ecrtypes.ImageScanningConfiguration{
181+
ScanOnPush: scanOnPush,
182+
},
183+
})
186184
return err
187185
}
188186

189-
func uploadLifeCyclePolicy(svc *ecr.ECR, lifecyclePolicy string, name string) (err error) {
190-
input := &ecr.PutLifecyclePolicyInput{}
191-
input.SetLifecyclePolicyText(lifecyclePolicy)
192-
input.SetRepositoryName(name)
193-
_, err = svc.PutLifecyclePolicy(input)
194-
187+
func uploadLifeCyclePolicy(ctx context.Context, svc *ecr.Client, lifecyclePolicy string, name string) error {
188+
_, err := svc.PutLifecyclePolicy(ctx, &ecr.PutLifecyclePolicyInput{
189+
LifecyclePolicyText: aws.String(lifecyclePolicy),
190+
RepositoryName: aws.String(name),
191+
})
195192
return err
196193
}
197194

198-
func uploadRepositoryPolicy(svc *ecr.ECR, repositoryPolicy string, name string) (err error) {
199-
input := &ecr.SetRepositoryPolicyInput{}
200-
input.SetPolicyText(repositoryPolicy)
201-
input.SetRepositoryName(name)
202-
_, err = svc.SetRepositoryPolicy(input)
203-
195+
func uploadRepositoryPolicy(ctx context.Context, svc *ecr.Client, repositoryPolicy string, name string) error {
196+
_, err := svc.SetRepositoryPolicy(ctx, &ecr.SetRepositoryPolicyInput{
197+
PolicyText: aws.String(repositoryPolicy),
198+
RepositoryName: aws.String(name),
199+
})
204200
return err
205201
}
206202

207-
func getAuthInfo(svc *ecr.ECR) (username, password, registry string, err error) {
203+
func getAuthInfo(ctx context.Context, svc *ecr.Client) (username, password, registry string, err error) {
208204
var result *ecr.GetAuthorizationTokenOutput
209205
var decoded []byte
210206

211-
result, err = svc.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{})
207+
result, err = svc.GetAuthorizationToken(ctx, &ecr.GetAuthorizationTokenInput{})
212208
if err != nil {
213209
return
214210
}
215211

212+
if len(result.AuthorizationData) == 0 {
213+
err = fmt.Errorf("no authorization data returned from ECR")
214+
return
215+
}
216+
216217
auth := result.AuthorizationData[0]
217218
token := *auth.AuthorizationToken
218219
decoded, err = base64.StdEncoding.DecodeString(token)
@@ -221,7 +222,11 @@ func getAuthInfo(svc *ecr.ECR) (username, password, registry string, err error)
221222
}
222223

223224
registry = strings.TrimPrefix(*auth.ProxyEndpoint, "https://")
224-
creds := strings.Split(string(decoded), ":")
225+
creds := strings.SplitN(string(decoded), ":", 2)
226+
if len(creds) < 2 {
227+
err = fmt.Errorf("invalid ECR authorization token format")
228+
return
229+
}
225230
username = creds[0]
226231
password = creds[1]
227232
return
@@ -233,7 +238,6 @@ func parseBoolOrDefault(defaultValue bool, s string) (result bool) {
233238
if err != nil {
234239
result = defaultValue
235240
}
236-
237241
return
238242
}
239243

@@ -247,55 +251,51 @@ func getenv(key ...string) (s string) {
247251
return
248252
}
249253

250-
func getECRClient(sess *session.Session, role string, externalId string, idToken string) *ecr.ECR {
254+
func getECRClient(cfg aws.Config, role string, externalId string, idToken string) *ecr.Client {
251255
if role == "" {
252-
return ecr.New(sess)
256+
return ecr.NewFromConfig(cfg)
253257
}
254258

255-
if idToken != "" {
256-
tempFile, err := os.CreateTemp("/tmp", "idToken-*.jwt")
257-
if err != nil {
258-
log.Fatalf("Failed to create temporary file: %v", err)
259-
}
260-
defer tempFile.Close()
261-
262-
if err := os.Chmod(tempFile.Name(), 0600); err != nil {
263-
log.Fatalf("Failed to set file permissions: %v", err)
264-
}
259+
stsSvc := sts.NewFromConfig(cfg)
265260

266-
if _, err := tempFile.WriteString(idToken); err != nil {
267-
log.Fatalf("Failed to write ID token to temporary file: %v", err)
268-
}
261+
if idToken != "" {
262+
provider := stscreds.NewWebIdentityRoleProvider(stsSvc, role, identityToken(idToken))
263+
cfg.Credentials = aws.NewCredentialsCache(provider)
264+
return ecr.NewFromConfig(cfg)
265+
}
269266

270-
// Create credentials using the path to the ID token file
271-
creds := stscreds.NewWebIdentityCredentials(sess, role, "", tempFile.Name())
272-
return ecr.New(sess, &aws.Config{Credentials: creds})
273-
} else if externalId != "" {
274-
return ecr.New(sess, &aws.Config{
275-
Credentials: stscreds.NewCredentials(sess, role, func(p *stscreds.AssumeRoleProvider) {
276-
p.ExternalID = &externalId
277-
}),
267+
var provider *stscreds.AssumeRoleProvider
268+
if externalId != "" {
269+
provider = stscreds.NewAssumeRoleProvider(stsSvc, role, func(o *stscreds.AssumeRoleOptions) {
270+
o.ExternalID = &externalId
278271
})
279272
} else {
280-
return ecr.New(sess, &aws.Config{
281-
Credentials: stscreds.NewCredentials(sess, role),
282-
})
273+
provider = stscreds.NewAssumeRoleProvider(stsSvc, role)
283274
}
275+
cfg.Credentials = aws.NewCredentialsCache(provider)
276+
return ecr.NewFromConfig(cfg)
284277
}
285278

286-
func tagExists(svc ecrAPI, repository, tag string) (bool, error) {
279+
func tagExists(ctx context.Context, svc *ecr.Client, repository, tag string) (bool, error) {
287280
input := &ecr.DescribeImagesInput{
288281
RepositoryName: aws.String(repository),
289-
ImageIds: []*ecr.ImageIdentifier{
282+
ImageIds: []ecrtypes.ImageIdentifier{
290283
{ImageTag: aws.String(tag)},
291284
},
292285
}
293-
output, err := svc.DescribeImages(input)
286+
output, err := svc.DescribeImages(ctx, input)
294287
if err != nil {
295-
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == "ImageNotFoundException" {
288+
var inf *ecrtypes.ImageNotFoundException
289+
if errors.As(err, &inf) {
296290
return false, nil
297291
}
298292
return false, err
299293
}
300294
return len(output.ImageDetails) > 0, nil
301295
}
296+
297+
type identityToken string
298+
299+
func (t identityToken) GetIdentityToken() ([]byte, error) {
300+
return []byte(t), nil
301+
}

go.mod

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ module github.com/drone-plugins/drone-docker
33
require (
44
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1
55
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2
6-
github.com/aws/aws-sdk-go v1.26.7
6+
github.com/aws/aws-sdk-go-v2 v1.41.2
7+
github.com/aws/aws-sdk-go-v2/config v1.32.10
8+
github.com/aws/aws-sdk-go-v2/credentials v1.19.10
9+
github.com/aws/aws-sdk-go-v2/service/ecr v1.55.3
10+
github.com/aws/aws-sdk-go-v2/service/sts v1.41.7
711
github.com/coreos/go-semver v0.3.0
812
github.com/dchest/uniuri v1.2.0
913
github.com/drone-plugins/drone-plugin-lib v0.4.1
@@ -22,6 +26,16 @@ require (
2226
cloud.google.com/go/compute/metadata v0.3.0 // indirect
2327
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
2428
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
29+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 // indirect
30+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18 // indirect
31+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18 // indirect
32+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
33+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5 // indirect
34+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18 // indirect
35+
github.com/aws/aws-sdk-go-v2/service/signin v1.0.6 // indirect
36+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.11 // indirect
37+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 // indirect
38+
github.com/aws/smithy-go v1.24.1 // indirect
2539
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
2640
github.com/davecgh/go-spew v1.1.1 // indirect
2741
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
@@ -31,7 +45,6 @@ require (
3145
github.com/google/uuid v1.6.0 // indirect
3246
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
3347
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
34-
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
3548
github.com/kylelemons/godebug v1.1.0 // indirect
3649
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
3750
github.com/pmezard/go-difflib v1.0.0 // indirect

0 commit comments

Comments
 (0)