Skip to content

Commit 3a2c636

Browse files
committed
Refactor internal OCI package
Signed-off-by: Stefan Prodan <[email protected]>
1 parent 21af88f commit 3a2c636

File tree

5 files changed

+35
-33
lines changed

5 files changed

+35
-33
lines changed

controllers/ocirepository_controller.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
311311
}
312312
options = append(options, crane.WithAuthFromKeychain(keychain))
313313

314-
if _, ok := keychain.(util.Anonymous); obj.Spec.Provider != sourcev1.GenericOCIProvider && ok {
314+
if _, ok := keychain.(soci.Anonymous); obj.Spec.Provider != sourcev1.GenericOCIProvider && ok {
315315
auth, authErr := oidcAuth(ctxTimeout, obj.Spec.URL, obj.Spec.Provider)
316316
if authErr != nil && !errors.Is(authErr, oci.ErrUnconfiguredProvider) {
317317
e := serror.NewGeneric(
@@ -410,21 +410,25 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
410410
}()
411411

412412
// Extract the content of the first artifact layer
413-
if !obj.GetArtifact().HasRevision(revision) {
413+
if !obj.GetArtifact().HasRevision(revision) || obj.Status.ObservedGeneration != obj.Generation {
414414
if obj.Spec.Verify != nil {
415415
provider := obj.Spec.Verify.Provider
416416
err := r.verifyOCISourceSignature(ctx, obj, url, keychain)
417417
if err != nil {
418418
e := serror.NewGeneric(
419-
fmt.Errorf("failed to verify OCI image signature '%s' using provider '%s': %w", url, provider, err),
419+
fmt.Errorf("failed to verify the signature using provider '%s': %w", provider, err),
420420
sourcev1.VerificationError,
421421
)
422422
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, e.Err.Error())
423423
return sreconcile.ResultEmpty, e
424424
}
425425

426-
conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, meta.SucceededReason, "OCI image %s with digest %s verified.", url, revision)
426+
conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of digest %s", revision)
427+
} else {
428+
// Remove old observations if verification was disabled
429+
conditions.Delete(obj, sourcev1.SourceVerifiedCondition)
427430
}
431+
428432
layers, err := img.Layers()
429433
if err != nil {
430434
e := serror.NewGeneric(
@@ -512,7 +516,6 @@ func (r *OCIRepositoryReconciler) verifyOCISourceSignature(ctx context.Context,
512516
case "cosign":
513517
defaultCosignOciOpts := []soci.Options{
514518
soci.WithAuthnKeychain(keychain),
515-
soci.WithContext(ctxTimeout),
516519
}
517520

518521
ref, err := name.ParseReference(url)
@@ -536,12 +539,12 @@ func (r *OCIRepositoryReconciler) verifyOCISourceSignature(ctx context.Context,
536539
for k, data := range pubSecret.Data {
537540
// search for public keys in the secret
538541
if strings.HasSuffix(k, ".pub") {
539-
verifier, err := soci.New(append(defaultCosignOciOpts, soci.WithPublicKey(data))...)
542+
verifier, err := soci.NewVerifier(ctxTimeout, append(defaultCosignOciOpts, soci.WithPublicKey(data))...)
540543
if err != nil {
541544
return err
542545
}
543546

544-
signatures, _, err := verifier.VerifyImageSignatures(ref)
547+
signatures, _, err := verifier.VerifyImageSignatures(ctxTimeout, ref)
545548
if err != nil {
546549
continue
547550
}
@@ -562,12 +565,12 @@ func (r *OCIRepositoryReconciler) verifyOCISourceSignature(ctx context.Context,
562565

563566
// if no secret is provided, try keyless verification
564567
ctrl.LoggerFrom(ctx).Info("no secret reference is provided, trying to verify the image using keyless approach")
565-
verifier, err := soci.New(defaultCosignOciOpts...)
568+
verifier, err := soci.NewVerifier(ctxTimeout, defaultCosignOciOpts...)
566569
if err != nil {
567570
return err
568571
}
569572

570-
signatures, _, err := verifier.VerifyImageSignatures(ref)
573+
signatures, _, err := verifier.VerifyImageSignatures(ctxTimeout, ref)
571574
if err != nil {
572575
return err
573576
}
@@ -689,7 +692,7 @@ func (r *OCIRepositoryReconciler) keychain(ctx context.Context, obj *sourcev1.OC
689692

690693
// if no pullsecrets available return an AnonymousKeychain
691694
if len(pullSecretNames) == 0 {
692-
return util.Anonymous{}, nil
695+
return soci.Anonymous{}, nil
693696
}
694697

695698
// lookup image pull secrets

controllers/ocirepository_controller_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,22 +1042,22 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
10421042
assertConditions: []metav1.Condition{
10431043
*conditions.TrueCondition(meta.ReconcilingCondition, "NewRevision", "new digest '<digest>' for '<url>'"),
10441044
*conditions.TrueCondition(sourcev1.ArtifactOutdatedCondition, "NewRevision", "new digest '<digest>' for '<url>'"),
1045-
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "OCI image <url> with digest <digest> verified."),
1045+
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of digest <digest>"),
10461046
},
10471047
},
10481048
{
1049-
name: "not signed image should not pass verification",
1049+
name: "unsigned image should not pass verification",
10501050
reference: &sourcev1.OCIRepositoryRef{
10511051
Tag: "6.1.5",
10521052
},
10531053
digest: img5.digest.Hex,
10541054
wantErr: true,
1055-
wantErrMsg: "failed to verify OCI image signature '<url>' using provider 'cosign': no matching signatures were found for '<url>",
1055+
wantErrMsg: "failed to verify the signature using provider 'cosign': no matching signatures were found for '<url>'",
10561056
want: sreconcile.ResultEmpty,
10571057
assertConditions: []metav1.Condition{
10581058
*conditions.TrueCondition(meta.ReconcilingCondition, "NewRevision", "new digest '<digest>' for '<url>'"),
10591059
*conditions.TrueCondition(sourcev1.ArtifactOutdatedCondition, "NewRevision", "new digest '<digest>' for '<url>'"),
1060-
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "failed to verify OCI image signature '<url>' using provider '<provider>': no matching signatures were found for '<url>'"),
1060+
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "failed to verify the signature using provider '<provider>': no matching signatures were found for '<url>'"),
10611061
},
10621062
},
10631063
}

docs/spec/v1beta2/ocirepositories.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ data:
455455
key2.pub: <BASE64>
456456
```
457457

458-
Note that the keys must have the `.pub` extension for Flux to make user of them.
458+
Note that the keys must have the `.pub` extension for Flux to make use of them.
459459

460460
#### Keyless verification
461461

@@ -482,7 +482,7 @@ The controller verifies the signatures using the Fulcio root CA and the Rekor
482482
instance hosted at [rekor.sigstore.dev](https://rekor.sigstore.dev/).
483483

484484
Note that keyless verification is an **experimental feature**, using
485-
custom root CAs or self-hosted Rekor instances are not currency supported.
485+
custom root CAs or self-hosted Rekor instances are not currently supported.
486486

487487
### Suspend
488488

@@ -839,6 +839,14 @@ and is only present on the OCIRepository while the status value is `"True"`.
839839
There may be more arbitrary values for the `reason` field to provide accurate
840840
reason for a condition.
841841

842+
In addition to the above Condition types, when the signature
843+
[verification](#verification) fails. A condition with
844+
the following attributes is added to the GitRepository's `.status.conditions`:
845+
846+
- `type: SourceVerified`
847+
- `status: "False"`
848+
- `reason: VerificationError`
849+
842850
While the OCIRepository has one or more of these Conditions, the controller
843851
will continue to attempt to produce an Artifact for the resource with an
844852
exponential backoff, until it succeeds and the OCIRepository is marked as

internal/util/auth.go renamed to internal/oci/auth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package util
17+
package oci
1818

1919
import "github.com/google/go-containerregistry/pkg/authn"
2020

internal/oci/oci.go renamed to internal/oci/verifier.go

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import (
3838
type options struct {
3939
PublicKey []byte
4040
Keychain authn.Keychain
41-
Context context.Context
4241
}
4342

4443
// Options is a function that configures the options applied to a Verifier.
@@ -57,20 +56,13 @@ func WithAuthnKeychain(keychain authn.Keychain) Options {
5756
}
5857
}
5958

60-
func WithContext(ctx context.Context) Options {
61-
return func(opts *options) {
62-
opts.Context = ctx
63-
}
64-
}
65-
6659
// Verifier is a struct which is responsible for executing verification logic.
6760
type Verifier struct {
68-
opts *cosign.CheckOpts
69-
context context.Context
61+
opts *cosign.CheckOpts
7062
}
7163

72-
// New initializes a new Verifier.
73-
func New(opts ...Options) (*Verifier, error) {
64+
// NewVerifier initializes a new Verifier.
65+
func NewVerifier(ctx context.Context, opts ...Options) (*Verifier, error) {
7466
o := options{}
7567
for _, opt := range opts {
7668
opt(&o)
@@ -79,7 +71,7 @@ func New(opts ...Options) (*Verifier, error) {
7971
checkOpts := &cosign.CheckOpts{}
8072

8173
ro := coptions.RegistryOptions{}
82-
co, err := ro.ClientOpts(o.Context)
74+
co, err := ro.ClientOpts(ctx)
8375
if err != nil {
8476
return nil, err
8577
}
@@ -124,12 +116,11 @@ func New(opts ...Options) (*Verifier, error) {
124116
}
125117

126118
return &Verifier{
127-
opts: checkOpts,
128-
context: o.Context,
119+
opts: checkOpts,
129120
}, nil
130121
}
131122

132123
// VerifyImageSignatures verify the authenticity of the given ref OCI image.
133-
func (v *Verifier) VerifyImageSignatures(ref name.Reference) ([]oci.Signature, bool, error) {
134-
return cosign.VerifyImageSignatures(v.context, ref, v.opts)
124+
func (v *Verifier) VerifyImageSignatures(ctx context.Context, ref name.Reference) ([]oci.Signature, bool, error) {
125+
return cosign.VerifyImageSignatures(ctx, ref, v.opts)
135126
}

0 commit comments

Comments
 (0)