@@ -299,6 +299,8 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.O
299
299
// reconcileSource fetches the upstream OCI artifact metadata and content.
300
300
// If this fails, it records v1beta2.FetchFailedCondition=True on the object and returns early.
301
301
func (r * OCIRepositoryReconciler ) reconcileSource (ctx context.Context , obj * sourcev1.OCIRepository , metadata * sourcev1.Artifact , dir string ) (sreconcile.Result , error ) {
302
+ var auth authn.Authenticator
303
+
302
304
ctxTimeout , cancel := context .WithTimeout (ctx , obj .Spec .Timeout .Duration )
303
305
defer cancel ()
304
306
@@ -310,8 +312,6 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
310
312
conditions .Delete (obj , sourcev1 .SourceVerifiedCondition )
311
313
}
312
314
313
- options := r .craneOptions (ctxTimeout , obj .Spec .Insecure )
314
-
315
315
// Generate the registry credential keychain either from static credentials or using cloud OIDC
316
316
keychain , err := r .keychain (ctx , obj )
317
317
if err != nil {
@@ -322,10 +322,10 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
322
322
conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Err .Error ())
323
323
return sreconcile .ResultEmpty , e
324
324
}
325
- options = append (options , crane .WithAuthFromKeychain (keychain ))
326
325
327
326
if _ , ok := keychain .(soci.Anonymous ); obj .Spec .Provider != sourcev1 .GenericOCIProvider && ok {
328
- auth , authErr := oidcAuth (ctxTimeout , obj .Spec .URL , obj .Spec .Provider )
327
+ var authErr error
328
+ auth , authErr = oidcAuth (ctxTimeout , obj .Spec .URL , obj .Spec .Provider )
329
329
if authErr != nil && ! errors .Is (authErr , oci .ErrUnconfiguredProvider ) {
330
330
e := serror .NewGeneric (
331
331
fmt .Errorf ("failed to get credential from %s: %w" , obj .Spec .Provider , authErr ),
@@ -334,9 +334,6 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
334
334
conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Err .Error ())
335
335
return sreconcile .ResultEmpty , e
336
336
}
337
- if auth != nil {
338
- options = append (options , crane .WithAuth (auth ))
339
- }
340
337
}
341
338
342
339
// Generate the transport for remote operations
@@ -349,12 +346,11 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
349
346
conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Err .Error ())
350
347
return sreconcile .ResultEmpty , e
351
348
}
352
- if transport != nil {
353
- options = append (options , crane .WithTransport (transport ))
354
- }
349
+
350
+ opts := makeRemoteOptions (ctx , obj , transport , keychain , auth )
355
351
356
352
// Determine which artifact revision to pull
357
- url , err := r .getArtifactURL (obj , options )
353
+ url , err := r .getArtifactURL (obj , opts . craneOpts )
358
354
if err != nil {
359
355
if _ , ok := err .(invalidOCIURLError ); ok {
360
356
e := serror .NewStalling (
@@ -372,7 +368,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
372
368
}
373
369
374
370
// Get the upstream revision from the artifact digest
375
- revision , err := r .getRevision (url , options )
371
+ revision , err := r .getRevision (url , opts . craneOpts )
376
372
if err != nil {
377
373
e := serror .NewGeneric (
378
374
fmt .Errorf ("failed to determine artifact digest: %w" , err ),
@@ -403,7 +399,18 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
403
399
} else if ! obj .GetArtifact ().HasRevision (revision ) ||
404
400
conditions .GetObservedGeneration (obj , sourcev1 .SourceVerifiedCondition ) != obj .Generation ||
405
401
conditions .IsFalse (obj , sourcev1 .SourceVerifiedCondition ) {
406
- err := r .verifySignature (ctx , obj , url , keychain )
402
+
403
+ // Insecure is not supported for verification
404
+ if obj .Spec .Insecure {
405
+ e := serror .NewGeneric (
406
+ fmt .Errorf ("cosign does not support insecure registries" ),
407
+ sourcev1 .VerificationError ,
408
+ )
409
+ conditions .MarkFalse (obj , sourcev1 .SourceVerifiedCondition , e .Reason , e .Err .Error ())
410
+ return sreconcile .ResultEmpty , e
411
+ }
412
+
413
+ err := r .verifySignature (ctx , obj , url , opts .verifyOpts ... )
407
414
if err != nil {
408
415
provider := obj .Spec .Verify .Provider
409
416
if obj .Spec .Verify .SecretRef == nil {
@@ -429,7 +436,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
429
436
}
430
437
431
438
// Pull artifact from the remote container registry
432
- img , err := crane .Pull (url , options ... )
439
+ img , err := crane .Pull (url , opts . craneOpts ... )
433
440
if err != nil {
434
441
e := serror .NewGeneric (
435
442
fmt .Errorf ("failed to pull artifact from '%s': %w" , obj .Spec .URL , err ),
@@ -589,15 +596,15 @@ func (r *OCIRepositoryReconciler) digestFromRevision(revision string) string {
589
596
590
597
// verifySignature verifies the authenticity of the given image reference url. First, it tries using a key
591
598
// if a secret with a valid public key is provided. If not, it falls back to a keyless approach for verification.
592
- func (r * OCIRepositoryReconciler ) verifySignature (ctx context.Context , obj * sourcev1.OCIRepository , url string , keychain authn. Keychain ) error {
599
+ func (r * OCIRepositoryReconciler ) verifySignature (ctx context.Context , obj * sourcev1.OCIRepository , url string , opt ... remote. Option ) error {
593
600
ctxTimeout , cancel := context .WithTimeout (ctx , obj .Spec .Timeout .Duration )
594
601
defer cancel ()
595
602
596
603
provider := obj .Spec .Verify .Provider
597
604
switch provider {
598
605
case "cosign" :
599
606
defaultCosignOciOpts := []soci.Options {
600
- soci .WithAuthnKeychain ( keychain ),
607
+ soci .WithRemoteOptions ( opt ... ),
601
608
}
602
609
603
610
ref , err := name .ParseReference (url )
@@ -857,21 +864,6 @@ func oidcAuth(ctx context.Context, url, provider string) (authn.Authenticator, e
857
864
return login .NewManager ().Login (ctx , u , ref , opts )
858
865
}
859
866
860
- // craneOptions sets the auth headers, timeout and user agent
861
- // for all operations against remote container registries.
862
- func (r * OCIRepositoryReconciler ) craneOptions (ctx context.Context , insecure bool ) []crane.Option {
863
- options := []crane.Option {
864
- crane .WithContext (ctx ),
865
- crane .WithUserAgent (oci .UserAgent ),
866
- }
867
-
868
- if insecure {
869
- options = append (options , crane .Insecure )
870
- }
871
-
872
- return options
873
- }
874
-
875
867
// reconcileStorage ensures the current state of the storage matches the
876
868
// desired and previously observed state.
877
869
//
@@ -1166,3 +1158,53 @@ func (r *OCIRepositoryReconciler) calculateContentConfigChecksum(obj *sourcev1.O
1166
1158
1167
1159
return fmt .Sprintf ("sha256:%x" , sha256 .Sum256 (c ))
1168
1160
}
1161
+
1162
+ // craneOptions sets the auth headers, timeout and user agent
1163
+ // for all operations against remote container registries.
1164
+ func craneOptions (ctx context.Context , insecure bool ) []crane.Option {
1165
+ options := []crane.Option {
1166
+ crane .WithContext (ctx ),
1167
+ crane .WithUserAgent (oci .UserAgent ),
1168
+ }
1169
+
1170
+ if insecure {
1171
+ options = append (options , crane .Insecure )
1172
+ }
1173
+
1174
+ return options
1175
+ }
1176
+
1177
+ // makeRemoteOptions returns a remoteOptions struct with the authentication and transport options set.
1178
+ // The returned struct can be used to interact with a remote registry using go-containerregistry based libraries.
1179
+ func makeRemoteOptions (ctxTimeout context.Context , obj * sourcev1.OCIRepository , transport http.RoundTripper ,
1180
+ keychain authn.Keychain , auth authn.Authenticator ) remoteOptions {
1181
+ o := remoteOptions {
1182
+ craneOpts : craneOptions (ctxTimeout , obj .Spec .Insecure ),
1183
+ verifyOpts : []remote.Option {},
1184
+ }
1185
+
1186
+ if transport != nil {
1187
+ o .craneOpts = append (o .craneOpts , crane .WithTransport (transport ))
1188
+ o .verifyOpts = append (o .verifyOpts , remote .WithTransport (transport ))
1189
+ }
1190
+
1191
+ if auth != nil {
1192
+ // auth take precedence over keychain here as we expect the caller to set
1193
+ // the auth only if it is required.
1194
+ o .verifyOpts = append (o .verifyOpts , remote .WithAuth (auth ))
1195
+ o .craneOpts = append (o .craneOpts , crane .WithAuth (auth ))
1196
+ return o
1197
+ }
1198
+
1199
+ o .verifyOpts = append (o .verifyOpts , remote .WithAuthFromKeychain (keychain ))
1200
+ o .craneOpts = append (o .craneOpts , crane .WithAuthFromKeychain (keychain ))
1201
+
1202
+ return o
1203
+ }
1204
+
1205
+ // remoteOptions contains the options to interact with a remote registry.
1206
+ // It can be used to pass options to go-containerregistry based libraries.
1207
+ type remoteOptions struct {
1208
+ craneOpts []crane.Option
1209
+ verifyOpts []remote.Option
1210
+ }
0 commit comments