mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-26 01:24:26 +00:00
* feat: webhook support for image verification Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * feat: add validation Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: add tests Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: tests Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: ci Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: codegen Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: trim prefix Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: only use matched policies Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: conflicts Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: remove commented code 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>
144 lines
4.2 KiB
Go
144 lines
4.2 KiB
Go
package variables
|
|
|
|
import (
|
|
"github.com/google/cel-go/cel"
|
|
"github.com/kyverno/kyverno/api/policies.kyverno.io/v1alpha1"
|
|
"github.com/kyverno/kyverno/pkg/cel/utils"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
|
)
|
|
|
|
var (
|
|
podImageExtractors = []v1alpha1.Image{
|
|
{
|
|
Name: "containers",
|
|
Expression: "has(object.spec.containers) ? object.spec.containers.map(e, e.image) : []",
|
|
},
|
|
{
|
|
Name: "initContainers",
|
|
Expression: "has(object.spec.initContainers) ? object.spec.initContainers.map(e, e.image) : []",
|
|
},
|
|
{
|
|
Name: "ephemeralContainers",
|
|
Expression: "has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers.map(e, e.image) : []",
|
|
},
|
|
}
|
|
podControllerImageExtractors = []v1alpha1.Image{
|
|
{
|
|
Name: "containers",
|
|
Expression: "has(object.spec.template.spec.containers) ? object.spec.template.spec.containers.map(e, e.image) : []",
|
|
},
|
|
{
|
|
Name: "initContainers",
|
|
Expression: "has(object.spec.template.spec.initContainers) ? object.spec.template.spec.initContainers.map(e, e.image) : []",
|
|
},
|
|
{
|
|
Name: "ephemeralContainers",
|
|
Expression: "has(object.spec.template.spec.ephemeralContainers) ? object.spec.template.spec.ephemeralContainers.map(e, e.image) : []",
|
|
},
|
|
}
|
|
cronJobImageExtractors = []v1alpha1.Image{
|
|
{
|
|
Name: "containers",
|
|
Expression: "has(object.spec.jobTemplate.spec.template.spec.containers) ? object.spec.jobTemplate.spec.template.spec.containers.map(e, e.image) : []",
|
|
},
|
|
{
|
|
Name: "initContainers",
|
|
Expression: "has(object.spec.jobTemplate.spec.template.spec.initContainers) ? object.spec.jobTemplate.spec.template.spec.initContainers.map(e, e.image) : []",
|
|
},
|
|
{
|
|
Name: "ephemeralContainers",
|
|
Expression: "has(object.spec.jobTemplate.spec.template.spec.ephemeralContainers) ? object.spec.jobTemplate.spec.template.spec.ephemeralContainers.map(e, e.image) : []",
|
|
},
|
|
}
|
|
)
|
|
|
|
type CompiledImageExtractor struct {
|
|
key string
|
|
e cel.Program
|
|
}
|
|
|
|
func (c *CompiledImageExtractor) GetImages(data map[string]any) (string, []string, error) {
|
|
out, _, err := c.e.Eval(data)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
result, err := utils.ConvertToNative[[]string](out)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
return c.key, result, nil
|
|
}
|
|
|
|
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(envOpts...)
|
|
if err != nil {
|
|
return nil, append(allErrs, field.Invalid(path, imageExtractors, err.Error()))
|
|
}
|
|
|
|
for i, m := range imageExtractors {
|
|
path := path.Index(i).Child("expression")
|
|
c := &CompiledImageExtractor{
|
|
key: m.Name,
|
|
}
|
|
ast, iss := e.Compile(m.Expression)
|
|
if iss.Err() != nil {
|
|
return nil, append(allErrs, field.Invalid(path, m.Expression, iss.Err().Error()))
|
|
}
|
|
prg, err := e.Program(ast)
|
|
if err != nil {
|
|
return nil, append(allErrs, field.Invalid(path, m.Expression, err.Error()))
|
|
}
|
|
c.e = prg
|
|
compiledMatches = append(compiledMatches, c)
|
|
}
|
|
|
|
return compiledMatches, nil
|
|
}
|
|
|
|
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(data); err != nil {
|
|
return nil, err
|
|
} else {
|
|
result[key] = images
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func getExtractorForGVR(gvr *metav1.GroupVersionResource) []v1alpha1.Image {
|
|
if gvr == nil {
|
|
return []v1alpha1.Image{}
|
|
}
|
|
|
|
if gvr.Group == "batch" && gvr.Version == "v1" {
|
|
if gvr.Resource == "jobs" {
|
|
return podControllerImageExtractors
|
|
} else if gvr.Resource == "cronjobs" {
|
|
return cronJobImageExtractors
|
|
}
|
|
}
|
|
|
|
if gvr.Group == "apps" && gvr.Version == "v1" {
|
|
r := gvr.Resource
|
|
if r == "deployments" || r == "statefulsets" || r == "daemonsets" || r == "replicasets" {
|
|
return podControllerImageExtractors
|
|
}
|
|
}
|
|
|
|
if gvr.Group == "" && gvr.Version == "v1" && gvr.Resource == "pods" {
|
|
return podImageExtractors
|
|
}
|
|
|
|
return []v1alpha1.Image{}
|
|
}
|