@@ -7,7 +7,6 @@ package orchestrator
7
7
import (
8
8
"context"
9
9
"crypto/sha256"
10
- "encoding/base64"
11
10
"encoding/json"
12
11
"errors"
13
12
"fmt"
@@ -19,6 +18,7 @@ import (
19
18
"sync"
20
19
"time"
21
20
21
+ "github.com/aws/aws-sdk-go-v2/service/ecr"
22
22
"github.com/docker/distribution/reference"
23
23
"github.com/google/uuid"
24
24
"github.com/opentracing/opentracing-go"
@@ -30,6 +30,7 @@ import (
30
30
"google.golang.org/grpc/credentials/insecure"
31
31
"google.golang.org/grpc/status"
32
32
33
+ awsconfig "github.com/aws/aws-sdk-go-v2/config"
33
34
common_grpc "github.com/gitpod-io/gitpod/common-go/grpc"
34
35
"github.com/gitpod-io/gitpod/common-go/log"
35
36
"github.com/gitpod-io/gitpod/common-go/tracing"
@@ -40,10 +41,6 @@ import (
40
41
"github.com/gitpod-io/gitpod/image-builder/pkg/auth"
41
42
"github.com/gitpod-io/gitpod/image-builder/pkg/resolve"
42
43
wsmanapi "github.com/gitpod-io/gitpod/ws-manager/api"
43
-
44
- "github.com/aws/aws-sdk-go-v2/aws"
45
- awsconfig "github.com/aws/aws-sdk-go-v2/config"
46
- "github.com/aws/aws-sdk-go-v2/service/ecr"
47
44
)
48
45
49
46
const (
@@ -60,17 +57,26 @@ const (
60
57
61
58
// NewOrchestratingBuilder creates a new orchestrating image builder
62
59
func NewOrchestratingBuilder (cfg config.Configuration ) (res * Orchestrator , err error ) {
63
- var authentication auth.RegistryAuthenticator
60
+ var authentication auth.CompositeAuth
64
61
if cfg .PullSecretFile != "" {
65
62
fn := cfg .PullSecretFile
66
63
if tproot := os .Getenv ("TELEPRESENCE_ROOT" ); tproot != "" {
67
64
fn = filepath .Join (tproot , fn )
68
65
}
69
66
70
- authentication , err = auth .NewDockerConfigFileAuth (fn )
67
+ ath , err : = auth .NewDockerConfigFileAuth (fn )
71
68
if err != nil {
72
- return
69
+ return nil , err
73
70
}
71
+ authentication = append (authentication , ath )
72
+ }
73
+ if cfg .EnableAdditionalECRAuth {
74
+ awsCfg , err := awsconfig .LoadDefaultConfig (context .Background ())
75
+ if err != nil {
76
+ return nil , err
77
+ }
78
+ ecrc := ecr .NewFromConfig (awsCfg )
79
+ authentication = append (authentication , auth .NewECRAuthenticator (ecrc ))
74
80
}
75
81
76
82
var wsman wsmanapi.WorkspaceManagerClient
@@ -138,10 +144,6 @@ type Orchestrator struct {
138
144
139
145
metrics * metrics
140
146
141
- ecrAuth string
142
- ecrAuthLastRefreshTime time.Time
143
- ecrAuthLock sync.Mutex
144
-
145
147
protocol.UnimplementedImageBuilderServer
146
148
}
147
149
@@ -176,15 +178,6 @@ func (o *Orchestrator) ResolveWorkspaceImage(ctx context.Context, req *protocol.
176
178
tracing .LogRequestSafe (span , req )
177
179
178
180
reqauth := o .AuthResolver .ResolveRequestAuth (req .Auth )
179
- // The user might want to pull from ECR in a Dockerfile. Use the explicitely listed repos
180
- // to get the auth for that operation.
181
- for _ , explicitRef := range reqauth .Explicit {
182
- err := o .addAdditionalECRAuth (ctx , & reqauth , explicitRef )
183
- if err != nil {
184
- log .WithError (err ).WithField ("ref" , explicitRef ).Warn ("cannot add additional ECR auth" )
185
- }
186
- }
187
-
188
181
baseref , err := o .getBaseImageRef (ctx , req .Source , reqauth )
189
182
if _ , ok := status .FromError (err ); err != nil && ok {
190
183
return nil , err
@@ -200,7 +193,7 @@ func (o *Orchestrator) ResolveWorkspaceImage(ctx context.Context, req *protocol.
200
193
201
194
// to check if the image exists we must have access to the image caching registry and the refstr we check here does not come
202
195
// from the user. Thus we can safely use auth.AllowedAuthForAll here.
203
- auth , err := auth .AllowedAuthForAll ().GetAuthFor (o .Auth , refstr )
196
+ auth , err := auth .AllowedAuthForAll ().GetAuthFor (ctx , o .Auth , refstr )
204
197
if err != nil {
205
198
return nil , status .Errorf (codes .Internal , "cannot get workspace image authentication: %v" , err )
206
199
}
@@ -235,16 +228,6 @@ func (o *Orchestrator) Build(req *protocol.BuildRequest, resp protocol.ImageBuil
235
228
236
229
// resolve build request authentication
237
230
reqauth := o .AuthResolver .ResolveRequestAuth (req .Auth )
238
-
239
- // The user might want to pull from ECR in a Dockerfile. Use the explicitely listed repos
240
- // to get the auth for that operation.
241
- for _ , explicitRef := range reqauth .Explicit {
242
- err := o .addAdditionalECRAuth (ctx , & reqauth , explicitRef )
243
- if err != nil {
244
- log .WithError (err ).WithField ("ref" , explicitRef ).Warn ("cannot add additional ECR auth" )
245
- }
246
- }
247
-
248
231
baseref , err := o .getBaseImageRef (ctx , req .Source , reqauth )
249
232
if _ , ok := status .FromError (err ); err != nil && ok {
250
233
return err
@@ -256,7 +239,7 @@ func (o *Orchestrator) Build(req *protocol.BuildRequest, resp protocol.ImageBuil
256
239
if err != nil {
257
240
return status .Errorf (codes .Internal , "cannot produce workspace image ref: %q" , err )
258
241
}
259
- wsrefAuth , err := auth .AllowedAuthForAll ().GetAuthFor (o .Auth , wsrefstr )
242
+ wsrefAuth , err := auth .AllowedAuthForAll ().GetAuthFor (ctx , o .Auth , wsrefstr )
260
243
if err != nil {
261
244
return status .Errorf (codes .Internal , "cannot get workspace image authentication: %q" , err )
262
245
}
@@ -576,12 +559,7 @@ func (o *Orchestrator) checkImageExists(ctx context.Context, ref string, authent
576
559
577
560
// getAbsoluteImageRef returns the "digest" form of an image, i.e. contains no mutable image tags
578
561
func (o * Orchestrator ) getAbsoluteImageRef (ctx context.Context , ref string , allowedAuth auth.AllowedAuthFor ) (res string , err error ) {
579
- err = o .addAdditionalECRAuth (ctx , & allowedAuth , ref )
580
- if err != nil {
581
- return "" , err
582
- }
583
-
584
- auth , err := allowedAuth .GetAuthFor (o .Auth , ref )
562
+ auth , err := allowedAuth .GetAuthFor (ctx , o .Auth , ref )
585
563
if err != nil {
586
564
return "" , status .Errorf (codes .InvalidArgument , "cannt resolve base image ref: %v" , err )
587
565
}
@@ -605,10 +583,6 @@ func (o *Orchestrator) getBaseImageRef(ctx context.Context, bs *protocol.BuildSo
605
583
606
584
switch src := bs .From .(type ) {
607
585
case * protocol.BuildSource_Ref :
608
- err := o .addAdditionalECRAuth (ctx , & allowedAuth , src .Ref .Ref )
609
- if err != nil {
610
- return "" , err
611
- }
612
586
return o .getAbsoluteImageRef (ctx , src .Ref .Ref , allowedAuth )
613
587
614
588
case * protocol.BuildSource_File :
@@ -679,70 +653,6 @@ func (o *Orchestrator) getWorkspaceImageRef(ctx context.Context, baseref string)
679
653
return fmt .Sprintf ("%s:%x" , o .Config .WorkspaceImageRepository , dst ), nil
680
654
}
681
655
682
- func (o * Orchestrator ) addAdditionalECRAuth (ctx context.Context , allowedAuth * auth.AllowedAuthFor , ref string ) (err error ) {
683
- if ! o .Config .EnableAdditionalECRAuth {
684
- return nil
685
- }
686
- defer func () {
687
- if err == nil {
688
- return
689
- }
690
- err = fmt .Errorf ("cannot add additional ECR credentials: %w" , err )
691
- }()
692
-
693
- // Total hack because the explicit auth entries (defaultBaseImageRegistryWhitelist) lists domains, not
694
- // repositories or references.
695
- domain := ref
696
- if strings .Contains (ref , "/" ) {
697
- refp , err := reference .ParseNamed (ref )
698
- if err != nil {
699
- return fmt .Errorf ("cannot parse %s: %w" , ref , err )
700
- }
701
- domain = reference .Domain (refp )
702
- }
703
-
704
- log .WithField ("domain" , domain ).Debug ("checking if additional ECR auth needs to be added" )
705
-
706
- // TODO(cw): find better way to detect if ref is an ECR repo
707
- if ! strings .Contains (domain , ".dkr." ) || ! strings .Contains (domain , ".amazonaws.com" ) {
708
- return nil
709
- }
710
-
711
- o .ecrAuthLock .Lock ()
712
- defer o .ecrAuthLock .Unlock ()
713
- // ECR tokens are valid for 12h: https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_GetAuthorizationToken.html
714
- if time .Since (o .ecrAuthLastRefreshTime ) > 10 * time .Hour {
715
- awsCfg , err := awsconfig .LoadDefaultConfig (context .Background ())
716
- if err != nil {
717
- return err
718
- }
719
- ecrc := ecr .NewFromConfig (awsCfg )
720
- tknout , err := ecrc .GetAuthorizationToken (ctx , & ecr.GetAuthorizationTokenInput {})
721
- if err != nil {
722
- return err
723
- }
724
- if len (tknout .AuthorizationData ) == 0 {
725
- return fmt .Errorf ("no ECR authorization data received" )
726
- }
727
-
728
- pwd , err := base64 .StdEncoding .DecodeString (aws .ToString (tknout .AuthorizationData [0 ].AuthorizationToken ))
729
- if err != nil {
730
- return err
731
- }
732
-
733
- o .ecrAuth = string (pwd )
734
- o .ecrAuthLastRefreshTime = time .Now ()
735
- log .Debug ("refreshed ECR token" )
736
- }
737
-
738
- if allowedAuth .Additional == nil {
739
- allowedAuth .Additional = make (map [string ]string )
740
- }
741
- allowedAuth .Additional [domain ] = base64 .StdEncoding .EncodeToString ([]byte (o .ecrAuth ))
742
- log .WithField ("domain" , domain ).Debug ("added additional auth" )
743
- return nil
744
- }
745
-
746
656
// parentCantCancelContext is a bit of a hack. We have some operations which we want to keep alive even after clients
747
657
// disconnect. gRPC cancels the context once a client disconnects, thus we intercept the cancelation and act as if
748
658
// nothing had happened.
0 commit comments