1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 02:18:15 +00:00

Adding support for overriding the default registry (#4715)

Signed-off-by: Njegos Railic <railic.njegos@gmail.com>

Signed-off-by: Njegos Railic <railic.njegos@gmail.com>
This commit is contained in:
Njegos Railic 2023-01-02 18:14:40 +01:00 committed by GitHub
parent eabd7a238b
commit c429f845dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 421 additions and 159 deletions

View file

@ -177,6 +177,8 @@ The command removes all the Kubernetes components associated with the chart and
| generatecontrollerExtraResources | list | `[]` | Additional resources to be added to controller RBAC permissions. |
| excludeKyvernoNamespace | bool | `true` | Exclude Kyverno namespace Determines if default Kyverno namespace exclusion is enabled for webhooks and resourceFilters |
| resourceFiltersExcludeNamespaces | list | `[]` | resourceFilter namespace exclude Namespaces to exclude from the default resourceFilters |
| config.defaultRegistry | string | `"docker.io"` | The registry hostname used for the image mutation. |
| config.enableDefaultRegistryMutation | bool | `true` | Enable registry mutation for container images. Enabled by default. |
| config.resourceFilters | list | See [values.yaml](values.yaml) | Resource types to be skipped by the Kyverno policy engine. Make sure to surround each entry in quotes so that it doesn't get parsed as a nested YAML list. These are joined together without spaces, run through `tpl`, and the result is set in the config map. |
| config.existingConfig | string | `""` | Name of an existing config map (ignores default/provided resourceFilters) |
| config.annotations | object | `{}` | Additional annotations to add to the configmap |

View file

@ -11,6 +11,12 @@ metadata:
name: {{ template "kyverno.configMapName" . }}
namespace: {{ template "kyverno.namespace" . }}
data:
{{- if .Values.config.defaultRegistry }}
defaultRegistry: {{ .Values.config.defaultRegistry | quote }}
{{- end }}
{{- if .Values.config.enableDefaultRegistryMutation }}
enableDefaultRegistryMutation: {{ .Values.config.enableDefaultRegistryMutation | quote }}
{{- end }}
# resource types to be skipped by kyverno policy engine
{{- if .Values.config.resourceFilters }}
resourceFilters: {{ include "kyverno.resourceFilters" . | quote }}

View file

@ -304,6 +304,12 @@ excludeKyvernoNamespace: true
resourceFiltersExcludeNamespaces: []
config:
# -- The registry hostname used for the image mutation.
defaultRegistry: docker.io
# -- Enable registry mutation for container images. Enabled by default.
enableDefaultRegistryMutation: true
# -- Resource types to be skipped by the Kyverno policy engine.
# Make sure to surround each entry in quotes so that it doesn't get parsed as a nested YAML list.
# These are joined together without spaces, run through `tpl`, and the result is set in the config map.

View file

@ -8,6 +8,7 @@ import (
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
kyvernov2alpha1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v2alpha1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
match "github.com/kyverno/kyverno/pkg/utils/match"
@ -38,7 +39,7 @@ func New(
}
}
func (h *handlers) Cleanup(ctx context.Context, logger logr.Logger, name string, _ time.Time) error {
func (h *handlers) Cleanup(ctx context.Context, logger logr.Logger, name string, _ time.Time, cfg config.Configuration) error {
logger.Info("cleaning up...")
defer logger.Info("done")
namespace, name, err := cache.SplitMetaNamespaceKey(name)
@ -49,7 +50,7 @@ func (h *handlers) Cleanup(ctx context.Context, logger logr.Logger, name string,
if err != nil {
return err
}
return h.executePolicy(ctx, logger, policy)
return h.executePolicy(ctx, logger, policy, cfg)
}
func (h *handlers) lookupPolicy(namespace, name string) (kyvernov2alpha1.CleanupPolicyInterface, error) {
@ -60,7 +61,7 @@ func (h *handlers) lookupPolicy(namespace, name string) (kyvernov2alpha1.Cleanup
}
}
func (h *handlers) executePolicy(ctx context.Context, logger logr.Logger, policy kyvernov2alpha1.CleanupPolicyInterface) error {
func (h *handlers) executePolicy(ctx context.Context, logger logr.Logger, policy kyvernov2alpha1.CleanupPolicyInterface, cfg config.Configuration) error {
spec := policy.GetSpec()
kinds := sets.New(spec.MatchResources.GetKinds()...)
debug := logger.V(5)
@ -120,7 +121,7 @@ func (h *handlers) executePolicy(ctx context.Context, logger logr.Logger, policy
errs = append(errs, err)
continue
}
if err := enginectx.AddImageInfos(&resource); err != nil {
if err := enginectx.AddImageInfos(&resource, cfg); err != nil {
debug.Error(err, "failed to add image infos in context")
errs = append(errs, err)
continue

View file

@ -207,6 +207,7 @@ func main() {
DumpPayload: dumpPayload,
},
probes{},
config.NewDefaultConfiguration(),
)
// start server
server.Run(ctx.Done())

View file

@ -32,7 +32,7 @@ type server struct {
type (
TlsProvider = func() ([]byte, []byte, error)
ValidationHandler = func(context.Context, logr.Logger, *admissionv1.AdmissionRequest, time.Time) *admissionv1.AdmissionResponse
CleanupHandler = func(context.Context, logr.Logger, string, time.Time) error
CleanupHandler = func(context.Context, logr.Logger, string, time.Time, config.Configuration) error
)
type Probes interface {
@ -48,13 +48,14 @@ func NewServer(
metricsConfig metrics.MetricsConfigManager,
debugModeOpts webhooks.DebugModeOptions,
probes Probes,
cfg config.Configuration,
) Server {
policyLogger := logging.WithName("cleanup-policy")
cleanupLogger := logging.WithName("cleanup")
cleanupHandlerFunc := func(w http.ResponseWriter, r *http.Request) {
policy := r.URL.Query().Get("policy")
logger := cleanupLogger.WithValues("policy", policy)
err := cleanupHandler(r.Context(), logger, policy, time.Now())
err := cleanupHandler(r.Context(), logger, policy, time.Now(), cfg)
if err == nil {
w.WriteHeader(http.StatusOK)
} else {

View file

@ -21,6 +21,7 @@ import (
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/background/generate"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
engineContext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
@ -452,7 +453,8 @@ OuterLoop:
}
}
if err := ctx.AddImageInfos(c.Resource); err != nil {
cfg := config.NewDefaultConfiguration()
if err := ctx.AddImageInfos(c.Resource, cfg); err != nil {
if err != nil {
log.Log.Error(err, "failed to add image variables to context")
}
@ -511,7 +513,7 @@ OuterLoop:
var info Info
var validateResponse *response.EngineResponse
if policyHasValidate {
validateResponse = engine.Validate(context.Background(), registryclient.NewOrDie(), policyContext)
validateResponse = engine.Validate(context.Background(), registryclient.NewOrDie(), policyContext, cfg)
info = ProcessValidateEngineResponse(c.Policy, validateResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)
}
@ -519,7 +521,7 @@ OuterLoop:
engineResponses = append(engineResponses, validateResponse)
}
verifyImageResponse, _ := engine.VerifyAndPatchImages(context.Background(), registryclient.NewOrDie(), policyContext)
verifyImageResponse, _ := engine.VerifyAndPatchImages(context.Background(), registryclient.NewOrDie(), policyContext, cfg)
if verifyImageResponse != nil && !verifyImageResponse.IsEmpty() {
engineResponses = append(engineResponses, verifyImageResponse)
info = ProcessValidateEngineResponse(c.Policy, verifyImageResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)

View file

@ -170,6 +170,7 @@ func createReportControllers(
kyvernoInformer kyvernoinformer.SharedInformerFactory,
configMapResolver resolvers.ConfigmapResolver,
backgroundScanInterval time.Duration,
configuration config.Configuration,
) ([]internal.Controller, func(context.Context) error) {
var ctrls []internal.Controller
var warmups []func(context.Context) error
@ -225,6 +226,7 @@ func createReportControllers(
resourceReportController,
configMapResolver,
backgroundScanInterval,
configuration,
),
backgroundScanWorkers,
))
@ -340,6 +342,7 @@ func createrLeaderControllers(
kyvernoInformer,
configMapResolver,
backgroundScanInterval,
configuration,
)
return append(
[]internal.Controller{

View file

@ -46,6 +46,8 @@ metadata:
name: kyverno
namespace: kyverno
data:
defaultRegistry: "docker.io"
enableDefaultRegistryMutation: "true"
# resource types to be skipped by kyverno policy engine
resourceFilters: "[*,kyverno,*][Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*][Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][SelfSubjectAccessReview,*,*][Binding,*,*][ReplicaSet,*,*][AdmissionReport,*,*][ClusterAdmissionReport,*,*][BackgroundScanReport,*,*][ClusterBackgroundScanReport,*,*][ClusterRole,*,kyverno:*][ClusterRoleBinding,*,kyverno:*][ServiceAccount,kyverno,kyverno][ConfigMap,kyverno,kyverno][ConfigMap,kyverno,kyverno-metrics][Deployment,kyverno,kyverno][Job,kyverno,kyverno-hook-pre-delete][NetworkPolicy,kyverno,kyverno][PodDisruptionBudget,kyverno,kyverno][Role,kyverno,kyverno:*][RoleBinding,kyverno,kyverno:*][Secret,kyverno,kyverno-svc.kyverno.svc.*][Service,kyverno,kyverno-svc][Service,kyverno,kyverno-svc-metrics][ServiceMonitor,kyverno,kyverno-svc-service-monitor][Pod,kyverno,kyverno-test]"
webhooks: '[{"namespaceSelector": {"matchExpressions": [{"key":"kubernetes.io/metadata.name","operator":"NotIn","values":["kyverno"]}]}}]'

View file

@ -75,7 +75,7 @@ func NewBackgroundContext(dclient dclient.Interface, ur *kyvernov1beta1.UpdateRe
return nil, false, errors.Wrapf(err, "failed to load UserInfo in context")
}
if err := ctx.AddImageInfos(trigger); err != nil {
if err := ctx.AddImageInfos(trigger, cfg); err != nil {
logger.Error(err, "unable to add image info to variables context")
}

View file

@ -5,6 +5,7 @@ import (
"strconv"
"sync"
valid "github.com/asaskevich/govalidator"
osutils "github.com/kyverno/kyverno/pkg/utils/os"
wildcard "github.com/kyverno/kyverno/pkg/utils/wildcard"
corev1 "k8s.io/api/core/v1"
@ -130,6 +131,10 @@ func KyvernoConfigMapName() string {
// Configuration to be used by consumer to check filters
type Configuration interface {
// GetDefaultRegistry return default image registry
GetDefaultRegistry() string
// GetEnableDefaultRegistryMutation return if should mutate image registry
GetEnableDefaultRegistryMutation() bool
// ToFilter checks if the given resource is set to be filtered in the configuration
ToFilter(kind, namespace, name string) bool
// GetExcludeGroupRole return exclude roles
@ -148,18 +153,22 @@ type Configuration interface {
// configuration stores the configuration
type configuration struct {
mux sync.RWMutex
filters []filter
excludeGroupRole []string
excludeUsername []string
webhooks []WebhookConfig
generateSuccessEvents bool
defaultRegistry string
enableDefaultRegistryMutation bool
excludeGroupRole []string
excludeUsername []string
filters []filter
generateSuccessEvents bool
mux sync.RWMutex
webhooks []WebhookConfig
}
// NewDefaultConfiguration ...
func NewDefaultConfiguration() *configuration {
return &configuration{
excludeGroupRole: defaultExcludeGroupRole,
defaultRegistry: "docker.io",
enableDefaultRegistryMutation: true,
excludeGroupRole: defaultExcludeGroupRole,
}
}
@ -199,6 +208,18 @@ func (cd *configuration) GetExcludeGroupRole() []string {
return cd.excludeGroupRole
}
func (cd *configuration) GetDefaultRegistry() string {
cd.mux.RLock()
defer cd.mux.RUnlock()
return cd.defaultRegistry
}
func (cd *configuration) GetEnableDefaultRegistryMutation() bool {
cd.mux.RLock()
defer cd.mux.RUnlock()
return cd.enableDefaultRegistryMutation
}
func (cd *configuration) GetExcludeUsername() []string {
cd.mux.RLock()
defer cd.mux.RUnlock()
@ -250,6 +271,28 @@ func (cd *configuration) load(cm *corev1.ConfigMap) {
cd.webhooks = nil
// load filters
cd.filters = parseKinds(cm.Data["resourceFilters"])
newDefaultRegistry, ok := cm.Data["defaultRegistry"]
if !ok {
logger.V(4).Info("configuration: No defaultRegistry defined in ConfigMap")
} else {
if valid.IsDNSName(newDefaultRegistry) {
logger.V(4).Info("Updated defaultRegistry config parameter.", "oldDefaultRegistry", cd.defaultRegistry, "newDefaultRegistry", newDefaultRegistry)
cd.defaultRegistry = newDefaultRegistry
} else {
logger.V(4).Info("defaultRegistry didn't change because the provided config value isn't a valid DNS hostname")
}
}
enableDefaultRegistryMutation, ok := cm.Data["enableDefaultRegistryMutation"]
if !ok {
logger.V(4).Info("configuration: No enableDefaultRegistryMutation defined in ConfigMap")
} else {
newEnableDefaultRegistryMutation, err := strconv.ParseBool(enableDefaultRegistryMutation)
if err != nil {
logger.V(4).Info("configuration: Invalid value for enableDefaultRegistryMutation defined in ConfigMap. enableDefaultRegistryMutation didn't change")
}
logger.V(4).Info("Updated enableDefaultRegistryMutation config parameter", "oldEnableDefaultRegistryMutation", cd.enableDefaultRegistryMutation, "newEnableDefaultRegistryMutation", newEnableDefaultRegistryMutation)
cd.enableDefaultRegistryMutation = newEnableDefaultRegistryMutation
}
// load excludeGroupRole
cd.excludeGroupRole = append(cd.excludeGroupRole, parseRbac(cm.Data["excludeGroupRole"])...)
cd.excludeGroupRole = append(cd.excludeGroupRole, defaultExcludeGroupRole...)
@ -281,6 +324,8 @@ func (cd *configuration) unload() {
cd.mux.Lock()
defer cd.mux.Unlock()
cd.filters = []filter{}
cd.defaultRegistry = "docker.io"
cd.enableDefaultRegistryMutation = true
cd.excludeGroupRole = []string{}
cd.excludeUsername = []string{}
cd.generateSuccessEvents = false

View file

@ -12,6 +12,7 @@ import (
kyvernov1informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
kyvernov1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/controllers"
"github.com/kyverno/kyverno/pkg/controllers/report/resource"
"github.com/kyverno/kyverno/pkg/controllers/report/utils"
@ -62,6 +63,8 @@ type controller struct {
metadataCache resource.MetadataCache
informerCacheResolvers resolvers.ConfigmapResolver
forceDelay time.Duration
cfg config.Configuration
}
func NewController(
@ -75,6 +78,7 @@ func NewController(
metadataCache resource.MetadataCache,
informerCacheResolvers resolvers.ConfigmapResolver,
forceDelay time.Duration,
cfg config.Configuration,
) controllers.Controller {
bgscanr := metadataFactory.ForResource(kyvernov1alpha2.SchemeGroupVersion.WithResource("backgroundscanreports"))
cbgscanr := metadataFactory.ForResource(kyvernov1alpha2.SchemeGroupVersion.WithResource("clusterbackgroundscanreports"))
@ -94,6 +98,7 @@ func NewController(
metadataCache: metadataCache,
informerCacheResolvers: informerCacheResolvers,
forceDelay: forceDelay,
cfg: cfg,
}
controllerutils.AddEventHandlersT(polInformer.Informer(), c.addPolicy, c.updatePolicy, c.deletePolicy)
controllerutils.AddEventHandlersT(cpolInformer.Informer(), c.addPolicy, c.updatePolicy, c.deletePolicy)
@ -239,7 +244,7 @@ func (c *controller) updateReport(ctx context.Context, meta metav1.Object, gvk s
}
// if the resource changed, we need to rebuild the report
if force || !reportutils.CompareHash(meta, resource.Hash) {
scanner := utils.NewScanner(logger, c.client, c.rclient, c.informerCacheResolvers)
scanner := utils.NewScanner(logger, c.client, c.rclient, c.informerCacheResolvers, c.cfg)
before, err := c.getReport(ctx, meta.GetNamespace(), meta.GetName())
if err != nil {
return nil
@ -329,7 +334,7 @@ func (c *controller) updateReport(ctx context.Context, meta metav1.Object, gvk s
}
// creations
if len(toCreate) > 0 {
scanner := utils.NewScanner(logger, c.client, c.rclient, c.informerCacheResolvers)
scanner := utils.NewScanner(logger, c.client, c.rclient, c.informerCacheResolvers, c.cfg)
resource, err := c.client.GetResource(ctx, gvk.GroupVersion().String(), gvk.Kind, resource.Namespace, resource.Name)
if err != nil {
return err

View file

@ -6,6 +6,7 @@ import (
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
@ -20,6 +21,7 @@ type scanner struct {
client dclient.Interface
rclient registryclient.Client
informerCacheResolvers resolvers.ConfigmapResolver
cfg config.Configuration
excludeGroupRole []string
}
@ -32,12 +34,13 @@ type Scanner interface {
ScanResource(context.Context, unstructured.Unstructured, map[string]string, ...kyvernov1.PolicyInterface) map[kyvernov1.PolicyInterface]ScanResult
}
func NewScanner(logger logr.Logger, client dclient.Interface, rclient registryclient.Client, informerCacheResolvers resolvers.ConfigmapResolver, excludeGroupRole ...string) Scanner {
func NewScanner(logger logr.Logger, client dclient.Interface, rclient registryclient.Client, informerCacheResolvers resolvers.ConfigmapResolver, cfg config.Configuration, excludeGroupRole ...string) Scanner {
return &scanner{
logger: logger,
client: client,
rclient: rclient,
informerCacheResolvers: informerCacheResolvers,
cfg: cfg,
excludeGroupRole: excludeGroupRole,
}
}
@ -77,7 +80,7 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un
if err := enginectx.AddNamespace(resource.GetNamespace()); err != nil {
return nil, err
}
if err := enginectx.AddImageInfos(&resource); err != nil {
if err := enginectx.AddImageInfos(&resource, s.cfg); err != nil {
return nil, err
}
if err := enginectx.AddOperation("CREATE"); err != nil {
@ -90,7 +93,7 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un
WithNamespaceLabels(nsLabels).
WithExcludeGroupRole(s.excludeGroupRole...).
WithInformerCacheResolver(s.informerCacheResolvers)
return engine.Validate(ctx, s.rclient, policyCtx), nil
return engine.Validate(ctx, s.rclient, policyCtx, s.cfg), nil
}
func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unstructured, nsLabels map[string]string, policy kyvernov1.PolicyInterface) (*response.EngineResponse, error) {
@ -101,7 +104,7 @@ func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unst
if err := enginectx.AddNamespace(resource.GetNamespace()); err != nil {
return nil, err
}
if err := enginectx.AddImageInfos(&resource); err != nil {
if err := enginectx.AddImageInfos(&resource, s.cfg); err != nil {
return nil, err
}
if err := enginectx.AddOperation("CREATE"); err != nil {
@ -114,7 +117,7 @@ func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unst
WithNamespaceLabels(nsLabels).
WithExcludeGroupRole(s.excludeGroupRole...).
WithInformerCacheResolver(s.informerCacheResolvers)
response, _ := engine.VerifyAndPatchImages(ctx, s.rclient, policyCtx)
response, _ := engine.VerifyAndPatchImages(ctx, s.rclient, policyCtx, s.cfg)
if len(response.PolicyResponse.Rules) > 0 {
s.logger.Info("validateImages", "policy", policy, "response", response)
}

View file

@ -9,6 +9,7 @@ import (
jsonpatch "github.com/evanphx/json-patch/v5"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/logging"
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
"github.com/pkg/errors"
@ -69,17 +70,17 @@ type Interface interface {
AddElement(data interface{}, index, nesting int) error
// AddImageInfo adds image info to the context
AddImageInfo(info apiutils.ImageInfo) error
AddImageInfo(info apiutils.ImageInfo, cfg config.Configuration) error
// AddImageInfos adds image infos to the context
AddImageInfos(resource *unstructured.Unstructured) error
AddImageInfos(resource *unstructured.Unstructured, cfg config.Configuration) error
// ImageInfo returns image infos present in the context
ImageInfo() map[string]map[string]apiutils.ImageInfo
// GenerateCustomImageInfo returns image infos as defined by a custom image extraction config
// and updates the context
GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs) (map[string]map[string]apiutils.ImageInfo, error)
GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs, cfg config.Configuration) (map[string]map[string]apiutils.ImageInfo, error)
// Checkpoint creates a copy of the current internal state and pushes it into a stack of stored states.
Checkpoint()
@ -252,7 +253,7 @@ func (ctx *context) AddElement(data interface{}, index, nesting int) error {
return addToContext(ctx, data)
}
func (ctx *context) AddImageInfo(info apiutils.ImageInfo) error {
func (ctx *context) AddImageInfo(info apiutils.ImageInfo, cfg config.Configuration) error {
data := map[string]interface{}{
"reference": info.String(),
"referenceWithTag": info.ReferenceWithTag(),
@ -265,8 +266,8 @@ func (ctx *context) AddImageInfo(info apiutils.ImageInfo) error {
return addToContext(ctx, data, "image")
}
func (ctx *context) AddImageInfos(resource *unstructured.Unstructured) error {
images, err := apiutils.ExtractImagesFromResource(*resource, nil)
func (ctx *context) AddImageInfos(resource *unstructured.Unstructured, cfg config.Configuration) error {
images, err := apiutils.ExtractImagesFromResource(*resource, nil, cfg)
if err != nil {
return err
}
@ -279,8 +280,8 @@ func (ctx *context) AddImageInfos(resource *unstructured.Unstructured) error {
return addToContext(ctx, images, "images")
}
func (ctx *context) GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs) (map[string]map[string]apiutils.ImageInfo, error) {
images, err := apiutils.ExtractImagesFromResource(*resource, imageExtractorConfigs)
func (ctx *context) GenerateCustomImageInfo(resource *unstructured.Unstructured, imageExtractorConfigs kyvernov1.ImageExtractorConfigs, cfg config.Configuration) (map[string]map[string]apiutils.ImageInfo, error) {
images, err := apiutils.ExtractImagesFromResource(*resource, imageExtractorConfigs, cfg)
if err != nil {
return nil, errors.Wrapf(err, "failed to extract images")
}

View file

@ -12,6 +12,7 @@ import (
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/cosign"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
@ -46,7 +47,7 @@ func getMatchingImages(images map[string]map[string]apiutils.ImageInfo, rule *ky
return imageInfos, strings.Join(imageRefs, ",")
}
func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule) ([]apiutils.ImageInfo, string, error) {
func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule, cfg config.Configuration) ([]apiutils.ImageInfo, string, error) {
var (
images map[string]map[string]apiutils.ImageInfo
err error
@ -54,7 +55,7 @@ func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule) (
images = policyContext.jsonContext.ImageInfo()
if rule.ImageExtractors != nil {
images, err = policyContext.jsonContext.GenerateCustomImageInfo(
&policyContext.newResource, rule.ImageExtractors)
&policyContext.newResource, rule.ImageExtractors, cfg)
if err != nil {
// if we get an error while generating custom images from image extractors,
// don't check for matching images in imageExtractors
@ -69,6 +70,7 @@ func VerifyAndPatchImages(
ctx context.Context,
rclient registryclient.Client,
policyContext *PolicyContext,
cfg config.Configuration,
) (*response.EngineResponse, *ImageVerificationMetadata) {
resp := &response.EngineResponse{}
@ -117,7 +119,7 @@ func VerifyAndPatchImages(
logger.V(3).Info("processing image verification rule", "ruleSelector", applyRules)
ruleImages, imageRefs, err := extractMatchingImages(policyContext, rule)
ruleImages, imageRefs, err := extractMatchingImages(policyContext, rule, cfg)
if err != nil {
appendResponse(resp, rule, fmt.Sprintf("failed to extract images: %s", err.Error()), response.RuleStatusError)
return
@ -154,7 +156,7 @@ func VerifyAndPatchImages(
}
for _, imageVerify := range ruleCopy.VerifyImages {
iv.verify(ctx, imageVerify, ruleImages)
iv.verify(ctx, imageVerify, ruleImages, cfg)
}
},
)
@ -205,7 +207,7 @@ type imageVerifier struct {
// verify applies policy rules to each matching image. The policy rule results and annotation patches are
// added to tme imageVerifier `resp` and `ivm` fields.
func (iv *imageVerifier) verify(ctx context.Context, imageVerify kyvernov1.ImageVerification, matchedImageInfos []apiutils.ImageInfo) {
func (iv *imageVerifier) verify(ctx context.Context, imageVerify kyvernov1.ImageVerification, matchedImageInfos []apiutils.ImageInfo, cfg config.Configuration) {
// for backward compatibility
imageVerify = *imageVerify.Convert()
@ -234,7 +236,7 @@ func (iv *imageVerifier) verify(ctx context.Context, imageVerify kyvernov1.Image
continue
}
ruleResp, digest := iv.verifyImage(ctx, imageVerify, imageInfo)
ruleResp, digest := iv.verifyImage(ctx, imageVerify, imageInfo, cfg)
if imageVerify.MutateDigest {
patch, retrievedDigest, err := iv.handleMutateDigest(ctx, digest, imageInfo)
@ -317,6 +319,7 @@ func (iv *imageVerifier) verifyImage(
ctx context.Context,
imageVerify kyvernov1.ImageVerification,
imageInfo apiutils.ImageInfo,
cfg config.Configuration,
) (*response.RuleResponse, string) {
if len(imageVerify.Attestors) <= 0 && len(imageVerify.Attestations) <= 0 {
return nil, ""
@ -326,7 +329,7 @@ func (iv *imageVerifier) verifyImage(
iv.logger.V(2).Info("verifying image signatures", "image", image,
"attestors", len(imageVerify.Attestors), "attestations", len(imageVerify.Attestations))
if err := iv.policyContext.jsonContext.AddImageInfo(imageInfo); err != nil {
if err := iv.policyContext.jsonContext.AddImageInfo(imageInfo, cfg); err != nil {
iv.logger.Error(err, "failed to add image to context")
msg := fmt.Sprintf("failed to add image to context %s: %s", image, err.Error())
return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusError), ""

View file

@ -8,6 +8,7 @@ import (
"github.com/go-logr/logr"
gojmespath "github.com/jmespath/go-jmespath"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/registryclient"
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
@ -15,13 +16,13 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func processImageValidationRule(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, rule *kyvernov1.Rule) *response.RuleResponse {
func processImageValidationRule(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, rule *kyvernov1.Rule, cfg config.Configuration) *response.RuleResponse {
if isDeleteRequest(enginectx) {
return nil
}
log = log.WithValues("rule", rule.Name)
matchingImages, _, err := extractMatchingImages(enginectx, rule)
matchingImages, _, err := extractMatchingImages(enginectx, rule, cfg)
if err != nil {
return ruleResponse(*rule, response.Validation, err.Error(), response.RuleStatusError)
}

View file

@ -7,6 +7,7 @@ import (
"strings"
"testing"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/registryclient"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -63,7 +64,7 @@ var testPolicyGood = `{
"key": "{{ repo.uri }}",
"operator": "Equals",
"value": "https://github.com/example/my-project"
},
},
{
"key": "{{ repo.branch }}",
"operator": "Equals",
@ -112,7 +113,7 @@ var testPolicyBad = `{
"key": "{{ repo.uri }}",
"operator": "Equals",
"value": "https://github.com/example/my-project"
},
},
{
"key": "{{ repo.branch }}",
"operator": "Equals",
@ -157,12 +158,14 @@ var signaturePayloads = [][]byte{
[]byte(`{"critical":{"identity":{"docker-reference":"ghcr.io/kyverno/test-verify-image"},"image":{"docker-manifest-digest":"sha256:b31bfb4d0213f254d361e0079deaaebefa4f82ba7aa76ef82e90b4935ad5b105"},"type":"cosign container image signature"},"optional":null}`),
}
var cfg = config.NewDefaultConfiguration()
func Test_CosignMockAttest(t *testing.T) {
policyContext := buildContext(t, testPolicyGood, testResource, "")
err := cosign.SetMock("ghcr.io/jimbugwadia/pause2:latest", attestationPayloads)
assert.NilError(t, err)
er, ivm := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
er, ivm := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusPass,
fmt.Sprintf("expected: %v, got: %v, failure: %v",
@ -176,7 +179,7 @@ func Test_CosignMockAttest_fail(t *testing.T) {
err := cosign.SetMock("ghcr.io/jimbugwadia/pause2:latest", attestationPayloads)
assert.NilError(t, err)
er, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
er, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
}
@ -209,7 +212,7 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) *Po
policyContext.oldResource = *oldResourceUnstructured
}
if err := ctx.AddImageInfos(resourceUnstructured); err != nil {
if err := ctx.AddImageInfos(resourceUnstructured, cfg); err != nil {
t.Errorf("unable to add image info to variables context: %v", err)
t.Fail()
}
@ -425,7 +428,7 @@ var (
func Test_ConfigMapMissingSuccess(t *testing.T) {
policyContext := buildContext(t, testConfigMapMissing, testConfigMapMissingResource, "")
cosign.ClearMock()
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusSkip, err.PolicyResponse.Rules[0].Message)
}
@ -437,7 +440,7 @@ func Test_ConfigMapMissingFailure(t *testing.T) {
assert.NilError(t, err)
policyContext.informerCacheResolvers = resolver
cosign.ClearMock()
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(resp.PolicyResponse.Rules), 1)
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusError, resp.PolicyResponse.Rules[0].Message)
}
@ -446,7 +449,7 @@ func Test_SignatureGoodSigned(t *testing.T) {
policyContext := buildContext(t, testSampleSingleKeyPolicy, testSampleResource, "")
policyContext.policy.GetSpec().Rules[0].VerifyImages[0].MutateDigest = true
cosign.ClearMock()
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, engineResp.PolicyResponse.Rules[0].Message)
assert.Equal(t, len(engineResp.PolicyResponse.Rules[0].Patches), 1)
@ -458,7 +461,7 @@ func Test_SignatureUnsigned(t *testing.T) {
cosign.ClearMock()
unsigned := strings.Replace(testSampleResource, ":signed", ":unsigned", -1)
policyContext := buildContext(t, testSampleSingleKeyPolicy, unsigned, "")
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusFail, engineResp.PolicyResponse.Rules[0].Message)
}
@ -467,7 +470,7 @@ func Test_SignatureWrongKey(t *testing.T) {
cosign.ClearMock()
otherKey := strings.Replace(testSampleResource, ":signed", ":signed-by-someone-else", -1)
policyContext := buildContext(t, testSampleSingleKeyPolicy, otherKey, "")
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusFail, engineResp.PolicyResponse.Rules[0].Message)
}
@ -478,7 +481,7 @@ func Test_SignaturesMultiKey(t *testing.T) {
policy = strings.Replace(policy, "KEY2", testVerifyImageKey, -1)
policy = strings.Replace(policy, "COUNT", "0", -1)
policyContext := buildContext(t, policy, testSampleResource, "")
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, engineResp.PolicyResponse.Rules[0].Message)
}
@ -488,7 +491,7 @@ func Test_SignaturesMultiKeyFail(t *testing.T) {
policy := strings.Replace(testSampleMultipleKeyPolicy, "KEY1", testVerifyImageKey, -1)
policy = strings.Replace(policy, "COUNT", "0", -1)
policyContext := buildContext(t, policy, testSampleResource, "")
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusFail, engineResp.PolicyResponse.Rules[0].Message)
}
@ -499,7 +502,7 @@ func Test_SignaturesMultiKeyOneGoodKey(t *testing.T) {
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
policy = strings.Replace(policy, "COUNT", "1", -1)
policyContext := buildContext(t, policy, testSampleResource, "")
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, engineResp.PolicyResponse.Rules[0].Message)
}
@ -510,7 +513,7 @@ func Test_SignaturesMultiKeyZeroGoodKey(t *testing.T) {
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
policy = strings.Replace(policy, "COUNT", "1", -1)
policyContext := buildContext(t, policy, testSampleResource, "")
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(resp.PolicyResponse.Rules), 1)
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusFail, resp.PolicyResponse.Rules[0].Message)
}
@ -526,14 +529,14 @@ func Test_RuleSelectorImageVerify(t *testing.T) {
applyAll := kyverno.ApplyAll
spec.ApplyRules = &applyAll
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(resp.PolicyResponse.Rules), 2)
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, resp.PolicyResponse.Rules[0].Message)
assert.Equal(t, resp.PolicyResponse.Rules[1].Status, response.RuleStatusFail, resp.PolicyResponse.Rules[1].Message)
applyOne := kyverno.ApplyOne
spec.ApplyRules = &applyOne
resp, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
resp, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(resp.PolicyResponse.Rules), 1)
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, resp.PolicyResponse.Rules[0].Message)
}
@ -637,7 +640,7 @@ func Test_NestedAttestors(t *testing.T) {
policy = strings.Replace(policy, "KEY2", testVerifyImageKey, -1)
policy = strings.Replace(policy, "COUNT", "0", -1)
policyContext := buildContext(t, policy, testSampleResource, "")
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass)
@ -645,7 +648,7 @@ func Test_NestedAttestors(t *testing.T) {
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
policy = strings.Replace(policy, "COUNT", "0", -1)
policyContext = buildContext(t, policy, testSampleResource, "")
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
@ -653,7 +656,7 @@ func Test_NestedAttestors(t *testing.T) {
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
policy = strings.Replace(policy, "COUNT", "1", -1)
policyContext = buildContext(t, policy, testSampleResource, "")
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass)
}
@ -746,7 +749,7 @@ func Test_MarkImageVerified(t *testing.T) {
err := cosign.SetMock(image, attestationPayloads)
assert.NilError(t, err)
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Assert(t, engineResponse != nil)
assert.Equal(t, len(engineResponse.PolicyResponse.Rules), 1)
assert.Equal(t, engineResponse.PolicyResponse.Rules[0].Status, response.RuleStatusPass)
@ -839,7 +842,7 @@ func Test_ParsePEMDelimited(t *testing.T) {
err := cosign.SetMock(image, signaturePayloads)
assert.NilError(t, err)
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext)
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Assert(t, engineResponse != nil)
assert.Equal(t, len(engineResponse.PolicyResponse.Rules), 1)
assert.Equal(t, engineResponse.PolicyResponse.Rules[0].Status, response.RuleStatusPass)

View file

@ -369,7 +369,7 @@ func Test_chained_rules(t *testing.T) {
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
err = ctx.AddImageInfos(resource, cfg)
assert.NilError(t, err)
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
@ -648,7 +648,7 @@ func Test_foreach(t *testing.T) {
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
err = ctx.AddImageInfos(resource, cfg)
assert.NilError(t, err)
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
@ -755,7 +755,7 @@ func Test_foreach_element_mutation(t *testing.T) {
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
err = ctx.AddImageInfos(resource, cfg)
assert.NilError(t, err)
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
@ -881,7 +881,7 @@ func Test_Container_InitContainer_foreach(t *testing.T) {
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
err = ctx.AddImageInfos(resource, cfg)
assert.NilError(t, err)
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
@ -1031,7 +1031,7 @@ func testApplyPolicyToResource(t *testing.T, policyRaw, resourceRaw []byte) *res
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
err = ctx.AddImageInfos(resource, cfg)
assert.NilError(t, err)
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
@ -1646,7 +1646,7 @@ func Test_RuleSelectorMutate(t *testing.T) {
}
}
}
}
}
]
}
}`)

View file

@ -259,7 +259,7 @@ func NewPolicyContextFromAdmissionRequest(
if err != nil {
return nil, errors.Wrap(err, "failed to parse resource")
}
if err := ctx.AddImageInfos(&newResource); err != nil {
if err := ctx.AddImageInfos(&newResource, configuration); err != nil {
return nil, errors.Wrap(err, "failed to add image information to the policy rule context")
}
requestResource := request.RequestResource.DeepCopy()

View file

@ -14,6 +14,7 @@ import (
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/common"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/validate"
@ -37,7 +38,7 @@ import (
)
// Validate applies validation rules from policy on the resource
func Validate(ctx context.Context, rclient registryclient.Client, policyContext *PolicyContext) (resp *response.EngineResponse) {
func Validate(ctx context.Context, rclient registryclient.Client, policyContext *PolicyContext, cfg config.Configuration) (resp *response.EngineResponse) {
resp = &response.EngineResponse{}
startTime := time.Now()
@ -48,7 +49,7 @@ func Validate(ctx context.Context, rclient registryclient.Client, policyContext
logger.V(4).Info("finished policy processing", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
}()
resp = validateResource(ctx, logger, rclient, policyContext)
resp = validateResource(ctx, logger, rclient, policyContext, cfg)
return
}
@ -95,7 +96,7 @@ func buildResponse(ctx *PolicyContext, resp *response.EngineResponse, startTime
resp.PolicyResponse.PolicyExecutionTimestamp = startTime.Unix()
}
func validateResource(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext) *response.EngineResponse {
func validateResource(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, cfg config.Configuration) *response.EngineResponse {
resp := &response.EngineResponse{}
enginectx.jsonContext.Checkpoint()
@ -145,7 +146,7 @@ func validateResource(ctx context.Context, log logr.Logger, rclient registryclie
if hasValidate && !hasYAMLSignatureVerify {
return processValidationRule(ctx, log, rclient, enginectx, rule)
} else if hasValidateImage {
return processImageValidationRule(ctx, log, rclient, enginectx, rule)
return processImageValidationRule(ctx, log, rclient, enginectx, rule, cfg)
} else if hasYAMLSignatureVerify {
return processYAMLValidationRule(log, enginectx, rule)
}

View file

@ -133,7 +133,7 @@ func TestValidate_image_tag_fail(t *testing.T) {
"validation error: imagePullPolicy 'Always' required with tag 'latest'. rule validate-latest failed at path /spec/containers/0/imagePullPolicy/",
}
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
@ -233,7 +233,7 @@ func TestValidate_image_tag_pass(t *testing.T) {
"validation rule 'validate-tag' passed.",
"validation rule 'validate-latest' passed.",
}
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
@ -307,7 +307,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
assert.Assert(t, !er.IsSuccessful())
msgs := []string{"validation error: A namespace is required. rule check-default-namespace[0] failed at path /metadata/namespace/ rule check-default-namespace[1] failed at path /metadata/namespace/"}
@ -390,7 +390,7 @@ func TestValidate_host_network_port(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation error: Host network and port are not allowed. rule validate-host-network-port failed at path /spec/containers/0/ports/0/hostPort/"}
for index, r := range er.PolicyResponse.Rules {
@ -480,7 +480,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation rule 'validate-host-path' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -568,7 +568,7 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation error: Host path '/var/lib/' is not allowed. rule validate-host-path failed at path /spec/volumes/0/hostPath/path/"}
for index, r := range er.PolicyResponse.Rules {
@ -638,7 +638,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -711,7 +711,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -785,7 +785,7 @@ func TestValidate_inequality_List_Processing(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -865,7 +865,7 @@ func TestValidate_inequality_List_ProcessingBrackets(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -939,7 +939,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation error: pod: validate run as non root user. rule pod rule 2 failed at path /spec/securityContext/runAsNonRoot/"}
for index, r := range er.PolicyResponse.Rules {
@ -1014,7 +1014,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation rule 'pod image rule' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -1089,7 +1089,7 @@ func TestValidate_AnchorList_fail(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
assert.Assert(t, !er.IsSuccessful())
}
@ -1159,7 +1159,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
assert.Assert(t, !er.IsSuccessful())
}
@ -1229,7 +1229,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation rule 'pod image rule' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -1317,7 +1317,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation error: Host path is not allowed. rule validate-host-path failed at path /spec/volumes/0/hostPath/"}
for index, r := range er.PolicyResponse.Rules {
@ -1404,7 +1404,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
msgs := []string{"validation rule 'validate-host-path' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -1481,7 +1481,7 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError)
@ -1575,7 +1575,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfiesButSu
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError)
@ -1637,7 +1637,7 @@ func Test_VariableSubstitution_NotOperatorWithStringVariable(t *testing.T) {
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "validation error: rule not-operator-with-variable-should-alway-fail-validation failed at path /spec/content/")
}
@ -1729,7 +1729,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError)
@ -1823,7 +1823,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
assert.Equal(t, er.PolicyResponse.Rules[0].Message,
@ -1929,7 +1929,7 @@ func Test_VariableSubstitutionValidate_VariablesInMessageAreResolved(t *testing.
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "The animal cow is not in the allowed list of animals.")
}
@ -1983,7 +1983,7 @@ func Test_Flux_Kustomization_PathNotPresent(t *testing.T) {
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
for i, rule := range er.PolicyResponse.Rules {
assert.Equal(t, er.PolicyResponse.Rules[i].Status, test.expectedResults[i], "\ntest %s failed\nexpected: %s\nactual: %s", test.name, test.expectedResults[i].String(), er.PolicyResponse.Rules[i].Status.String())
@ -2149,7 +2149,7 @@ func executeTest(t *testing.T, test testCase) {
jsonContext: ctx,
}
resp := Validate(context.TODO(), registryclient.NewOrDie(), pc)
resp := Validate(context.TODO(), registryclient.NewOrDie(), pc, cfg)
if resp.IsSuccessful() && test.requestDenied {
t.Errorf("Testcase has failed, policy: %v", policy.Name)
}
@ -2248,7 +2248,7 @@ func TestValidate_context_variable_substitution_CLI(t *testing.T) {
msgs := []string{
"restrict pod counts to be no more than 10 on node minikube",
}
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
@ -2337,7 +2337,7 @@ func Test_EmptyStringInDenyCondition(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg)
assert.Assert(t, !er.IsSuccessful())
}
@ -2426,7 +2426,7 @@ func Test_StringInDenyCondition(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg)
assert.Assert(t, er.IsSuccessful())
}
@ -3105,7 +3105,7 @@ func testForEach(t *testing.T, policyraw []byte, resourceRaw []byte, msg string,
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, status)
if msg != "" {
@ -3169,7 +3169,7 @@ func Test_delete_ignore_pattern(t *testing.T) {
jsonContext: ctx,
newResource: *resourceUnstructured,
}
engineResponseCreate := Validate(context.TODO(), registryclient.NewOrDie(), policyContextCreate)
engineResponseCreate := Validate(context.TODO(), registryclient.NewOrDie(), policyContextCreate, cfg)
assert.Equal(t, len(engineResponseCreate.PolicyResponse.Rules), 1)
assert.Equal(t, engineResponseCreate.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
@ -3178,7 +3178,7 @@ func Test_delete_ignore_pattern(t *testing.T) {
jsonContext: ctx,
oldResource: *resourceUnstructured,
}
engineResponseDelete := Validate(context.TODO(), registryclient.NewOrDie(), policyContextDelete)
engineResponseDelete := Validate(context.TODO(), registryclient.NewOrDie(), policyContextDelete, cfg)
assert.Equal(t, len(engineResponseDelete.PolicyResponse.Rules), 0)
}
@ -3237,7 +3237,7 @@ func Test_ValidatePattern_anyPattern(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(tc.rawResource)
assert.NilError(t, err)
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()})
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
if tc.expectedFailed {
assert.Assert(t, er.IsFailed())
} else if tc.expectedSkipped {

View file

@ -11,6 +11,7 @@ import (
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
@ -31,6 +32,7 @@ func applyPolicy(
rclient registryclient.Client,
informerCacheResolvers resolvers.ConfigmapResolver,
namespaceLabels map[string]string,
cfg config.Configuration,
) (responses []*response.EngineResponse) {
startTime := time.Now()
defer func() {
@ -61,7 +63,7 @@ func applyPolicy(
logger.Error(err, "failed to add namespace to ctx")
}
if err := ctx.AddImageInfos(&resource); err != nil {
if err := ctx.AddImageInfos(&resource, cfg); err != nil {
logger.Error(err, "unable to add image info to variables context")
}
@ -82,7 +84,7 @@ func applyPolicy(
WithExcludeGroupRole(excludeGroupRole...).
WithInformerCacheResolver(informerCacheResolvers)
engineResponseValidation = engine.Validate(context.TODO(), rclient, policyCtx)
engineResponseValidation = engine.Validate(context.TODO(), rclient, policyCtx, cfg)
engineResponses = append(engineResponses, mergeRuleRespose(engineResponseMutation, engineResponseValidation))
return engineResponses

View file

@ -460,7 +460,7 @@ func (pc *PolicyController) applyPolicy(policy kyvernov1.PolicyInterface, resour
}
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(resource.GetKind(), resource.GetNamespace(), pc.nsLister, logger)
engineResponse := applyPolicy(policy, resource, logger, pc.configHandler.GetExcludeGroupRole(), pc.client, pc.rclient, pc.informerCacheResolvers, namespaceLabels)
engineResponse := applyPolicy(policy, resource, logger, pc.configHandler.GetExcludeGroupRole(), pc.client, pc.rclient, pc.informerCacheResolvers, namespaceLabels, pc.configHandler)
engineResponses = append(engineResponses, engineResponse...)
// post-processing, register the resource as processed

View file

@ -97,7 +97,7 @@ func validateJSONPatch(patch string, ruleIdx int) error {
for _, operation := range decodedPatch {
op := operation.Kind()
if op != "add" && op != "remove" && op != "replace" {
return fmt.Errorf("Unexpected kind: spec.rules[%d]: %s", ruleIdx, op)
return fmt.Errorf("unexpected kind: spec.rules[%d]: %s", ruleIdx, op)
}
v, _ := operation.ValueInterface()
if v != nil {

View file

@ -1732,7 +1732,7 @@ func Test_ValidateJSON6902(t *testing.T) {
op: addition
value: "nginx"`
err := validateJSONPatch(patch, 0)
assert.Error(t, err, "Unexpected kind: spec.rules[0]: addition")
assert.Error(t, err, "unexpected kind: spec.rules[0]: addition")
patch = `- path: "/metadata/labels/img"
op: add

View file

@ -13,6 +13,7 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/registryclient"
@ -158,7 +159,8 @@ func runTestCase(t *testing.T, tc TestCase) bool {
policyContext = policyContext.WithNewResource(*resource)
er = engine.Validate(context.TODO(), registryclient.NewOrDie(), policyContext)
cfg := config.NewDefaultConfiguration()
er = engine.Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
t.Log("---Validation---")
validateResponse(t, er.PolicyResponse, tc.Expected.Validation.PolicyResponse)

View file

@ -6,6 +6,7 @@ import (
"strings"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
imageutils "github.com/kyverno/kyverno/pkg/utils/image"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@ -39,15 +40,15 @@ type imageExtractor struct {
Name string
}
func (i *imageExtractor) ExtractFromResource(resource interface{}) (map[string]ImageInfo, error) {
func (i *imageExtractor) ExtractFromResource(resource interface{}, cfg config.Configuration) (map[string]ImageInfo, error) {
imageInfo := map[string]ImageInfo{}
if err := extract(resource, []string{}, i.Key, i.Value, i.Fields, &imageInfo); err != nil {
if err := extract(resource, []string{}, i.Key, i.Value, i.Fields, &imageInfo, cfg); err != nil {
return nil, err
}
return imageInfo, nil
}
func extract(obj interface{}, path []string, keyPath, valuePath string, fields []string, imageInfos *map[string]ImageInfo) error {
func extract(obj interface{}, path []string, keyPath, valuePath string, fields []string, imageInfos *map[string]ImageInfo, cfg config.Configuration) error {
if obj == nil {
return nil
}
@ -55,13 +56,13 @@ func extract(obj interface{}, path []string, keyPath, valuePath string, fields [
switch typedObj := obj.(type) {
case []interface{}:
for i, v := range typedObj {
if err := extract(v, append(path, strconv.Itoa(i)), keyPath, valuePath, fields[1:], imageInfos); err != nil {
if err := extract(v, append(path, strconv.Itoa(i)), keyPath, valuePath, fields[1:], imageInfos, cfg); err != nil {
return err
}
}
case map[string]interface{}:
for i, v := range typedObj {
if err := extract(v, append(path, i), keyPath, valuePath, fields[1:], imageInfos); err != nil {
if err := extract(v, append(path, i), keyPath, valuePath, fields[1:], imageInfos, cfg); err != nil {
return err
}
}
@ -89,7 +90,7 @@ func extract(obj interface{}, path []string, keyPath, valuePath string, fields [
if !ok {
return fmt.Errorf("invalid value")
}
if imageInfo, err := imageutils.GetImageInfo(value); err != nil {
if imageInfo, err := imageutils.GetImageInfo(value, cfg); err != nil {
return fmt.Errorf("invalid image %s", value)
} else {
(*imageInfos)[key] = ImageInfo{*imageInfo, pointer}
@ -98,7 +99,7 @@ func extract(obj interface{}, path []string, keyPath, valuePath string, fields [
}
currentPath := fields[0]
return extract(output[currentPath], append(path, currentPath), keyPath, valuePath, fields[1:], imageInfos)
return extract(output[currentPath], append(path, currentPath), keyPath, valuePath, fields[1:], imageInfos, cfg)
}
func BuildStandardExtractors(tags ...string) []imageExtractor {
@ -150,7 +151,7 @@ func lookupImageExtractor(kind string, configs kyvernov1.ImageExtractorConfigs)
return registeredExtractors[kind]
}
func ExtractImagesFromResource(resource unstructured.Unstructured, configs kyvernov1.ImageExtractorConfigs) (map[string]map[string]ImageInfo, error) {
func ExtractImagesFromResource(resource unstructured.Unstructured, configs kyvernov1.ImageExtractorConfigs, cfg config.Configuration) (map[string]map[string]ImageInfo, error) {
infos := map[string]map[string]ImageInfo{}
extractors := lookupImageExtractor(resource.GetKind(), configs)
@ -159,7 +160,7 @@ func ExtractImagesFromResource(resource unstructured.Unstructured, configs kyver
}
for _, extractor := range extractors {
if infoMap, err := extractor.ExtractFromResource(resource.Object); err != nil {
if infoMap, err := extractor.ExtractFromResource(resource.Object, cfg); err != nil {
return nil, err
} else if len(infoMap) > 0 {
infos[extractor.Name] = infoMap

View file

@ -4,11 +4,14 @@ import (
"testing"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/utils"
imageutils "github.com/kyverno/kyverno/pkg/utils/image"
"gotest.tools/assert"
)
var cfg = config.NewDefaultConfiguration()
func Test_extractImageInfo(t *testing.T) {
tests := []struct {
extractionConfig kyvernov1.ImageExtractorConfigs
@ -219,7 +222,7 @@ func Test_extractImageInfo(t *testing.T) {
for _, test := range tests {
resource, err := utils.ConvertToUnstructured(test.raw)
assert.NilError(t, err)
images, err := ExtractImagesFromResource(*resource, test.extractionConfig)
images, err := ExtractImagesFromResource(*resource, test.extractionConfig, cfg)
assert.NilError(t, err)
assert.DeepEqual(t, test.images, images)
}

View file

@ -1,12 +1,17 @@
package image
import (
"fmt"
"strings"
"github.com/distribution/distribution/reference"
"github.com/kyverno/kyverno/pkg/config"
"github.com/pkg/errors"
"sigs.k8s.io/controller-runtime/pkg/log"
)
var logger = log.Log.WithName("image")
type ImageInfo struct {
// Registry is the URL address of the image registry e.g. `docker.io`
Registry string `json:"registry,omitempty"`
@ -25,40 +30,73 @@ type ImageInfo struct {
}
func (i *ImageInfo) String() string {
image := i.Registry + "/" + i.Path
if i.Digest != "" {
return image + "@" + i.Digest
var image string
if i.Registry != "" {
image = fmt.Sprintf("%s/%s", i.Registry, i.Path)
} else {
return image + ":" + i.Tag
image = i.Path
}
if i.Digest != "" {
return fmt.Sprintf("%s@%s", image, i.Digest)
} else {
return fmt.Sprintf("%s:%s", image, i.Tag)
}
}
func (i *ImageInfo) ReferenceWithTag() string {
return i.Registry + "/" + i.Path + ":" + i.Tag
if i.Registry != "" {
return fmt.Sprintf("%s/%s:%s", i.Registry, i.Path, i.Tag)
} else {
return fmt.Sprintf("%s:%s", i.Path, i.Tag)
}
}
func GetImageInfo(image string) (*ImageInfo, error) {
image = addDefaultDomain(image)
ref, err := reference.Parse(image)
func GetImageInfo(image string, cfg config.Configuration) (*ImageInfo, error) {
logger.V(2).Info(
"Getting the image info",
image, "image",
"defaultRegistry", config.Configuration.GetDefaultRegistry(cfg),
"enableDefaultRegistryMutation", config.Configuration.GetEnableDefaultRegistryMutation(cfg),
)
// adding the default domain in order to properly parse image info
fullImageName := addDefaultRegistry(image, cfg)
ref, err := reference.Parse(fullImageName)
if err != nil {
return nil, errors.Wrapf(err, "bad image: %s", image)
return nil, errors.Wrapf(err, "bad image: %s", fullImageName)
}
var registry, path, name, tag, digest string
if named, ok := ref.(reference.Named); ok {
registry = reference.Domain(named)
path = reference.Path(named)
name = path[strings.LastIndex(path, "/")+1:]
}
if tagged, ok := ref.(reference.Tagged); ok {
tag = tagged.Tag()
}
if digested, ok := ref.(reference.Digested); ok {
digest = digested.Digest().String()
}
// set default tag - the domain is set via addDefaultDomain before parsing
// set default tag - the domain is set via addDefaultRegistry before parsing
if digest == "" && tag == "" {
tag = "latest"
}
// if registry mutation isn't enabled don't add the default registry
if fullImageName != image && !config.Configuration.GetEnableDefaultRegistryMutation(cfg) {
registry = ""
}
logger.V(2).Info(
"Getting the image info",
"image", image,
"registry", registry,
"name", name,
"path", path,
"tag", tag,
"digest", digest,
)
return &ImageInfo{
Registry: registry,
Name: name,
@ -68,10 +106,11 @@ func GetImageInfo(image string) (*ImageInfo, error) {
}, nil
}
func addDefaultDomain(name string) string {
// addDefaultRegistry always adds default registry
func addDefaultRegistry(name string, cfg config.Configuration) string {
i := strings.IndexRune(name, '/')
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost" && strings.ToLower(name[:i]) == name[:i]) {
return "docker.io/" + name
name = fmt.Sprintf("%s/%s", config.Configuration.GetDefaultRegistry(cfg), name)
}
return name
}

View file

@ -1,11 +1,33 @@
package image
import (
"strconv"
"testing"
"github.com/kyverno/kyverno/pkg/config"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)
// initializeMockConfig initializes a basic configuration with a fake dynamic client
func initializeMockConfig(defaultRegistry string, enableDefaultRegistryMutation bool) (config.Configuration, error) {
configMapData := make(map[string]string, 0)
configMapData["defaultRegistry"] = defaultRegistry
configMapData["enableDefaultRegistryMutation"] = strconv.FormatBool(enableDefaultRegistryMutation)
cm := v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Namespace: "kyverno", Name: "kyverno"},
Data: configMapData,
}
cs := fake.NewSimpleClientset(&cm)
dynamicConfig, err := config.NewConfiguration(cs)
if err != nil {
return nil, err
}
return dynamicConfig, nil
}
func Test_GetImageInfo(t *testing.T) {
validateImageInfo(t,
"nginx",
@ -14,7 +36,9 @@ func Test_GetImageInfo(t *testing.T) {
"docker.io",
"latest",
"",
"docker.io/nginx:latest")
"docker.io/nginx:latest",
"docker.io",
true)
validateImageInfo(t,
"nginx:v10.3",
@ -23,7 +47,9 @@ func Test_GetImageInfo(t *testing.T) {
"docker.io",
"v10.3",
"",
"docker.io/nginx:v10.3")
"docker.io/nginx:v10.3",
"docker.io",
true)
validateImageInfo(t,
"docker.io/test/nginx:v10.3",
@ -32,7 +58,9 @@ func Test_GetImageInfo(t *testing.T) {
"docker.io",
"v10.3",
"",
"docker.io/test/nginx:v10.3")
"docker.io/test/nginx:v10.3",
"docker.io",
true)
validateImageInfo(t,
"test/nginx",
@ -41,7 +69,9 @@ func Test_GetImageInfo(t *testing.T) {
"docker.io",
"latest",
"",
"docker.io/test/nginx:latest")
"docker.io/test/nginx:latest",
"docker.io",
true)
validateImageInfo(t,
"localhost:4443/test/nginx",
@ -50,7 +80,10 @@ func Test_GetImageInfo(t *testing.T) {
"localhost:4443",
"latest",
"",
"localhost:4443/test/nginx:latest")
"localhost:4443/test/nginx:latest",
"docker.io",
true)
validateImageInfo(t,
"docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
"centos",
@ -58,7 +91,31 @@ func Test_GetImageInfo(t *testing.T) {
"docker.io",
"",
"sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
"docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f")
"docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
"docker.io",
true)
validateImageInfo(t,
"test/nginx",
"nginx",
"test/nginx",
"gcr.io",
"latest",
"",
"gcr.io/test/nginx:latest",
"gcr.io",
true)
validateImageInfo(t,
"test/nginx",
"nginx",
"test/nginx",
"",
"latest",
"",
"test/nginx:latest",
"gcr.io",
false)
}
func Test_ReferenceWithTag(t *testing.T) {
@ -84,8 +141,10 @@ func Test_ReferenceWithTag(t *testing.T) {
input: "docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
expected: "docker.io/test/centos:",
}}
cfg, err := initializeMockConfig("docker.io", true)
assert.NoError(t, err)
for _, test := range testCases {
imageInfo, err := GetImageInfo(test.input)
imageInfo, err := GetImageInfo(test.input, cfg)
assert.NoError(t, err)
assert.Equal(t, test.expected, imageInfo.ReferenceWithTag())
}
@ -95,15 +154,20 @@ func Test_ParseError(t *testing.T) {
testCases := []string{
"++",
}
cfg, err := initializeMockConfig("docker.io", true)
assert.NoError(t, err)
for _, test := range testCases {
imageInfo, err := GetImageInfo(test)
imageInfo, err := GetImageInfo(test, cfg)
assert.Error(t, err)
assert.Nil(t, imageInfo)
}
}
func validateImageInfo(t *testing.T, raw, name, path, registry, tag, digest, str string) {
i1, err := GetImageInfo(raw)
func validateImageInfo(t *testing.T, raw, name, path, registry, tag, digest, str string, defautRegistry string, enableDefaultRegistryMutation bool) {
cfg, err := initializeMockConfig(defautRegistry, enableDefaultRegistryMutation)
assert.NoError(t, err)
i1, err := GetImageInfo(raw, cfg)
assert.NoError(t, err)
assert.Equal(t, name, i1.Name)
assert.Equal(t, path, i1.Path)
@ -112,3 +176,56 @@ func validateImageInfo(t *testing.T, raw, name, path, registry, tag, digest, str
assert.Equal(t, digest, i1.Digest)
assert.Equal(t, str, i1.String())
}
func Test_addDefaultRegistry(t *testing.T) {
tests := []struct {
input string
defaultRegistry string
enableDefaultRegistryMutation bool
want string
}{
{
defaultRegistry: "test.io",
enableDefaultRegistryMutation: true,
input: "docker.io/test/nginx:v10.4",
want: "docker.io/test/nginx:v10.4",
},
{
defaultRegistry: "docker.io",
enableDefaultRegistryMutation: true,
input: "test/nginx:v10.3",
want: "docker.io/test/nginx:v10.3",
},
{
defaultRegistry: "myregistry.io",
enableDefaultRegistryMutation: false,
input: "test/nginx:v10.6",
want: "myregistry.io/test/nginx:v10.6",
},
{
input: "localhost/netd:v0.4.4-gke.0",
defaultRegistry: "docker.io",
enableDefaultRegistryMutation: true,
want: "localhost/netd:v0.4.4-gke.0",
},
{
input: "myregistry.org/test/nginx:v10.3",
defaultRegistry: "docker.io",
enableDefaultRegistryMutation: false,
want: "myregistry.org/test/nginx:v10.3",
},
{
input: "test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
defaultRegistry: "docker.io",
enableDefaultRegistryMutation: true,
want: "docker.io/test/centos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f",
},
}
for _, tt := range tests {
cfg, err := initializeMockConfig(tt.defaultRegistry, true)
assert.NoError(t, err)
got := addDefaultRegistry(tt.input, cfg)
assert.Equal(t, tt.want, got)
}
}

View file

@ -137,7 +137,7 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad
namespaceLabels = engineutils.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, logger)
}
vh := validation.NewValidationHandler(logger, h.kyvernoClient, h.rclient, h.pCache, h.pcBuilder, h.eventGen, h.admissionReports, h.metricsConfig)
vh := validation.NewValidationHandler(logger, h.kyvernoClient, h.rclient, h.pCache, h.pcBuilder, h.eventGen, h.admissionReports, h.metricsConfig, h.configuration)
ok, msg, warnings := vh.HandleValidation(ctx, request, policies, policyContext, namespaceLabels, startTime)
if !ok {
@ -184,7 +184,7 @@ func (h *handlers) Mutate(ctx context.Context, logger logr.Logger, request *admi
logger.Error(err, "failed to build policy context")
return admissionutils.Response(request.UID, err)
}
ivh := imageverification.NewImageVerificationHandler(logger, h.kyvernoClient, h.rclient, h.eventGen, h.admissionReports)
ivh := imageverification.NewImageVerificationHandler(logger, h.kyvernoClient, h.rclient, h.eventGen, h.admissionReports, h.configuration)
imagePatches, imageVerifyWarnings, err := ivh.Handle(ctx, newRequest, verifyImagesPolicies, policyContext)
if err != nil {
logger.Error(err, "image verification failed")

View file

@ -9,6 +9,7 @@ import (
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/event"
@ -35,6 +36,7 @@ type imageVerificationHandler struct {
log logr.Logger
eventGen event.Interface
admissionReports bool
cfg config.Configuration
}
func NewImageVerificationHandler(
@ -43,6 +45,7 @@ func NewImageVerificationHandler(
rclient registryclient.Client,
eventGen event.Interface,
admissionReports bool,
cfg config.Configuration,
) ImageVerificationHandler {
return &imageVerificationHandler{
kyvernoClient: kyvernoClient,
@ -50,6 +53,7 @@ func NewImageVerificationHandler(
log: log,
eventGen: eventGen,
admissionReports: admissionReports,
cfg: cfg,
}
}
@ -87,7 +91,7 @@ func (h *imageVerificationHandler) handleVerifyImages(
fmt.Sprintf("POLICY %s/%s", policy.GetNamespace(), policy.GetName()),
func(ctx context.Context, span trace.Span) {
policyContext := policyContext.WithPolicy(policy)
resp, ivm := engine.VerifyAndPatchImages(ctx, h.rclient, policyContext)
resp, ivm := engine.VerifyAndPatchImages(ctx, h.rclient, policyContext, h.cfg)
engineResponses = append(engineResponses, resp)
patches = append(patches, resp.GetPatches()...)

View file

@ -9,6 +9,7 @@ import (
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/event"
@ -43,6 +44,7 @@ func NewValidationHandler(
eventGen event.Interface,
admissionReports bool,
metrics metrics.MetricsConfigManager,
cfg config.Configuration,
) ValidationHandler {
return &validationHandler{
log: log,
@ -53,6 +55,7 @@ func NewValidationHandler(
eventGen: eventGen,
admissionReports: admissionReports,
metrics: metrics,
cfg: cfg,
}
}
@ -65,6 +68,7 @@ type validationHandler struct {
eventGen event.Interface
admissionReports bool
metrics metrics.MetricsConfigManager
cfg config.Configuration
}
func (v *validationHandler) HandleValidation(
@ -110,7 +114,7 @@ func (v *validationHandler) HandleValidation(
failurePolicy = kyvernov1.Fail
}
engineResponse := engine.Validate(ctx, v.rclient, policyContext)
engineResponse := engine.Validate(ctx, v.rclient, policyContext, v.cfg)
if engineResponse.IsNil() {
// we get an empty response if old and new resources created the same response
// allow updates if resource update doesnt change the policy evaluation
@ -169,7 +173,7 @@ func (v *validationHandler) buildAuditResponses(
fmt.Sprintf("POLICY %s/%s", policy.GetNamespace(), policy.GetName()),
func(ctx context.Context, span trace.Span) {
policyContext := policyContext.WithPolicy(policy).WithNamespaceLabels(namespaceLabels)
responses = append(responses, engine.Validate(ctx, v.rclient, policyContext))
responses = append(responses, engine.Validate(ctx, v.rclient, policyContext, v.cfg))
},
)
}

View file

@ -6,6 +6,7 @@ import (
"fmt"
"testing"
"github.com/kyverno/kyverno/pkg/config"
log "github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/registryclient"
@ -34,7 +35,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
},
"spec": {
"validationFailureAction": "audit",
"validationFailureActionOverrides":
"validationFailureActionOverrides":
[
{
"action": "enforce",
@ -104,7 +105,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
},
"spec": {
"validationFailureAction": "audit",
"validationFailureActionOverrides":
"validationFailureActionOverrides":
[
{
"action": "enforce",
@ -176,7 +177,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
},
"spec": {
"validationFailureAction": "audit",
"validationFailureActionOverrides":
"validationFailureActionOverrides":
[
{
"action": "enforce",
@ -246,7 +247,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
"validationFailureActionOverrides":
[
{
"action": "enforce",
@ -316,7 +317,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
"validationFailureActionOverrides":
[
{
"action": "enforce",
@ -388,7 +389,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
"validationFailureActionOverrides":
[
{
"action": "enforce",
@ -458,7 +459,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
"validationFailureActionOverrides":
[
{
"action": "enforce",
@ -523,6 +524,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
},
}
cfg := config.NewDefaultConfiguration()
for i, tc := range testcases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
var policy kyvernov1.ClusterPolicy
@ -535,6 +537,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
context.TODO(),
registryclient.NewOrDie(),
engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured),
cfg,
)
if tc.blocked && tc.messages != nil {
for _, r := range er.PolicyResponse.Rules {
@ -563,7 +566,7 @@ func Test_RuleSelector(t *testing.T) {
"match": {"name": "test-*", "resources": {"kinds": ["Pod"]}},
"validate": {
"message": "The label 'app' is required.",
"pattern": { "metadata": { "labels": { "app": "?*" } } }
"pattern": { "metadata": { "labels": { "app": "?*" } } }
}
},
{
@ -571,7 +574,7 @@ func Test_RuleSelector(t *testing.T) {
"match": {"name": "*", "resources": {"kinds": ["Pod"]}},
"validate": {
"message": "The label 'app' is required.",
"pattern": { "metadata": { "labels": { "app": "?*", "test" : "?*" } } }
"pattern": { "metadata": { "labels": { "app": "?*", "test" : "?*" } } }
}
}
]
@ -595,7 +598,8 @@ func Test_RuleSelector(t *testing.T) {
ctx := engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured)
resp := engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx)
cfg := config.NewDefaultConfiguration()
resp := engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx, cfg)
assert.Assert(t, resp.PolicyResponse.RulesAppliedCount == 2)
assert.Assert(t, resp.PolicyResponse.RulesErrorCount == 0)
@ -606,7 +610,7 @@ func Test_RuleSelector(t *testing.T) {
applyOne := kyvernov1.ApplyOne
policy.Spec.ApplyRules = &applyOne
resp = engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx)
resp = engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx, cfg)
assert.Assert(t, resp.PolicyResponse.RulesAppliedCount == 1)
assert.Assert(t, resp.PolicyResponse.RulesErrorCount == 0)