1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-30 19:35:06 +00:00

Fix keyless attest (#3219)

* allow root cert for keyless attestations checks

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* add logs and improve var names

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* make fmt

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* handle err in sig loading

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

Co-authored-by: Sambhav Kothari <sambhavs.email@gmail.com>
This commit is contained in:
Jim Bugwadia 2022-02-13 20:35:11 -08:00 committed by GitHub
parent 14111aaa05
commit bd1a145678
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 29 deletions

View file

@ -9,6 +9,8 @@ import (
"fmt"
"strings"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/sigstore/cosign/cmd/cosign/cli/rekor"
"github.com/sigstore/cosign/cmd/cosign/cli/fulcio"
@ -145,23 +147,32 @@ func getFulcioRoots(roots []byte) (*x509.CertPool, error) {
// FetchAttestations retrieves signed attestations and decodes them into in-toto statements
// https://github.com/in-toto/attestation/blob/main/spec/README.md#statement
func FetchAttestations(imageRef string, key string, repository string, log logr.Logger) ([]map[string]interface{}, error) {
func FetchAttestations(imageRef string, imageVerify *v1.ImageVerification, log logr.Logger) ([]map[string]interface{}, error) {
ctx := context.Background()
var pubKey signature.Verifier
var err error
if strings.HasPrefix(key, "-----BEGIN PUBLIC KEY-----") {
pubKey, err = decodePEM([]byte(key))
if err != nil {
return nil, errors.Wrap(err, "decode pem")
cosignOpts := &cosign.CheckOpts{
ClaimVerifier: cosign.IntotoSubjectClaimVerifier,
}
if imageVerify.Key != "" {
if strings.HasPrefix(imageVerify.Key, "-----BEGIN PUBLIC KEY-----") {
cosignOpts.SigVerifier, err = decodePEM([]byte(imageVerify.Key))
} else {
cosignOpts.SigVerifier, err = sigs.PublicKeyFromKeyRef(ctx, imageVerify.Key)
}
} else {
pubKey, err = sigs.PublicKeyFromKeyRef(ctx, key)
if err != nil {
return nil, errors.Wrap(err, "loading public key")
cosignOpts.CertEmail = ""
cosignOpts.RootCerts, err = getFulcioRoots([]byte(imageVerify.Roots))
if err == nil {
cosignOpts.RekorClient, err = rekor.NewClient("https://rekor.sigstore.dev")
}
}
if err != nil {
return nil, errors.Wrap(err, "loading credentials")
}
var opts []remote.Option
ro := options.RegistryOptions{}
@ -170,20 +181,14 @@ func FetchAttestations(imageRef string, key string, repository string, log logr.
return nil, errors.Wrap(err, "constructing client options")
}
opts = append(opts, remote.WithRemoteOptions(gcrremote.WithAuthFromKeychain(registryclient.DefaultKeychain)))
if repository != "" {
signatureRepo, err := name.NewRepository(repository)
if imageVerify.Repository != "" {
signatureRepo, err := name.NewRepository(imageVerify.Repository)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse signature repository %s", repository)
return nil, errors.Wrapf(err, "failed to parse signature repository %s", imageVerify.Repository)
}
opts = append(opts, remote.WithTargetRepository(signatureRepo))
}
cosignOpts := &cosign.CheckOpts{
ClaimVerifier: cosign.IntotoSubjectClaimVerifier,
SigVerifier: pubKey,
RegistryClientOpts: opts,
}
ref, err := name.ParseReference(imageRef)
if err != nil {
return nil, errors.Wrap(err, "failed to parse image")

View file

@ -125,8 +125,6 @@ type imageVerifier struct {
func (iv *imageVerifier) verify(imageVerify *v1.ImageVerification, images map[string]*context.ImageInfo) {
imagePattern := imageVerify.Image
key := imageVerify.Key
repository := getSignatureRepository(imageVerify)
for _, imageInfo := range images {
image := imageInfo.String()
@ -150,7 +148,7 @@ func (iv *imageVerifier) verify(imageVerify *v1.ImageVerification, images map[st
iv.patchDigest(imageInfo, digest, ruleResp)
}
} else {
ruleResp = iv.attestImage(repository, key, imageInfo, imageVerify.Attestations)
ruleResp = iv.attestImage(imageVerify, imageInfo)
}
iv.resp.PolicyResponse.Rules = append(iv.resp.PolicyResponse.Rules, *ruleResp)
@ -235,11 +233,11 @@ func makeAddDigestPatch(imageInfo *context.ImageInfo, digest string) ([]byte, er
return json.Marshal(patch)
}
func (iv *imageVerifier) attestImage(repository, key string, imageInfo *context.ImageInfo, attestationChecks []*v1.Attestation) *response.RuleResponse {
func (iv *imageVerifier) attestImage(imageVerify *v1.ImageVerification, imageInfo *context.ImageInfo) *response.RuleResponse {
image := imageInfo.String()
start := time.Now()
statements, err := cosign.FetchAttestations(image, key, repository, iv.logger)
statements, err := cosign.FetchAttestations(image, imageVerify, iv.logger)
if err != nil {
iv.logger.Info("failed to fetch attestations", "image", image, "error", err, "duration", time.Since(start).Seconds())
return ruleError(iv.rule, utils.ImageVerify, fmt.Sprintf("failed to fetch attestations for %s", image), err)
@ -248,7 +246,7 @@ func (iv *imageVerifier) attestImage(repository, key string, imageInfo *context.
iv.logger.V(4).Info("received attestations", "statements", statements)
statementsByPredicate := buildStatementMap(statements)
for _, ac := range attestationChecks {
for _, ac := range imageVerify.Attestations {
statements := statementsByPredicate[ac.PredicateType]
if statements == nil {
msg := fmt.Sprintf("predicate type %s not found", ac.PredicateType)

View file

@ -512,13 +512,13 @@ func buildPolicyResults(engineResponses []*response.EngineResponse, testResults
}
var result report.PolicyReportResult
var resultsKey []string
var resultsKeys []string
var resultKey string
resultsKey = GetAllPossibleResultsKey("", info.PolicyName, rule.Name, infoResult.Resource.Namespace, infoResult.Resource.Kind, infoResult.Resource.Name)
for _, resultK := range resultsKey {
if val, ok := results[resultK]; ok {
resultsKeys = GetAllPossibleResultsKey("", info.PolicyName, rule.Name, infoResult.Resource.Namespace, infoResult.Resource.Kind, infoResult.Resource.Name)
for _, key := range resultsKeys {
if val, ok := results[key]; ok {
result = val
resultKey = resultK
resultKey = key
} else {
continue
}
@ -779,6 +779,7 @@ func printTestResult(resps map[string]report.PolicyReportResult, testResults []T
if val, ok := resps[resultKey]; ok {
testRes = val
} else {
log.Log.V(2).Info("result not found", "key", resultKey)
res.Result = boldYellow.Sprintf("Not found")
rc.Fail++
table = append(table, res)
@ -799,6 +800,7 @@ func printTestResult(resps map[string]report.PolicyReportResult, testResults []T
rc.Pass++
}
} else {
log.Log.V(2).Info("result mismatch", "expected", testRes.Result, "received", v.Result, "key", resultKey)
res.Result = boldRed.Sprintf("Fail")
rc.Fail++
}