Skip to content

Commit f1a8289

Browse files
feat(notation): add notation back to ocirepository_controller
During the merge from main the ocirepository_controller.go was moved and git determined the file was delete. I took the changes from main and I have added back the logic for checking against notation. I have also add the ability to use insecure registries and registries running on localhost:port. Signed-off-by: Jason <jagoodse@microsoft.com>
1 parent 83b3956 commit f1a8289

File tree

2 files changed

+86
-4
lines changed

2 files changed

+86
-4
lines changed

internal/controller/ocirepository_controller.go

+69
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package controller
1919
import (
2020
"context"
2121
cryptotls "crypto/tls"
22+
"encoding/json"
2223
"errors"
2324
"fmt"
2425
"io"
@@ -35,6 +36,7 @@ import (
3536
"github.com/google/go-containerregistry/pkg/name"
3637
gcrv1 "github.com/google/go-containerregistry/pkg/v1"
3738
"github.com/google/go-containerregistry/pkg/v1/remote"
39+
"github.com/notaryproject/notation-go/verifier/trustpolicy"
3840
"github.com/sigstore/cosign/v2/pkg/cosign"
3941
corev1 "k8s.io/api/core/v1"
4042
"k8s.io/apimachinery/pkg/runtime"
@@ -689,6 +691,73 @@ func (r *OCIRepositoryReconciler) verifySignature(ctx context.Context, obj *ociv
689691
}
690692

691693
return fmt.Errorf("no matching signatures were found for '%s'", ref)
694+
695+
case "notation":
696+
// get the public keys from the given secret
697+
if secretRef := obj.Spec.Verify.SecretRef; secretRef != nil {
698+
certSecretName := types.NamespacedName{
699+
Namespace: obj.Namespace,
700+
Name: secretRef.Name,
701+
}
702+
703+
var pubSecret corev1.Secret
704+
if err := r.Get(ctxTimeout, certSecretName, &pubSecret); err != nil {
705+
return err
706+
}
707+
708+
var doc trustpolicy.Document
709+
710+
signatureVerified := false
711+
for k, data := range pubSecret.Data {
712+
if strings.HasSuffix(k, ".json") {
713+
if err := json.Unmarshal(data, &doc); err != nil {
714+
return err
715+
}
716+
}
717+
}
718+
719+
defaultNotaryOciOpts := []soci.NotationOptions{
720+
soci.WithTrustStore(&doc),
721+
soci.WithNotaryRemoteOptions(opt...),
722+
}
723+
724+
keychain, err := r.keychain(ctx, obj)
725+
if err != nil {
726+
e := serror.NewGeneric(
727+
fmt.Errorf("failed to get credential: %w", err),
728+
sourcev1.AuthenticationFailedReason,
729+
)
730+
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
731+
return e
732+
}
733+
734+
for k, data := range pubSecret.Data {
735+
// search for public keys in the secret
736+
if strings.HasSuffix(k, ".crt") || strings.HasSuffix(k, ".pem") {
737+
738+
verifier, err := soci.NewNotaryVerifier(append(defaultNotaryOciOpts, soci.WithNotaryPublicKey(data), soci.WithNotaryKeychain(keychain), soci.WithInsecureRegistry(obj.Spec.Insecure))...)
739+
if err != nil {
740+
return err
741+
}
742+
743+
signatures, err := verifier.Verify(ctxTimeout, ref)
744+
if err != nil {
745+
continue
746+
}
747+
748+
if signatures {
749+
signatureVerified = true
750+
break
751+
}
752+
}
753+
}
754+
755+
if !signatureVerified {
756+
return fmt.Errorf("no matching signatures were found for '%s'", ref)
757+
}
758+
return nil
759+
}
760+
return nil
692761
}
693762

694763
return nil

internal/oci/notation.go

+17-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package oci
33
import (
44
"context"
55
"fmt"
6-
"log"
76
"net/http"
87
"os"
98
"strings"
@@ -30,11 +29,19 @@ type notationOptions struct {
3029
TrustStore *trustpolicy.Document
3130
Keychain authn.Keychain
3231
ROpt []remote.Option
32+
Insecure bool
3333
}
3434

3535
// NotationOptions is a function that configures the options applied to a notation verifier
3636
type NotationOptions func(opts *notationOptions)
3737

38+
// WithInsecureRegistry sets notation to verify against insecure registry.
39+
func WithInsecureRegistry(insecure bool) NotationOptions {
40+
return func(opts *notationOptions) {
41+
opts.Insecure = insecure
42+
}
43+
}
44+
3845
// WithTrustStore sets the trust store configuration.
3946
func WithTrustStore(trustStore *trustpolicy.Document) NotationOptions {
4047
return func(opts *notationOptions) {
@@ -70,6 +77,7 @@ type NotaryVerifier struct {
7077
auth authn.Keychain
7178
verifier *notation.Verifier
7279
opts []remote.Option
80+
insecure bool
7381
}
7482

7583
// NewNotaryVerifier initializes a new NotaryVerifier
@@ -99,6 +107,7 @@ func NewNotaryVerifier(opts ...NotationOptions) (*NotaryVerifier, error) {
99107
auth: o.Keychain,
100108
verifier: &verifier,
101109
opts: o.ROpt,
110+
insecure: o.Insecure,
102111
}, nil
103112
}
104113

@@ -111,6 +120,8 @@ func (v *NotaryVerifier) Verify(ctx context.Context, ref name.Reference) (bool,
111120
if err != nil {
112121
return false, err
113122
}
123+
remoteRepo.PlainHTTP = v.insecure
124+
114125
repo := registry.NewRepository(remoteRepo)
115126

116127
ss := stringResource{url}
@@ -141,13 +152,15 @@ func (v *NotaryVerifier) Verify(ctx context.Context, ref name.Reference) (bool,
141152

142153
i, err := remote.Image(ref, v.opts...)
143154

144-
log.Println(i.ConfigFile())
145155
d, err := i.Digest()
146156

147157
repoUrl := ""
148158

149-
if s := strings.Split(url, ":"); len(s) == 2 && !strings.Contains(url, "@") {
150-
repoUrl = fmt.Sprintf("%s@%s", s[0], d)
159+
lastIndex := strings.LastIndex(url, ":")
160+
firstPart := url[:lastIndex]
161+
162+
if s := strings.Split(url, ":"); len(s) >= 2 && !strings.Contains(url, "@") {
163+
repoUrl = fmt.Sprintf("%s@%s", firstPart, d)
151164
}
152165

153166
verififyOptions := notation.VerifyOptions{

0 commit comments

Comments
 (0)