@@ -25,10 +25,14 @@ import (
25
25
"time"
26
26
27
27
"github.com/Masterminds/semver/v3"
28
+ "github.com/google/go-containerregistry/pkg/authn"
29
+ "github.com/google/go-containerregistry/pkg/authn/k8schain"
28
30
"github.com/google/go-containerregistry/pkg/crane"
29
31
gcrv1 "github.com/google/go-containerregistry/pkg/v1"
30
32
corev1 "k8s.io/api/core/v1"
31
33
"k8s.io/apimachinery/pkg/runtime"
34
+ "k8s.io/apimachinery/pkg/types"
35
+ "k8s.io/apimachinery/pkg/util/sets"
32
36
"k8s.io/apimachinery/pkg/util/uuid"
33
37
kuberecorder "k8s.io/client-go/tools/record"
34
38
@@ -280,16 +284,24 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
280
284
ctxTimeout , cancel := context .WithTimeout (ctx , obj .Spec .Timeout .Duration )
281
285
defer cancel ()
282
286
287
+ // Generates registry credential keychain
288
+ keychain , err := r .keychain (ctx , obj )
289
+ if err != nil {
290
+ e := & serror.Event {Err : err , Reason : sourcev1 .OCIOperationFailedReason }
291
+ conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Error ())
292
+ return sreconcile .ResultEmpty , e
293
+ }
294
+
283
295
// Determine which artifact revision to pull
284
- url , err := r .getArtifactURL (ctxTimeout , obj )
296
+ url , err := r .getArtifactURL (ctxTimeout , obj , keychain )
285
297
if err != nil {
286
298
e := & serror.Event {Err : err , Reason : sourcev1 .OCIOperationFailedReason }
287
299
conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Error ())
288
300
return sreconcile .ResultEmpty , e
289
301
}
290
302
291
303
// Pull artifact from the remote container registry
292
- img , err := crane .Pull (url , r .craneOptions (ctxTimeout )... )
304
+ img , err := crane .Pull (url , r .craneOptions (ctxTimeout , keychain )... )
293
305
if err != nil {
294
306
e := & serror.Event {Err : err , Reason : sourcev1 .OCIOperationFailedReason }
295
307
conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Error ())
@@ -352,15 +364,15 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
352
364
}
353
365
354
366
// getArtifactURL determines which tag or digest should be used and returns the OCI artifact FQN.
355
- func (r * OCIRepositoryReconciler ) getArtifactURL (ctx context.Context , obj * sourcev1.OCIRepository ) (string , error ) {
367
+ func (r * OCIRepositoryReconciler ) getArtifactURL (ctx context.Context , obj * sourcev1.OCIRepository , keychain authn. Keychain ) (string , error ) {
356
368
url := obj .Spec .URL
357
369
if obj .Spec .Reference != nil {
358
370
if obj .Spec .Reference .Digest != "" {
359
371
return fmt .Sprintf ("%s@%s" , obj .Spec .URL , obj .Spec .Reference .Digest ), nil
360
372
}
361
373
362
374
if obj .Spec .Reference .SemVer != "" {
363
- tag , err := r .getTagBySemver (ctx , url , obj .Spec .Reference .SemVer )
375
+ tag , err := r .getTagBySemver (ctx , url , obj .Spec .Reference .SemVer , keychain )
364
376
if err != nil {
365
377
return "" , err
366
378
}
@@ -377,8 +389,8 @@ func (r *OCIRepositoryReconciler) getArtifactURL(ctx context.Context, obj *sourc
377
389
378
390
// getTagBySemver call the remote container registry, fetches all the tags from the repository,
379
391
// and returns the latest tag according to the semver expression.
380
- func (r * OCIRepositoryReconciler ) getTagBySemver (ctx context.Context , url , exp string ) (string , error ) {
381
- tags , err := crane .ListTags (url , r .craneOptions (ctx )... )
392
+ func (r * OCIRepositoryReconciler ) getTagBySemver (ctx context.Context , url , exp string , keychain authn. Keychain ) (string , error ) {
393
+ tags , err := crane .ListTags (url , r .craneOptions (ctx , keychain )... )
382
394
if err != nil {
383
395
return "" , err
384
396
}
@@ -408,11 +420,56 @@ func (r *OCIRepositoryReconciler) getTagBySemver(ctx context.Context, url, exp s
408
420
return matchingVersions [0 ].Original (), nil
409
421
}
410
422
423
+ // keychain generates the credential keychain based on the resource
424
+ // configuration. If no auth is specified a default keychain with
425
+ // anonymous access is returned
426
+ func (r * OCIRepositoryReconciler ) keychain (ctx context.Context , obj * sourcev1.OCIRepository ) (authn.Keychain , error ) {
427
+ pullSecretNames := sets .NewString ()
428
+
429
+ // lookup auth secret
430
+ if obj .Spec .SecretRef != nil {
431
+ pullSecretNames .Insert (obj .Spec .SecretRef .Name )
432
+ }
433
+
434
+ // lookup service account
435
+ if obj .Spec .ServiceAccountName != "" {
436
+ serviceAccountName := obj .Spec .ServiceAccountName
437
+ serviceAccount := corev1.ServiceAccount {}
438
+ err := r .Get (ctx , types.NamespacedName {Namespace : obj .Namespace , Name : serviceAccountName }, & serviceAccount )
439
+ if err != nil {
440
+ return nil , err
441
+ }
442
+ for _ , ips := range serviceAccount .ImagePullSecrets {
443
+ pullSecretNames .Insert (ips .Name )
444
+ }
445
+ }
446
+
447
+ // if no pullsecrets available return DefaultKeyChain
448
+ if len (pullSecretNames ) == 0 {
449
+ return authn .DefaultKeychain , nil
450
+ }
451
+
452
+ // lookup image pull secrets
453
+ imagePullSecrets := make ([]corev1.Secret , len (pullSecretNames ))
454
+ for i , imagePullSecretName := range pullSecretNames .List () {
455
+ imagePullSecret := corev1.Secret {}
456
+ err := r .Get (ctx , types.NamespacedName {Namespace : obj .Namespace , Name : imagePullSecretName }, & imagePullSecret )
457
+ if err != nil {
458
+ r .eventLogf (ctx , obj , events .EventSeverityTrace , "secret %q not found" , imagePullSecretName )
459
+ return nil , err
460
+ }
461
+ imagePullSecrets [i ] = imagePullSecret
462
+ }
463
+
464
+ return k8schain .NewFromPullSecrets (ctx , imagePullSecrets )
465
+ }
466
+
411
467
// craneOptions sets the timeout and user agent for all operations against remote container registries.
412
- func (r * OCIRepositoryReconciler ) craneOptions (ctx context.Context ) []crane.Option {
468
+ func (r * OCIRepositoryReconciler ) craneOptions (ctx context.Context , keychain authn. Keychain ) []crane.Option {
413
469
return []crane.Option {
414
470
crane .WithContext (ctx ),
415
471
crane .WithUserAgent ("flux/v2" ),
472
+ crane .WithAuthFromKeychain (keychain ),
416
473
}
417
474
}
418
475
0 commit comments