1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-24 08:36:46 +00:00

fix: use object key in json image verification (#12298)

This commit is contained in:
Vishal Choudhary 2025-03-06 01:23:19 +05:30 committed by GitHub
parent c0c9cec7c3
commit 32f13d5894
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 55 additions and 57 deletions

View file

@ -64,16 +64,12 @@ func (c *compiler) Compile(logger logr.Logger, ivpolicy *policiesv1alpha1.ImageV
options = append(options, cel.Variable(ObjectKey, cel.DynType))
options = append(options, cel.Variable(OldObjectKey, cel.DynType))
} else {
options = append(options, cel.Variable(RequestKey, cel.DynType))
options = append(options, cel.Variable(ObjectKey, cel.DynType))
}
for _, declType := range declTypes {
options = append(options, cel.Types(declType.CelType()))
}
if err != nil {
// TODO: proper error handling
panic(err)
}
options = append(options, imageverifierfunctions.Lib(logger, c.ictx, ivpolicy, c.lister))
env, err := base.Extend(options...)
if err != nil {
@ -94,7 +90,7 @@ func (c *compiler) Compile(logger logr.Logger, ivpolicy *policiesv1alpha1.ImageV
return nil, append(allErrs, errs...)
}
imageExtractors, errs := variables.CompileImageExtractors(path.Child("images"), ivpolicy.Spec.Images, c.reqGVR)
imageExtractors, errs := variables.CompileImageExtractors(path.Child("images"), ivpolicy.Spec.Images, c.reqGVR, options)
if errs != nil {
return nil, append(allErrs, errs...)
}

View file

@ -35,7 +35,7 @@ var (
Images: []policiesv1alpha1.Image{
{
Name: "bar",
Expression: "[request.foo.bar]",
Expression: "[object.foo.bar]",
},
},
Attestors: []policiesv1alpha1.Attestor{

View file

@ -73,10 +73,10 @@ func (c *compiledPolicy) Evaluate(ctx context.Context, ictx imagedataloader.Imag
data[ObjectKey] = objectVal
data[OldObjectKey] = oldObjectVal
} else {
data[RequestKey] = request
data[ObjectKey] = request
}
images, err := variables.ExtractImages(c.imageExtractors, request)
images, err := variables.ExtractImages(c.imageExtractors, data)
if err != nil {
return nil, err
}
@ -151,7 +151,7 @@ func (p *compiledPolicy) match(
data[NamespaceObjectKey] = namespaceVal
data[RequestKey] = requestVal.Object
} else {
data[RequestKey] = request
data[ObjectKey] = request
}
var errs []error

View file

@ -2,9 +2,7 @@ package variables
import (
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
"github.com/kyverno/kyverno/api/policies.kyverno.io/v1alpha1"
"github.com/kyverno/kyverno/pkg/cel/policy"
"github.com/kyverno/kyverno/pkg/cel/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
@ -60,10 +58,8 @@ type CompiledImageExtractor struct {
e cel.Program
}
func (c *CompiledImageExtractor) GetImages(request interface{}) (string, []string, error) {
out, _, err := c.e.Eval(map[string]any{
policy.RequestKey: request,
})
func (c *CompiledImageExtractor) GetImages(data map[string]any) (string, []string, error) {
out, _, err := c.e.Eval(data)
if err != nil {
return "", nil, err
}
@ -76,17 +72,14 @@ func (c *CompiledImageExtractor) GetImages(request interface{}) (string, []strin
return c.key, result, nil
}
func CompileImageExtractors(path *field.Path, imageExtractors []v1alpha1.Image, gvr *metav1.GroupVersionResource) ([]*CompiledImageExtractor, field.ErrorList) {
func CompileImageExtractors(path *field.Path, imageExtractors []v1alpha1.Image, gvr *metav1.GroupVersionResource, envOpts []cel.EnvOption) ([]*CompiledImageExtractor, field.ErrorList) {
var allErrs field.ErrorList
if gvr != nil {
imageExtractors = append(imageExtractors, getExtractorForGVR(gvr)...)
}
compiledMatches := make([]*CompiledImageExtractor, 0, len(imageExtractors))
e, err := cel.NewEnv(
// this uses dyn type to allow unstructured data
cel.Variable(policy.RequestKey, types.DynType),
)
e, err := cel.NewEnv(envOpts...)
if err != nil {
return nil, append(allErrs, field.Invalid(path, imageExtractors, err.Error()))
}
@ -111,10 +104,10 @@ func CompileImageExtractors(path *field.Path, imageExtractors []v1alpha1.Image,
return compiledMatches, nil
}
func ExtractImages(c []*CompiledImageExtractor, request interface{}) (map[string][]string, error) {
func ExtractImages(c []*CompiledImageExtractor, data map[string]any) (map[string][]string, error) {
result := make(map[string][]string)
for _, v := range c {
if key, images, err := v.GetImages(request); err != nil {
if key, images, err := v.GetImages(data); err != nil {
return nil, err
} else {
result[key] = images

View file

@ -5,7 +5,10 @@ import (
"slices"
"testing"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
"github.com/kyverno/kyverno/api/policies.kyverno.io/v1alpha1"
"github.com/kyverno/kyverno/pkg/cel/policy"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
@ -15,7 +18,7 @@ func Test_Match(t *testing.T) {
tests := []struct {
name string
imageExtractor []v1alpha1.Image
request any
request map[string]any
gvr *metav1.GroupVersionResource
wantResult map[string][]string
wantErr bool
@ -28,10 +31,12 @@ func Test_Match(t *testing.T) {
Expression: "request.images",
},
},
request: map[string][]string{
"images": {
"nginx:latest",
"alpine:latest",
request: map[string]any{
"request": map[string][]string{
"images": {
"nginx:latest",
"alpine:latest",
},
},
},
wantResult: map[string][]string{
@ -52,34 +57,36 @@ func Test_Match(t *testing.T) {
},
},
request: map[string]any{
"images": []string{
"nginx:latest",
"alpine:latest",
},
"object": map[string]any{
"spec": map[string]any{
"containers": []map[string]string{
{
"image": "kyverno/image-one",
"request": map[string]any{
"images": []string{
"nginx:latest",
"alpine:latest",
},
"object": map[string]any{
"spec": map[string]any{
"containers": []map[string]string{
{
"image": "kyverno/image-one",
},
{
"image": "kyverno/image-two",
},
},
{
"image": "kyverno/image-two",
"initContainers": []map[string]string{
{
"image": "kyverno/init-image-one",
},
{
"image": "kyverno/init-image-two",
},
},
},
"initContainers": []map[string]string{
{
"image": "kyverno/init-image-one",
},
{
"image": "kyverno/init-image-two",
},
},
"ephemeralContainers": []map[string]string{
{
"image": "kyverno/ephr-image-one",
},
{
"image": "kyverno/ephr-image-two",
"ephemeralContainers": []map[string]string{
{
"image": "kyverno/ephr-image-one",
},
{
"image": "kyverno/ephr-image-two",
},
},
},
},
@ -114,8 +121,10 @@ func Test_Match(t *testing.T) {
Expression: "request.images",
},
},
request: map[string][]int{
"images": {0, 1},
request: map[string]any{
"request": map[string][]int{
"images": {0, 1},
},
},
gvr: nil,
wantErr: true,
@ -123,7 +132,7 @@ func Test_Match(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c, errList := CompileImageExtractors(field.NewPath("spec", "images"), tt.imageExtractor, tt.gvr)
c, errList := CompileImageExtractors(field.NewPath("spec", "images"), tt.imageExtractor, tt.gvr, []cel.EnvOption{cel.Variable(policy.RequestKey, types.DynType)})
assert.Nil(t, errList)
images, err := ExtractImages(c, tt.request)
if tt.wantErr {