1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-07 00:17:13 +00:00
kyverno/pkg/imageverifiers/notary/notary.go
Vishal Choudhary 219f25ace2
feat: add notary verifier with tsa support (#12160)
* feat: add notary repository

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* feat: add notary verifier

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* feat: tests

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* feat: more tests

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: more tests

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: ci

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* feat: update types

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

---------

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>
Co-authored-by: shuting <shuting@nirmata.com>
2025-02-18 07:23:39 +00:00

123 lines
4 KiB
Go

package notary
import (
"context"
"fmt"
"github.com/go-logr/logr"
policiesv1alpha1 "github.com/kyverno/kyverno/api/policies.kyverno.io/v1alpha1"
"github.com/kyverno/kyverno/pkg/imagedataloader"
"github.com/kyverno/kyverno/pkg/logging"
"github.com/notaryproject/notation-go"
notationlog "github.com/notaryproject/notation-go/log"
"github.com/pkg/errors"
"go.uber.org/multierr"
)
func NewVerifier() *notaryVerifier {
return &notaryVerifier{
log: logging.WithName("Notary"),
}
}
type notaryVerifier struct {
log logr.Logger
}
func (v *notaryVerifier) VerifyImageSignature(ctx context.Context, image *imagedataloader.ImageData, attestor *policiesv1alpha1.Attestor) error {
if attestor.Notary == nil {
return fmt.Errorf("notary verifier only supports notary attestor")
}
logger := v.log.WithValues("image", image.Image, "digest", image.Digest, "attestor", attestor.Name)
logger.V(2).Info("verifying notary image signature", "image", image.Image)
vInfo, err := getVerificationInfo(image, attestor.Notary)
if err != nil {
err := errors.Wrapf(err, "failed to setup notation verification data")
logger.Error(err, "image verification failed")
return err
}
opts := notation.VerifyOptions{
ArtifactReference: image.WithDigest(image.Digest),
MaxSignatureAttempts: 10,
}
_, outcomes, err := notation.Verify(notationlog.WithLogger(ctx, NotaryLoggerAdapter(v.log.WithName("Notary Verifier Debug"))), vInfo.Verifier,
vInfo.Repo, opts)
if err != nil {
err := errors.Wrapf(err, "failed to verify image %s", image.Image)
logger.Error(err, "image verification failed")
return err
}
if err := checkVerificationOutcomes(outcomes); err != nil {
err := errors.Wrapf(err, "notation failed to verify signatures")
logger.Error(err, "image verification failed")
return err
}
return nil
}
func (v *notaryVerifier) VerifyAttestationSignature(ctx context.Context, image *imagedataloader.ImageData, attestation *policiesv1alpha1.Attestation, attestor *policiesv1alpha1.Attestor) error {
if attestation.Referrer == nil {
return fmt.Errorf("notary verifier only supports oci 1.1 referrers as attestations")
}
if attestor.Notary == nil {
return fmt.Errorf("notary verifier only supports notary attestor")
}
logger := v.log.WithValues("image", image.Image, "digest", image.Digest, "attestation", attestation.Name, "attestor", attestor.Name) // TODO: use attestor and attestation names
logger.V(2).Info("verifying notary image signature", "image", image.Image)
vInfo, err := getVerificationInfo(image, attestor.Notary)
if err != nil {
err := errors.Wrapf(err, "failed to setup notation verification data")
logger.Error(err, "image verification failed")
return err
}
referrers, err := image.FetchRefererrs(attestation.Referrer.Type)
if err != nil {
err := errors.Wrapf(err, "failed to fetch referrers")
logger.Error(err, "image attestation verification failed")
return err
}
var errs []error
for _, r := range referrers {
reference := image.WithDigest(r.Digest.String())
logger := logger.WithValues("attestation ref", reference)
logger.V(2).Info("verifying attestation")
opts := notation.VerifyOptions{
ArtifactReference: reference,
MaxSignatureAttempts: 10,
}
_, outcomes, err := notation.Verify(notationlog.WithLogger(ctx, NotaryLoggerAdapter(v.log.WithName("Notary Verifier Debug"))), vInfo.Verifier,
vInfo.Repo, opts)
if err != nil {
err := errors.Wrapf(err, "failed to verify attestation %s, digest %s", r.ArtifactType, r.Digest)
logger.Error(err, "attestation verification failed")
errs = append(errs, err)
continue
}
if err := checkVerificationOutcomes(outcomes); err != nil {
err := errors.Wrapf(err, "notation failed to verify attesattion signatures")
logger.Error(err, "attesatation verification failed")
errs = append(errs, err)
continue
}
image.AddVerifiedReferrer(r)
return nil
}
if len(errs) == 0 {
return fmt.Errorf("attestation verification failed, no attestations found for type: %s", attestation.Referrer.Type)
}
return multierr.Combine(errs...)
}