Skip to content

Commit 47e5a90

Browse files
rashedkvmstefanprodan
authored andcommitted
Implements basic auth with static credentials OCIRepository
Signed-off-by: rashedkvm <[email protected]>
1 parent d245432 commit 47e5a90

File tree

7 files changed

+705
-42
lines changed

7 files changed

+705
-42
lines changed

controllers/ocirepository_controller.go

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@ import (
2525
"time"
2626

2727
"github.com/Masterminds/semver/v3"
28+
"github.com/google/go-containerregistry/pkg/authn"
29+
"github.com/google/go-containerregistry/pkg/authn/k8schain"
2830
"github.com/google/go-containerregistry/pkg/crane"
2931
gcrv1 "github.com/google/go-containerregistry/pkg/v1"
3032
corev1 "k8s.io/api/core/v1"
3133
"k8s.io/apimachinery/pkg/runtime"
34+
"k8s.io/apimachinery/pkg/types"
35+
"k8s.io/apimachinery/pkg/util/sets"
3236
"k8s.io/apimachinery/pkg/util/uuid"
3337
kuberecorder "k8s.io/client-go/tools/record"
3438

@@ -280,16 +284,24 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
280284
ctxTimeout, cancel := context.WithTimeout(ctx, obj.Spec.Timeout.Duration)
281285
defer cancel()
282286

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+
283295
// Determine which artifact revision to pull
284-
url, err := r.getArtifactURL(ctxTimeout, obj)
296+
url, err := r.getArtifactURL(ctxTimeout, obj, keychain)
285297
if err != nil {
286298
e := &serror.Event{Err: err, Reason: sourcev1.OCIOperationFailedReason}
287299
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Error())
288300
return sreconcile.ResultEmpty, e
289301
}
290302

291303
// 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)...)
293305
if err != nil {
294306
e := &serror.Event{Err: err, Reason: sourcev1.OCIOperationFailedReason}
295307
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Error())
@@ -352,15 +364,15 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
352364
}
353365

354366
// 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) {
356368
url := obj.Spec.URL
357369
if obj.Spec.Reference != nil {
358370
if obj.Spec.Reference.Digest != "" {
359371
return fmt.Sprintf("%s@%s", obj.Spec.URL, obj.Spec.Reference.Digest), nil
360372
}
361373

362374
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)
364376
if err != nil {
365377
return "", err
366378
}
@@ -377,8 +389,8 @@ func (r *OCIRepositoryReconciler) getArtifactURL(ctx context.Context, obj *sourc
377389

378390
// getTagBySemver call the remote container registry, fetches all the tags from the repository,
379391
// 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)...)
382394
if err != nil {
383395
return "", err
384396
}
@@ -408,11 +420,56 @@ func (r *OCIRepositoryReconciler) getTagBySemver(ctx context.Context, url, exp s
408420
return matchingVersions[0].Original(), nil
409421
}
410422

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+
411467
// 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 {
413469
return []crane.Option{
414470
crane.WithContext(ctx),
415471
crane.WithUserAgent("flux/v2"),
472+
crane.WithAuthFromKeychain(keychain),
416473
}
417474
}
418475

0 commit comments

Comments
 (0)