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:
parent
9fde4fd6a1
commit
9f3fc941ef
10 changed files with 156 additions and 11 deletions
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue