1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-13 19:28:55 +00:00

[imageVerify]: adding digestMutate to simplify tag-to-digest mutation (#3531)

* added digestMutate

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* rebase

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* setting always to true

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* small nit

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* make codegen

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* crds & failing rule if mutation fails

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* adding new func to fetch digest and changing naming to mutateDigest

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* small nits

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* generating crds

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* minor nit

Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

* correcting error format
Signed-off-by: Naman Lakhwani <namanlakhwani@gmail.com>

Co-authored-by: Jim Bugwadia <jim@nirmata.com>
This commit is contained in:
Naman Lakhwani 2022-04-22 13:38:49 +05:30 committed by GitHub
parent 9fde4fd6a1
commit 9f3fc941ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 156 additions and 11 deletions

View file

@ -65,6 +65,12 @@ type ImageVerification struct {
// If specified Repository will override the default OCI image repository configured for the installation.
// The repository can also be overridden per Attestor or Attestation.
Repository string `json:"repository,omitempty" yaml:"repository,omitempty"`
// MutateDigest is an optional field which handles the tag-to-digest mutation for the provided image paths.
// Defaults to true.
// +kubebuilder:default=true
// +kubebuilder:validation:Optional
MutateDigest *bool `json:"mutateDigest,omitempty" yaml:"mutateDigest,omitempty"`
}
type AttestorSet struct {

View file

@ -662,6 +662,11 @@ func (in *ImageVerification) DeepCopyInto(out *ImageVerification) {
(*out)[key] = val
}
}
if in.MutateDigest != nil {
in, out := &in.MutateDigest, &out.MutateDigest
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageVerification.

View file

@ -1414,6 +1414,10 @@ spec:
key:
description: Key is the PEM encoded public key that the image or attestation is signed with. Deprecated. Use StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles the tag-to-digest mutation for the provided image paths. Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository to use for image signatures and attestations that match this rule. If specified Repository will override the default OCI image repository configured for the installation. The repository can also be overridden per Attestor or Attestation.
type: string
@ -2876,6 +2880,10 @@ spec:
key:
description: Key is the PEM encoded public key that the image or attestation is signed with. Deprecated. Use StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles the tag-to-digest mutation for the provided image paths. Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository to use for image signatures and attestations that match this rule. If specified Repository will override the default OCI image repository configured for the installation. The repository can also be overridden per Attestor or Attestation.
type: string
@ -5047,6 +5055,10 @@ spec:
key:
description: Key is the PEM encoded public key that the image or attestation is signed with. Deprecated. Use StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles the tag-to-digest mutation for the provided image paths. Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository to use for image signatures and attestations that match this rule. If specified Repository will override the default OCI image repository configured for the installation. The repository can also be overridden per Attestor or Attestation.
type: string
@ -6509,6 +6521,10 @@ spec:
key:
description: Key is the PEM encoded public key that the image or attestation is signed with. Deprecated. Use StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles the tag-to-digest mutation for the provided image paths. Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository to use for image signatures and attestations that match this rule. If specified Repository will override the default OCI image repository configured for the installation. The repository can also be overridden per Attestor or Attestation.
type: string

View file

@ -2281,6 +2281,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match
@ -4654,6 +4660,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match

View file

@ -2282,6 +2282,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match
@ -4656,6 +4662,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match

View file

@ -2298,6 +2298,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match
@ -4671,6 +4677,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match
@ -7932,6 +7944,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match
@ -10306,6 +10324,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match

View file

@ -2287,6 +2287,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match
@ -4660,6 +4666,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match
@ -7897,6 +7909,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match
@ -10271,6 +10289,12 @@ spec:
image or attestation is signed with. Deprecated. Use
StaticKeyAttestor instead.
type: string
mutateDigest:
default: true
description: MutateDigest is an optional field which handles
the tag-to-digest mutation for the provided image paths.
Defaults to true.
type: boolean
repository:
description: Repository is an optional alternate OCI repository
to use for image signatures and attestations that match

View file

@ -1611,6 +1611,18 @@ If specified Repository will override the default OCI image repository configure
The repository can also be overridden per Attestor or Attestation.</p>
</td>
</tr>
<tr>
<td>
<code>mutateDigest</code></br>
<em>
bool
</em>
</td>
<td>
<p>MutateDigest is an optional field which handles the tag-to-digest mutation for the provided image paths.
Defaults to true.</p>
</td>
</tr>
</tbody>
</table>
<hr />

View file

@ -7,6 +7,8 @@ import (
"time"
"github.com/go-logr/logr"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/kyverno/go-wildcard"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/autogen"
@ -154,15 +156,35 @@ func (iv *imageVerifier) verify(imageVerify *v1.ImageVerification, images map[st
continue
}
if imageVerify.MutateDigest == nil {
mutate := true
imageVerify.MutateDigest = &mutate
}
var ruleResp *response.RuleResponse
if len(imageVerify.Attestations) == 0 {
var digest string
ruleResp, digest = iv.verifySignatures(imageVerify, imageInfo)
if ruleResp.Status == response.RuleStatusPass {
iv.patchDigest(path, imageInfo, digest, ruleResp)
if imageInfo.Digest == "" && *imageVerify.MutateDigest && ruleResp.Status == response.RuleStatusPass {
err := iv.patchDigest(path, imageInfo, digest, ruleResp)
if err != nil {
ruleResp = ruleResponse(iv.rule, response.ImageVerify, err.Error(), response.RuleStatusFail)
}
}
} else {
ruleResp = iv.attestImage(imageVerify, imageInfo)
if imageInfo.Digest == "" && *imageVerify.MutateDigest && ruleResp.Status == response.RuleStatusPass {
digest, err := fetchImageDigest(imageInfo.String())
if err != nil {
msg := fmt.Sprintf("fetching image digest from registry error: %s", err)
ruleResp = ruleResponse(iv.rule, response.ImageVerify, msg, response.RuleStatusFail)
} else {
err = iv.patchDigest(path, imageInfo, digest, ruleResp)
if err != nil {
ruleResp = ruleResponse(iv.rule, response.ImageVerify, err.Error(), response.RuleStatusFail)
}
}
}
}
iv.resp.PolicyResponse.Rules = append(iv.resp.PolicyResponse.Rules, *ruleResp)
@ -171,6 +193,18 @@ func (iv *imageVerifier) verify(imageVerify *v1.ImageVerification, images map[st
}
}
func fetchImageDigest(ref string) (string, error) {
parsedRef, err := name.ParseReference(ref)
if err != nil {
return "", fmt.Errorf("failed to parse image reference: %s, error: %v", ref, err)
}
desc, err := remote.Get(parsedRef, remote.WithAuthFromKeychain(registryclient.DefaultKeychain))
if err != nil {
return "", fmt.Errorf("failed to fetch image reference: %s, error: %v", ref, err)
}
return desc.Digest.String(), nil
}
func imageMatches(image string, imagePatterns []string) bool {
for _, imagePattern := range imagePatterns {
if wildcard.Match(imagePattern, image) {
@ -348,16 +382,15 @@ func (iv *imageVerifier) buildOptionsAndPath(attestor *v1.Attestor, imageVerify
return opts, path
}
func (iv *imageVerifier) patchDigest(path string, imageInfo kubeutils.ImageInfo, digest string, ruleResp *response.RuleResponse) {
if imageInfo.Digest == "" {
patch, err := makeAddDigestPatch(path, imageInfo, digest)
if err != nil {
iv.logger.Error(err, "failed to patch image with digest", "image", imageInfo.String(), "jsonPath", path)
} else {
iv.logger.V(4).Info("patching verified image with digest", "patch", string(patch))
ruleResp.Patches = [][]byte{patch}
}
func (iv *imageVerifier) patchDigest(path string, imageInfo kubeutils.ImageInfo, digest string, ruleResp *response.RuleResponse) error {
patch, err := makeAddDigestPatch(path, imageInfo, digest)
if err != nil {
return errors.Wrapf(err, "failed to patch image with digest. image: %s, jsonPath: %s", imageInfo.String(), path)
} else {
iv.logger.V(4).Info("patching verified image with digest", "patch", string(patch))
ruleResp.Patches = [][]byte{patch}
}
return nil
}
func makeAddDigestPatch(path string, imageInfo kubeutils.ImageInfo, digest string) ([]byte, error) {

View file

@ -114,6 +114,7 @@ func fetchImageData(logger logr.Logger, entry kyverno.ContextEntry, ctx *PolicyC
return imageData, nil
}
// FetchImageDataMap fetches image information from the remote registry.
func fetchImageDataMap(ref string) (interface{}, error) {
parsedRef, err := name.ParseReference(ref)
if err != nil {