1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-01-20 18:52:16 +00:00

refactor: do not allow matching with subresource kind (#6625)

* refactor: do not allow matching with subresource kind

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix kuttl

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix kuttl

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fixes

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

---------

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-03-21 14:28:00 +01:00 committed by GitHub
parent 08def22d04
commit e06c20f5cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 166 additions and 214 deletions

View file

@ -16,10 +16,20 @@ import (
// GroupVersionResourceSubresource contains a group/version/resource/subresource reference // GroupVersionResourceSubresource contains a group/version/resource/subresource reference
type GroupVersionResourceSubresource struct { type GroupVersionResourceSubresource struct {
schema.GroupVersionResource schema.GroupVersion
Kind string
Resource string
SubResource string SubResource string
} }
func (gvrs GroupVersionResourceSubresource) GroupVersionResource() schema.GroupVersionResource {
return gvrs.WithResource(gvrs.Resource)
}
func (gvrs GroupVersionResourceSubresource) GroupVersionKind() schema.GroupVersionKind {
return gvrs.WithKind(gvrs.Kind)
}
func (gvrs GroupVersionResourceSubresource) ResourceSubresource() string { func (gvrs GroupVersionResourceSubresource) ResourceSubresource() string {
if gvrs.SubResource == "" { if gvrs.SubResource == "" {
return gvrs.Resource return gvrs.Resource
@ -206,7 +216,9 @@ func (c serverResources) findResources(group, version, kind, subresource string)
gvk := getGVK(gv, resource.Group, resource.Version, resource.Kind) gvk := getGVK(gv, resource.Group, resource.Version, resource.Kind)
if wildcard.Match(group, gvk.Group) && wildcard.Match(version, gvk.Version) && wildcard.Match(kind, gvk.Kind) { if wildcard.Match(group, gvk.Group) && wildcard.Match(version, gvk.Version) && wildcard.Match(kind, gvk.Kind) {
gvrs := GroupVersionResourceSubresource{ gvrs := GroupVersionResourceSubresource{
GroupVersionResource: gv.WithResource(resource.Name), GroupVersion: gv,
Kind: resource.Kind,
Resource: resource.Name,
} }
resources[gvrs] = resource resources[gvrs] = resource
} }
@ -229,27 +241,6 @@ func (c serverResources) findResources(group, version, kind, subresource string)
} }
} }
} }
// third if no resource matched, try again but consider subresources this time
if len(resources) == 0 {
for _, list := range serverGroupsAndResources {
gv, err := schema.ParseGroupVersion(list.GroupVersion)
if err != nil {
return nil, err
} else {
for _, resource := range list.APIResources {
gvk := getGVK(gv, resource.Group, resource.Version, resource.Kind)
if wildcard.Match(group, gvk.Group) && wildcard.Match(version, gvk.Version) && wildcard.Match(kind, gvk.Kind) {
parts := strings.Split(resource.Name, "/")
gvrs := GroupVersionResourceSubresource{
GroupVersionResource: gv.WithResource(parts[0]),
SubResource: parts[1],
}
resources[gvrs] = resource
}
}
}
}
}
if kind == "*" && subresource == "*" { if kind == "*" && subresource == "*" {
for key, value := range subresources { for key, value := range subresources {
resources[key] = value resources[key] = value

View file

@ -235,7 +235,7 @@ func (c *controller) updateDynamicWatchers(ctx context.Context) error {
logger.Info("kind is not supported", "gvk", gvk) logger.Info("kind is not supported", "gvk", gvk)
} else { } else {
if slices.Contains(api.Verbs, "list") && slices.Contains(api.Verbs, "watch") { if slices.Contains(api.Verbs, "list") && slices.Contains(api.Verbs, "watch") {
gvkToGvr[gvk] = gvrs.GroupVersionResource gvkToGvr[gvk] = gvrs.GroupVersionResource()
} else { } else {
logger.Info("list/watch not supported for kind", "kind", kind) logger.Info("list/watch not supported for kind", "kind", kind)
} }

View file

@ -829,25 +829,17 @@ func (c *controller) mergeWebhook(dst *webhook, policy kyvernov1.PolicyInterface
matchedGVK = append(matchedGVK, rule.MatchResources.GetKinds()...) matchedGVK = append(matchedGVK, rule.MatchResources.GetKinds()...)
} }
} }
var gvrsList []dclient.GroupVersionResourceSubresource var gvrsList []schema.GroupVersionResource
for _, gvk := range matchedGVK { for _, gvk := range matchedGVK {
// NOTE: webhook stores GVR in its rules while policy stores GVK in its rules definition // NOTE: webhook stores GVR in its rules while policy stores GVK in its rules definition
group, version, kind, subresource := kubeutils.ParseKindSelector(gvk) group, version, kind, subresource := kubeutils.ParseKindSelector(gvk)
// if kind is `*` no need to lookup resources // if kind is `*` no need to lookup resources
if kind == "*" && subresource == "*" { if kind == "*" && subresource == "*" {
gvrsList = append(gvrsList, dclient.GroupVersionResourceSubresource{ gvrsList = append(gvrsList, schema.GroupVersionResource{Group: group, Version: version, Resource: "*/*"})
GroupVersionResource: schema.GroupVersionResource{Group: group, Version: version, Resource: "*"},
SubResource: "*",
})
} else if kind == "*" && subresource == "" { } else if kind == "*" && subresource == "" {
gvrsList = append(gvrsList, dclient.GroupVersionResourceSubresource{ gvrsList = append(gvrsList, schema.GroupVersionResource{Group: group, Version: version, Resource: "*"})
GroupVersionResource: schema.GroupVersionResource{Group: group, Version: version, Resource: "*"},
})
} else if kind == "*" && subresource != "" { } else if kind == "*" && subresource != "" {
gvrsList = append(gvrsList, dclient.GroupVersionResourceSubresource{ gvrsList = append(gvrsList, schema.GroupVersionResource{Group: group, Version: version, Resource: "*/" + subresource})
GroupVersionResource: schema.GroupVersionResource{Group: group, Version: version, Resource: "*"},
SubResource: subresource,
})
} else { } else {
gvrss, err := c.discoveryClient.FindResources(group, version, kind, subresource) gvrss, err := c.discoveryClient.FindResources(group, version, kind, subresource)
if err != nil { if err != nil {
@ -855,7 +847,7 @@ func (c *controller) mergeWebhook(dst *webhook, policy kyvernov1.PolicyInterface
continue continue
} }
for gvrs := range gvrss { for gvrs := range gvrss {
gvrsList = append(gvrsList, gvrs) gvrsList = append(gvrsList, gvrs.GroupVersion.WithResource(gvrs.ResourceSubresource()))
} }
} }
} }

View file

@ -4,7 +4,6 @@ import (
"strings" "strings"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/utils" "github.com/kyverno/kyverno/pkg/utils"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1" admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
@ -71,13 +70,13 @@ func (wh *webhook) buildRulesWithOperations(ops ...admissionregistrationv1.Opera
return rules return rules
} }
func (wh *webhook) set(gvrs dclient.GroupVersionResourceSubresource) { func (wh *webhook) set(gvrs schema.GroupVersionResource) {
gv := gvrs.GroupVersion() gv := gvrs.GroupVersion()
resources := wh.rules[gv] resources := wh.rules[gv]
if resources == nil { if resources == nil {
wh.rules[gv] = sets.New(gvrs.ResourceSubresource()) wh.rules[gv] = sets.New(gvrs.Resource)
} else { } else {
resources.Insert(gvrs.ResourceSubresource()) resources.Insert(gvrs.Resource)
} }
} }

View file

@ -6,7 +6,6 @@ import (
kyverno "github.com/kyverno/kyverno/api/kyverno/v1" kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"gotest.tools/assert" "gotest.tools/assert"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1" admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
@ -17,10 +16,8 @@ func Test_webhook_isEmpty(t *testing.T) {
empty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore) empty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore)
assert.Equal(t, empty.isEmpty(), true) assert.Equal(t, empty.isEmpty(), true)
notEmpty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore) notEmpty := newWebhook(DefaultWebhookTimeout, admissionregistrationv1.Ignore)
notEmpty.set(dclient.GroupVersionResourceSubresource{ notEmpty.set(schema.GroupVersionResource{
GroupVersionResource: schema.GroupVersionResource{ Group: "", Version: "v1", Resource: "pods",
Group: "", Version: "v1", Resource: "pods",
},
}) })
assert.Equal(t, notEmpty.isEmpty(), false) assert.Equal(t, notEmpty.isEmpty(), false)
} }

View file

@ -83,7 +83,7 @@ func getTargets(client dclient.Interface, target kyvernov1.ResourceSpec, ctx eng
return nil, err return nil, err
} }
for gvrs := range gvrss { for gvrs := range gvrss {
dyn := client.GetDynamicInterface().Resource(gvrs.GroupVersionResource) dyn := client.GetDynamicInterface().Resource(gvrs.GroupVersionResource())
var sub []string var sub []string
if gvrs.SubResource != "" { if gvrs.SubResource != "" {
sub = []string{gvrs.SubResource} sub = []string{gvrs.SubResource}
@ -96,7 +96,11 @@ func getTargets(client dclient.Interface, target kyvernov1.ResourceSpec, ctx eng
if err != nil { if err != nil {
return nil, err return nil, err
} }
targetObjects = append(targetObjects, resourceInfo{unstructured: *obj, subresource: gvrs.SubResource, parentResourceGVR: metav1.GroupVersionResource(gvrs.GroupVersionResource)}) targetObjects = append(targetObjects, resourceInfo{
unstructured: *obj,
subresource: gvrs.SubResource,
parentResourceGVR: metav1.GroupVersionResource(gvrs.GroupVersionResource()),
})
} else { } else {
// we can use `LIST` // we can use `LIST`
if gvrs.SubResource == "" { if gvrs.SubResource == "" {
@ -132,7 +136,11 @@ func getTargets(client dclient.Interface, target kyvernov1.ResourceSpec, ctx eng
if err != nil { if err != nil {
return nil, err return nil, err
} }
targetObjects = append(targetObjects, resourceInfo{unstructured: *obj, subresource: gvrs.SubResource, parentResourceGVR: metav1.GroupVersionResource(gvrs.GroupVersionResource)}) targetObjects = append(targetObjects, resourceInfo{
unstructured: *obj,
subresource: gvrs.SubResource,
parentResourceGVR: metav1.GroupVersionResource(gvrs.GroupVersionResource()),
})
} }
} }
} }

View file

@ -5,6 +5,7 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/utils/wildcard" "github.com/kyverno/kyverno/pkg/utils/wildcard"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
) )
type ResourceFinder interface { type ResourceFinder interface {
@ -19,7 +20,7 @@ type Cache interface {
Unset(string) Unset(string)
// GetPolicies returns all policies that apply to a namespace, including cluster-wide policies // GetPolicies returns all policies that apply to a namespace, including cluster-wide policies
// If the namespace is empty, only cluster-wide policies are returned // If the namespace is empty, only cluster-wide policies are returned
GetPolicies(PolicyType, dclient.GroupVersionResourceSubresource, string) []kyvernov1.PolicyInterface GetPolicies(PolicyType, schema.GroupVersionResource, string, string) []kyvernov1.PolicyInterface
} }
type cache struct { type cache struct {
@ -41,15 +42,15 @@ func (c *cache) Unset(key string) {
c.store.unset(key) c.store.unset(key)
} }
func (c *cache) GetPolicies(pkey PolicyType, gvrs dclient.GroupVersionResourceSubresource, nspace string) []kyvernov1.PolicyInterface { func (c *cache) GetPolicies(pkey PolicyType, gvr schema.GroupVersionResource, subresource string, nspace string) []kyvernov1.PolicyInterface {
var result []kyvernov1.PolicyInterface var result []kyvernov1.PolicyInterface
result = append(result, c.store.get(pkey, gvrs, "")...) result = append(result, c.store.get(pkey, gvr, subresource, "")...)
if nspace != "" { if nspace != "" {
result = append(result, c.store.get(pkey, gvrs, nspace)...) result = append(result, c.store.get(pkey, gvr, subresource, nspace)...)
} }
// also get policies with ValidateEnforce // also get policies with ValidateEnforce
if pkey == ValidateAudit { if pkey == ValidateAudit {
result = append(result, c.store.get(ValidateEnforce, gvrs, "")...) result = append(result, c.store.get(ValidateEnforce, gvr, subresource, "")...)
} }
if pkey == ValidateAudit || pkey == ValidateEnforce { if pkey == ValidateAudit || pkey == ValidateEnforce {
result = filterPolicies(pkey, result, nspace) result = filterPolicies(pkey, result, nspace)

View file

@ -35,15 +35,15 @@ func Test_All(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
// get // get
mutate := pCache.get(Mutate, gvr, "") mutate := pCache.get(Mutate, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
validateEnforce := pCache.get(ValidateEnforce, gvr, "") validateEnforce := pCache.get(ValidateEnforce, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate policy, found %v", len(validateEnforce))
} }
generate := pCache.get(Generate, gvr, "") generate := pCache.get(Generate, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
@ -53,7 +53,7 @@ func Test_All(t *testing.T) {
// remove // remove
unsetPolicy(pCache, policy) unsetPolicy(pCache, policy)
validateEnforce := pCache.get(ValidateEnforce, podsGVRS, "") validateEnforce := pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "")
assert.Assert(t, len(validateEnforce) == 0) assert.Assert(t, len(validateEnforce) == 0)
} }
@ -70,16 +70,16 @@ func Test_Add_Duplicate_Policy(t *testing.T) {
gvrs, err := finder.FindResources(group, version, kind, subresource) gvrs, err := finder.FindResources(group, version, kind, subresource)
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
mutate := pCache.get(Mutate, gvr, "") mutate := pCache.get(Mutate, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
validateEnforce := pCache.get(ValidateEnforce, gvr, "") validateEnforce := pCache.get(ValidateEnforce, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate policy, found %v", len(validateEnforce))
} }
generate := pCache.get(Generate, gvr, "") generate := pCache.get(Generate, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
@ -103,12 +103,12 @@ func Test_Add_Validate_Audit(t *testing.T) {
gvrs, err := finder.FindResources(group, version, kind, subresource) gvrs, err := finder.FindResources(group, version, kind, subresource)
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
validateEnforce := pCache.get(ValidateEnforce, gvr, "") validateEnforce := pCache.get(ValidateEnforce, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(validateEnforce) != 0 { if len(validateEnforce) != 0 {
t.Errorf("expected 0 validate (enforce) policy, found %v", len(validateEnforce)) t.Errorf("expected 0 validate (enforce) policy, found %v", len(validateEnforce))
} }
validateAudit := pCache.get(ValidateAudit, gvr, "") validateAudit := pCache.get(ValidateAudit, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(validateAudit) != 1 { if len(validateAudit) != 1 {
t.Errorf("expected 1 validate (audit) policy, found %v", len(validateAudit)) t.Errorf("expected 1 validate (audit) policy, found %v", len(validateAudit))
} }
@ -122,20 +122,20 @@ func Test_Add_Remove(t *testing.T) {
policy := newPolicy(t) policy := newPolicy(t)
finder := TestResourceFinder{} finder := TestResourceFinder{}
setPolicy(t, pCache, policy, finder) setPolicy(t, pCache, policy, finder)
validateEnforce := pCache.get(ValidateEnforce, podsGVRS, "") validateEnforce := pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "")
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce))
} }
mutate := pCache.get(Mutate, podsGVRS, "") mutate := pCache.get(Mutate, podsGVRS.GroupVersionResource(), "", "")
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
generate := pCache.get(Generate, podsGVRS, "") generate := pCache.get(Generate, podsGVRS.GroupVersionResource(), "", "")
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
unsetPolicy(pCache, policy) unsetPolicy(pCache, policy)
deletedValidateEnforce := pCache.get(ValidateEnforce, podsGVRS, "") deletedValidateEnforce := pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "")
if len(deletedValidateEnforce) != 0 { if len(deletedValidateEnforce) != 0 {
t.Errorf("expected 0 validate enforce policy, found %v", len(deletedValidateEnforce)) t.Errorf("expected 0 validate enforce policy, found %v", len(deletedValidateEnforce))
} }
@ -146,20 +146,20 @@ func Test_Add_Remove_Any(t *testing.T) {
policy := newAnyPolicy(t) policy := newAnyPolicy(t)
finder := TestResourceFinder{} finder := TestResourceFinder{}
setPolicy(t, pCache, policy, finder) setPolicy(t, pCache, policy, finder)
validateEnforce := pCache.get(ValidateEnforce, podsGVRS, "") validateEnforce := pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "")
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce))
} }
mutate := pCache.get(Mutate, podsGVRS, "") mutate := pCache.get(Mutate, podsGVRS.GroupVersionResource(), "", "")
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
generate := pCache.get(Generate, podsGVRS, "") generate := pCache.get(Generate, podsGVRS.GroupVersionResource(), "", "")
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
unsetPolicy(pCache, policy) unsetPolicy(pCache, policy)
deletedValidateEnforce := pCache.get(ValidateEnforce, podsGVRS, "") deletedValidateEnforce := pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "")
if len(deletedValidateEnforce) != 0 { if len(deletedValidateEnforce) != 0 {
t.Errorf("expected 0 validate enforce policy, found %v", len(deletedValidateEnforce)) t.Errorf("expected 0 validate enforce policy, found %v", len(deletedValidateEnforce))
} }
@ -901,15 +901,15 @@ func Test_Ns_All(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
// get // get
mutate := pCache.get(Mutate, gvr, nspace) mutate := pCache.get(Mutate, gvr.GroupVersionResource(), gvr.SubResource, nspace)
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
validateEnforce := pCache.get(ValidateEnforce, gvr, nspace) validateEnforce := pCache.get(ValidateEnforce, gvr.GroupVersionResource(), gvr.SubResource, nspace)
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate policy, found %v", len(validateEnforce))
} }
generate := pCache.get(Generate, gvr, nspace) generate := pCache.get(Generate, gvr.GroupVersionResource(), gvr.SubResource, nspace)
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
@ -918,7 +918,7 @@ func Test_Ns_All(t *testing.T) {
} }
// remove // remove
unsetPolicy(pCache, policy) unsetPolicy(pCache, policy)
validateEnforce := pCache.get(ValidateEnforce, podsGVRS, nspace) validateEnforce := pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", nspace)
assert.Assert(t, len(validateEnforce) == 0) assert.Assert(t, len(validateEnforce) == 0)
} }
@ -936,15 +936,15 @@ func Test_Ns_Add_Duplicate_Policy(t *testing.T) {
gvrs, err := finder.FindResources(group, version, kind, subresource) gvrs, err := finder.FindResources(group, version, kind, subresource)
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
mutate := pCache.get(Mutate, gvr, nspace) mutate := pCache.get(Mutate, gvr.GroupVersionResource(), gvr.SubResource, nspace)
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
validateEnforce := pCache.get(ValidateEnforce, gvr, nspace) validateEnforce := pCache.get(ValidateEnforce, gvr.GroupVersionResource(), gvr.SubResource, nspace)
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate policy, found %v", len(validateEnforce))
} }
generate := pCache.get(Generate, gvr, nspace) generate := pCache.get(Generate, gvr.GroupVersionResource(), gvr.SubResource, nspace)
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
@ -969,12 +969,12 @@ func Test_Ns_Add_Validate_Audit(t *testing.T) {
gvrs, err := finder.FindResources(group, version, kind, subresource) gvrs, err := finder.FindResources(group, version, kind, subresource)
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
validateEnforce := pCache.get(ValidateEnforce, gvr, nspace) validateEnforce := pCache.get(ValidateEnforce, gvr.GroupVersionResource(), gvr.SubResource, nspace)
if len(validateEnforce) != 0 { if len(validateEnforce) != 0 {
t.Errorf("expected 0 validate (enforce) policy, found %v", len(validateEnforce)) t.Errorf("expected 0 validate (enforce) policy, found %v", len(validateEnforce))
} }
validateAudit := pCache.get(ValidateAudit, gvr, nspace) validateAudit := pCache.get(ValidateAudit, gvr.GroupVersionResource(), gvr.SubResource, nspace)
if len(validateAudit) != 1 { if len(validateAudit) != 1 {
t.Errorf("expected 1 validate (audit) policy, found %v", len(validateAudit)) t.Errorf("expected 1 validate (audit) policy, found %v", len(validateAudit))
} }
@ -989,12 +989,12 @@ func Test_Ns_Add_Remove(t *testing.T) {
finder := TestResourceFinder{} finder := TestResourceFinder{}
nspace := policy.GetNamespace() nspace := policy.GetNamespace()
setPolicy(t, pCache, policy, finder) setPolicy(t, pCache, policy, finder)
validateEnforce := pCache.get(ValidateEnforce, podsGVRS, nspace) validateEnforce := pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", nspace)
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce))
} }
unsetPolicy(pCache, policy) unsetPolicy(pCache, policy)
deletedValidateEnforce := pCache.get(ValidateEnforce, podsGVRS, nspace) deletedValidateEnforce := pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", nspace)
if len(deletedValidateEnforce) != 0 { if len(deletedValidateEnforce) != 0 {
t.Errorf("expected 0 validate enforce policy, found %v", len(deletedValidateEnforce)) t.Errorf("expected 0 validate enforce policy, found %v", len(deletedValidateEnforce))
} }
@ -1012,7 +1012,7 @@ func Test_GVk_Cache(t *testing.T) {
gvrs, err := finder.FindResources(group, version, kind, subresource) gvrs, err := finder.FindResources(group, version, kind, subresource)
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
generate := pCache.get(Generate, gvr, "") generate := pCache.get(Generate, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
@ -1026,12 +1026,12 @@ func Test_GVK_Add_Remove(t *testing.T) {
policy := newGVKPolicy(t) policy := newGVKPolicy(t)
finder := TestResourceFinder{} finder := TestResourceFinder{}
setPolicy(t, pCache, policy, finder) setPolicy(t, pCache, policy, finder)
generate := pCache.get(Generate, clusterrolesGVRS, "") generate := pCache.get(Generate, clusterrolesGVRS.GroupVersionResource(), "", "")
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
unsetPolicy(pCache, policy) unsetPolicy(pCache, policy)
deletedGenerate := pCache.get(Generate, clusterrolesGVRS, "") deletedGenerate := pCache.get(Generate, clusterrolesGVRS.GroupVersionResource(), "", "")
if len(deletedGenerate) != 0 { if len(deletedGenerate) != 0 {
t.Errorf("expected 0 generate policy, found %v", len(deletedGenerate)) t.Errorf("expected 0 generate policy, found %v", len(deletedGenerate))
} }
@ -1050,7 +1050,7 @@ func Test_Add_Validate_Enforce(t *testing.T) {
gvrs, err := finder.FindResources(group, version, kind, subresource) gvrs, err := finder.FindResources(group, version, kind, subresource)
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
validateEnforce := pCache.get(ValidateEnforce, gvr, nspace) validateEnforce := pCache.get(ValidateEnforce, gvr.GroupVersionResource(), gvr.SubResource, nspace)
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate policy, found %v", len(validateEnforce))
} }
@ -1066,12 +1066,12 @@ func Test_Ns_Add_Remove_User(t *testing.T) {
finder := TestResourceFinder{} finder := TestResourceFinder{}
// kind := "Deployment" // kind := "Deployment"
setPolicy(t, pCache, policy, finder) setPolicy(t, pCache, policy, finder)
validateEnforce := pCache.get(ValidateEnforce, deploymentsGVRS, nspace) validateEnforce := pCache.get(ValidateEnforce, deploymentsGVRS.GroupVersionResource(), "", nspace)
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce))
} }
unsetPolicy(pCache, policy) unsetPolicy(pCache, policy)
deletedValidateEnforce := pCache.get(ValidateEnforce, deploymentsGVRS, nspace) deletedValidateEnforce := pCache.get(ValidateEnforce, deploymentsGVRS.GroupVersionResource(), "", nspace)
if len(deletedValidateEnforce) != 0 { if len(deletedValidateEnforce) != 0 {
t.Errorf("expected 0 validate enforce policy, found %v", len(deletedValidateEnforce)) t.Errorf("expected 0 validate enforce policy, found %v", len(deletedValidateEnforce))
} }
@ -1092,7 +1092,7 @@ func Test_Mutate_Policy(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
// get // get
mutate := pCache.get(Mutate, gvr, "") mutate := pCache.get(Mutate, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
@ -1114,7 +1114,7 @@ func Test_Generate_Policy(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
for gvr := range gvrs { for gvr := range gvrs {
// get // get
generate := pCache.get(Generate, gvr, "") generate := pCache.get(Generate, gvr.GroupVersionResource(), gvr.SubResource, "")
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
@ -1135,12 +1135,12 @@ func Test_NsMutate_Policy(t *testing.T) {
setPolicy(t, pCache, nspolicy, finder) setPolicy(t, pCache, nspolicy, finder)
nspace := policy.GetNamespace() nspace := policy.GetNamespace()
// get // get
mutate := pCache.get(Mutate, statefulsetsGVRS, "") mutate := pCache.get(Mutate, statefulsetsGVRS.GroupVersionResource(), "", "")
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
// get // get
nsMutate := pCache.get(Mutate, statefulsetsGVRS, nspace) nsMutate := pCache.get(Mutate, statefulsetsGVRS.GroupVersionResource(), "", nspace)
if len(nsMutate) != 1 { if len(nsMutate) != 1 {
t.Errorf("expected 1 namespace mutate policy, found %v", len(nsMutate)) t.Errorf("expected 1 namespace mutate policy, found %v", len(nsMutate))
} }
@ -1153,21 +1153,21 @@ func Test_Validate_Enforce_Policy(t *testing.T) {
finder := TestResourceFinder{} finder := TestResourceFinder{}
setPolicy(t, pCache, policy1, finder) setPolicy(t, pCache, policy1, finder)
setPolicy(t, pCache, policy2, finder) setPolicy(t, pCache, policy2, finder)
validateEnforce := pCache.get(ValidateEnforce, podsGVRS, "") validateEnforce := pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "")
if len(validateEnforce) != 2 { if len(validateEnforce) != 2 {
t.Errorf("adding: expected 2 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("adding: expected 2 validate enforce policy, found %v", len(validateEnforce))
} }
validateAudit := pCache.get(ValidateAudit, podsGVRS, "") validateAudit := pCache.get(ValidateAudit, podsGVRS.GroupVersionResource(), "", "")
if len(validateAudit) != 0 { if len(validateAudit) != 0 {
t.Errorf("adding: expected 0 validate audit policy, found %v", len(validateAudit)) t.Errorf("adding: expected 0 validate audit policy, found %v", len(validateAudit))
} }
unsetPolicy(pCache, policy1) unsetPolicy(pCache, policy1)
unsetPolicy(pCache, policy2) unsetPolicy(pCache, policy2)
validateEnforce = pCache.get(ValidateEnforce, podsGVRS, "") validateEnforce = pCache.get(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "")
if len(validateEnforce) != 0 { if len(validateEnforce) != 0 {
t.Errorf("removing: expected 0 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("removing: expected 0 validate enforce policy, found %v", len(validateEnforce))
} }
validateAudit = pCache.get(ValidateAudit, podsGVRS, "") validateAudit = pCache.get(ValidateAudit, podsGVRS.GroupVersionResource(), "", "")
if len(validateAudit) != 0 { if len(validateAudit) != 0 {
t.Errorf("removing: expected 0 validate audit policy, found %v", len(validateAudit)) t.Errorf("removing: expected 0 validate audit policy, found %v", len(validateAudit))
} }
@ -1179,23 +1179,23 @@ func Test_Get_Policies(t *testing.T) {
finder := TestResourceFinder{} finder := TestResourceFinder{}
key, _ := kubecache.MetaNamespaceKeyFunc(policy) key, _ := kubecache.MetaNamespaceKeyFunc(policy)
cache.Set(key, policy, finder) cache.Set(key, policy, finder)
validateAudit := cache.GetPolicies(ValidateAudit, namespacesGVRS, "") validateAudit := cache.GetPolicies(ValidateAudit, namespacesGVRS.GroupVersionResource(), "", "")
if len(validateAudit) != 0 { if len(validateAudit) != 0 {
t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit)) t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit))
} }
validateAudit = cache.GetPolicies(ValidateAudit, podsGVRS, "test") validateAudit = cache.GetPolicies(ValidateAudit, podsGVRS.GroupVersionResource(), "", "test")
if len(validateAudit) != 0 { if len(validateAudit) != 0 {
t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit)) t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit))
} }
validateEnforce := cache.GetPolicies(ValidateEnforce, namespacesGVRS, "") validateEnforce := cache.GetPolicies(ValidateEnforce, namespacesGVRS.GroupVersionResource(), "", "")
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce))
} }
mutate := cache.GetPolicies(Mutate, podsGVRS, "") mutate := cache.GetPolicies(Mutate, podsGVRS.GroupVersionResource(), "", "")
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
generate := cache.GetPolicies(Generate, podsGVRS, "") generate := cache.GetPolicies(Generate, podsGVRS.GroupVersionResource(), "", "")
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
@ -1208,19 +1208,19 @@ func Test_Get_Policies_Ns(t *testing.T) {
key, _ := kubecache.MetaNamespaceKeyFunc(policy) key, _ := kubecache.MetaNamespaceKeyFunc(policy)
cache.Set(key, policy, finder) cache.Set(key, policy, finder)
nspace := policy.GetNamespace() nspace := policy.GetNamespace()
validateAudit := cache.GetPolicies(ValidateAudit, podsGVRS, nspace) validateAudit := cache.GetPolicies(ValidateAudit, podsGVRS.GroupVersionResource(), "", nspace)
if len(validateAudit) != 0 { if len(validateAudit) != 0 {
t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit)) t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit))
} }
validateEnforce := cache.GetPolicies(ValidateEnforce, podsGVRS, nspace) validateEnforce := cache.GetPolicies(ValidateEnforce, podsGVRS.GroupVersionResource(), "", nspace)
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce))
} }
mutate := cache.GetPolicies(Mutate, podsGVRS, nspace) mutate := cache.GetPolicies(Mutate, podsGVRS.GroupVersionResource(), "", nspace)
if len(mutate) != 1 { if len(mutate) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(mutate)) t.Errorf("expected 1 mutate policy, found %v", len(mutate))
} }
generate := cache.GetPolicies(Generate, podsGVRS, nspace) generate := cache.GetPolicies(Generate, podsGVRS.GroupVersionResource(), "", nspace)
if len(generate) != 1 { if len(generate) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(generate)) t.Errorf("expected 1 generate policy, found %v", len(generate))
} }
@ -1235,27 +1235,27 @@ func Test_Get_Policies_Validate_Failure_Action_Overrides(t *testing.T) {
cache.Set(key1, policy1, finder) cache.Set(key1, policy1, finder)
key2, _ := kubecache.MetaNamespaceKeyFunc(policy2) key2, _ := kubecache.MetaNamespaceKeyFunc(policy2)
cache.Set(key2, policy2, finder) cache.Set(key2, policy2, finder)
validateAudit := cache.GetPolicies(ValidateAudit, podsGVRS, "") validateAudit := cache.GetPolicies(ValidateAudit, podsGVRS.GroupVersionResource(), "", "")
if len(validateAudit) != 1 { if len(validateAudit) != 1 {
t.Errorf("expected 1 validate audit policy, found %v", len(validateAudit)) t.Errorf("expected 1 validate audit policy, found %v", len(validateAudit))
} }
validateEnforce := cache.GetPolicies(ValidateEnforce, podsGVRS, "") validateEnforce := cache.GetPolicies(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "")
if len(validateEnforce) != 1 { if len(validateEnforce) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce))
} }
validateAudit = cache.GetPolicies(ValidateAudit, podsGVRS, "test") validateAudit = cache.GetPolicies(ValidateAudit, podsGVRS.GroupVersionResource(), "", "test")
if len(validateAudit) != 2 { if len(validateAudit) != 2 {
t.Errorf("expected 2 validate audit policy, found %v", len(validateAudit)) t.Errorf("expected 2 validate audit policy, found %v", len(validateAudit))
} }
validateEnforce = cache.GetPolicies(ValidateEnforce, podsGVRS, "test") validateEnforce = cache.GetPolicies(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "test")
if len(validateEnforce) != 0 { if len(validateEnforce) != 0 {
t.Errorf("expected 0 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("expected 0 validate enforce policy, found %v", len(validateEnforce))
} }
validateAudit = cache.GetPolicies(ValidateAudit, podsGVRS, "default") validateAudit = cache.GetPolicies(ValidateAudit, podsGVRS.GroupVersionResource(), "", "default")
if len(validateAudit) != 0 { if len(validateAudit) != 0 {
t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit)) t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit))
} }
validateEnforce = cache.GetPolicies(ValidateEnforce, podsGVRS, "default") validateEnforce = cache.GetPolicies(ValidateEnforce, podsGVRS.GroupVersionResource(), "", "default")
if len(validateEnforce) != 2 { if len(validateEnforce) != 2 {
t.Errorf("expected 2 validate enforce policy, found %v", len(validateEnforce)) t.Errorf("expected 2 validate enforce policy, found %v", len(validateEnforce))
} }

View file

@ -5,9 +5,9 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/clients/dclient"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube" kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
"go.uber.org/multierr" "go.uber.org/multierr"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
kcache "k8s.io/client-go/tools/cache" kcache "k8s.io/client-go/tools/cache"
) )
@ -17,8 +17,8 @@ type store interface {
set(string, kyvernov1.PolicyInterface, ResourceFinder) error set(string, kyvernov1.PolicyInterface, ResourceFinder) error
// unset removes a policy from the cache // unset removes a policy from the cache
unset(string) unset(string)
// get finds policies that match a given type, gvr and namespace // get finds policies that match a given type, gvr, subresource and namespace
get(PolicyType, dclient.GroupVersionResourceSubresource, string) []kyvernov1.PolicyInterface get(PolicyType, schema.GroupVersionResource, string, string) []kyvernov1.PolicyInterface
} }
type policyCache struct { type policyCache struct {
@ -49,24 +49,33 @@ func (pc *policyCache) unset(key string) {
logger.V(4).Info("policy is removed from cache", "key", key) logger.V(4).Info("policy is removed from cache", "key", key)
} }
func (pc *policyCache) get(pkey PolicyType, gvrs dclient.GroupVersionResourceSubresource, nspace string) []kyvernov1.PolicyInterface { func (pc *policyCache) get(pkey PolicyType, gvr schema.GroupVersionResource, subresource string, nspace string) []kyvernov1.PolicyInterface {
pc.lock.RLock() pc.lock.RLock()
defer pc.lock.RUnlock() defer pc.lock.RUnlock()
return pc.store.get(pkey, gvrs, nspace) return pc.store.get(pkey, gvr, subresource, nspace)
} }
type policyKey struct {
Group string
Version string
Resource string
SubResource string
}
var podsKey = policyKey{"", "v1", "pods", ""}
type policyMap struct { type policyMap struct {
// policies maps names to policy interfaces // policies maps names to policy interfaces
policies map[string]kyvernov1.PolicyInterface policies map[string]kyvernov1.PolicyInterface
// kindType stores names of ClusterPolicies and Namespaced Policies. // kindType stores names of ClusterPolicies and Namespaced Policies.
// They are accessed first by GVRS then by PolicyType. // They are accessed first by GVRS then by PolicyType.
kindType map[dclient.GroupVersionResourceSubresource]map[PolicyType]sets.Set[string] kindType map[policyKey]map[PolicyType]sets.Set[string]
} }
func newPolicyMap() *policyMap { func newPolicyMap() *policyMap {
return &policyMap{ return &policyMap{
policies: map[string]kyvernov1.PolicyInterface{}, policies: map[string]kyvernov1.PolicyInterface{},
kindType: map[dclient.GroupVersionResourceSubresource]map[PolicyType]sets.Set[string]{}, kindType: map[policyKey]map[PolicyType]sets.Set[string]{},
} }
} }
@ -97,9 +106,9 @@ func (m *policyMap) set(key string, policy kyvernov1.PolicyInterface, client Res
type state struct { type state struct {
hasMutate, hasValidate, hasGenerate, hasVerifyImages, hasImagesValidationChecks bool hasMutate, hasValidate, hasGenerate, hasVerifyImages, hasImagesValidationChecks bool
} }
kindStates := map[dclient.GroupVersionResourceSubresource]state{} kindStates := map[policyKey]state{}
for _, rule := range autogen.ComputeRules(policy) { for _, rule := range autogen.ComputeRules(policy) {
entries := sets.New[dclient.GroupVersionResourceSubresource]() entries := sets.New[policyKey]()
for _, gvk := range rule.MatchResources.GetKinds() { for _, gvk := range rule.MatchResources.GetKinds() {
group, version, kind, subresource := kubeutils.ParseKindSelector(gvk) group, version, kind, subresource := kubeutils.ParseKindSelector(gvk)
gvrss, err := client.FindResources(group, version, kind, subresource) gvrss, err := client.FindResources(group, version, kind, subresource)
@ -108,14 +117,24 @@ func (m *policyMap) set(key string, policy kyvernov1.PolicyInterface, client Res
errs = append(errs, err) errs = append(errs, err)
} else { } else {
for gvrs := range gvrss { for gvrs := range gvrss {
entries.Insert(gvrs) entries.Insert(policyKey{
Group: gvrs.Group,
Version: gvrs.Version,
Resource: gvrs.Resource,
SubResource: gvrs.SubResource,
})
} }
} }
} }
if entries.Len() > 0 { if entries.Len() > 0 {
// account for pods/ephemeralcontainers special case // account for pods/ephemeralcontainers special case
if entries.Has(podsGVRS) { if entries.Has(podsKey) {
entries.Insert(podsGVRS.WithSubResource("ephemeralcontainers")) entries.Insert(policyKey{
Group: podsKey.Group,
Version: podsKey.Version,
Resource: podsKey.Resource,
SubResource: "ephemeralcontainers",
})
} }
hasMutate := rule.HasMutate() hasMutate := rule.HasMutate()
hasValidate := rule.HasValidate() hasValidate := rule.HasValidate()
@ -163,9 +182,10 @@ func (m *policyMap) unset(key string) {
} }
} }
func (m *policyMap) get(key PolicyType, gvrs dclient.GroupVersionResourceSubresource, namespace string) []kyvernov1.PolicyInterface { func (m *policyMap) get(key PolicyType, gvr schema.GroupVersionResource, subresource string, namespace string) []kyvernov1.PolicyInterface {
var result []kyvernov1.PolicyInterface var result []kyvernov1.PolicyInterface
for policyName := range m.kindType[gvrs][key] { pKey := policyKey{gvr.Group, gvr.Version, gvr.Resource, subresource}
for policyName := range m.kindType[pKey][key] {
ns, _, err := kcache.SplitMetaNamespaceKey(policyName) ns, _, err := kcache.SplitMetaNamespaceKey(policyName)
if err != nil { if err != nil {
logger.Error(err, "failed to parse policy name", "policyName", policyName) logger.Error(err, "failed to parse policy name", "policyName", policyName)

View file

@ -20,18 +20,26 @@ var (
replicasetsGVR = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "replicasets"} replicasetsGVR = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "replicasets"}
replicationcontrollersGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "replicationcontrollers"} replicationcontrollersGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "replicationcontrollers"}
podsGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: podsGVR} podsGVRS = mapGVR(podsGVR, "Pod")
namespacesGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: namespacesGVR} namespacesGVRS = mapGVR(namespacesGVR, "Namespace")
clusterrolesGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: clusterrolesGVR} clusterrolesGVRS = mapGVR(clusterrolesGVR, "ClusterRole")
deploymentsGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: deploymentsGVR} deploymentsGVRS = mapGVR(deploymentsGVR, "Deployment")
statefulsetsGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: statefulsetsGVR} statefulsetsGVRS = mapGVR(statefulsetsGVR, "StatefulSet")
daemonsetsGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: daemonsetsGVR} daemonsetsGVRS = mapGVR(daemonsetsGVR, "DaemonSet")
jobsGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: jobsGVR} jobsGVRS = mapGVR(jobsGVR, "Jon")
cronjobsGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: cronjobsGVR} cronjobsGVRS = mapGVR(cronjobsGVR, "CronJob")
replicasetsGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: replicasetsGVR} replicasetsGVRS = mapGVR(replicasetsGVR, "ReplicaSet")
replicationcontrollersGVRS = dclient.GroupVersionResourceSubresource{GroupVersionResource: replicationcontrollersGVR} replicationcontrollersGVRS = mapGVR(replicationcontrollersGVR, "ReplicationController")
) )
func mapGVR(gvr schema.GroupVersionResource, kind string) dclient.GroupVersionResourceSubresource {
return dclient.GroupVersionResourceSubresource{
GroupVersion: gvr.GroupVersion(),
Kind: kind,
Resource: gvr.Resource,
}
}
type TestResourceFinder struct{} type TestResourceFinder struct{}
func (TestResourceFinder) FindResources(group, version, kind, subresource string) (map[dclient.GroupVersionResourceSubresource]metav1.APIResource, error) { func (TestResourceFinder) FindResources(group, version, kind, subresource string) (map[dclient.GroupVersionResourceSubresource]metav1.APIResource, error) {

View file

@ -107,14 +107,11 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad
logger.V(4).Info("received an admission request in validating webhook") logger.V(4).Info("received an admission request in validating webhook")
// timestamp at which this admission request got triggered // timestamp at which this admission request got triggered
gvrs := dclient.GroupVersionResourceSubresource{ gvr := schema.GroupVersionResource(request.Resource)
GroupVersionResource: schema.GroupVersionResource(request.Resource), policies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.ValidateEnforce, gvr, request.SubResource, request.Namespace)...)
SubResource: request.SubResource, mutatePolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.Mutate, gvr, request.SubResource, request.Namespace)...)
} generatePolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.Generate, gvr, request.SubResource, request.Namespace)...)
policies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.ValidateEnforce, gvrs, request.Namespace)...) imageVerifyValidatePolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.VerifyImagesValidate, gvr, request.SubResource, request.Namespace)...)
mutatePolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.Mutate, gvrs, request.Namespace)...)
generatePolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.Generate, gvrs, request.Namespace)...)
imageVerifyValidatePolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.VerifyImagesValidate, gvrs, request.Namespace)...)
policies = append(policies, imageVerifyValidatePolicies...) policies = append(policies, imageVerifyValidatePolicies...)
if len(policies) == 0 && len(mutatePolicies) == 0 && len(generatePolicies) == 0 { if len(policies) == 0 && len(mutatePolicies) == 0 && len(generatePolicies) == 0 {
@ -149,12 +146,9 @@ func (h *handlers) Mutate(ctx context.Context, logger logr.Logger, request *admi
kind := request.Kind.Kind kind := request.Kind.Kind
logger = logger.WithValues("kind", kind) logger = logger.WithValues("kind", kind)
logger.V(4).Info("received an admission request in mutating webhook") logger.V(4).Info("received an admission request in mutating webhook")
gvrs := dclient.GroupVersionResourceSubresource{ gvr := schema.GroupVersionResource(request.Resource)
GroupVersionResource: schema.GroupVersionResource(request.Resource), mutatePolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.Mutate, gvr, request.SubResource, request.Namespace)...)
SubResource: request.SubResource, verifyImagesPolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.VerifyImagesMutate, gvr, request.SubResource, request.Namespace)...)
}
mutatePolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.Mutate, gvrs, request.Namespace)...)
verifyImagesPolicies := filterPolicies(failurePolicy, h.pCache.GetPolicies(policycache.VerifyImagesMutate, gvrs, request.Namespace)...)
if len(mutatePolicies) == 0 && len(verifyImagesPolicies) == 0 { if len(mutatePolicies) == 0 && len(verifyImagesPolicies) == 0 {
logger.V(4).Info("no policies matched mutate admission request") logger.V(4).Info("no policies matched mutate admission request")
return admissionutils.ResponseSuccess(request.UID) return admissionutils.ResponseSuccess(request.UID)

View file

@ -9,7 +9,6 @@ import (
"github.com/go-logr/logr" "github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned" "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api" engineapi "github.com/kyverno/kyverno/pkg/engine/api"
@ -152,11 +151,8 @@ func (v *validationHandler) buildAuditResponses(
request *admissionv1.AdmissionRequest, request *admissionv1.AdmissionRequest,
namespaceLabels map[string]string, namespaceLabels map[string]string,
) ([]*engineapi.EngineResponse, error) { ) ([]*engineapi.EngineResponse, error) {
gvrs := dclient.GroupVersionResourceSubresource{ gvr := schema.GroupVersionResource(request.Resource)
GroupVersionResource: schema.GroupVersionResource(request.Resource), policies := v.pCache.GetPolicies(policycache.ValidateAudit, gvr, request.SubResource, request.Namespace)
SubResource: request.SubResource,
}
policies := v.pCache.GetPolicies(policycache.ValidateAudit, gvrs, request.Namespace)
policyContext, err := v.pcBuilder.Build(request) policyContext, err := v.pcBuilder.Build(request)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -24,7 +24,7 @@ spec:
match: match:
resources: resources:
kinds: kinds:
- PodExecOptions - Pod/exec
context: context:
- name: podexeclabel - name: podexeclabel
apiCall: apiCall:

View file

@ -1,6 +1,5 @@
apiVersion: kuttl.dev/v1beta1 apiVersion: kuttl.dev/v1beta1
kind: TestStep kind: TestStep
apply: apply:
- policy.yaml - file: policy.yaml
assert: shouldFail: true
- policy-assert.yaml

View file

@ -1,4 +0,0 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
assert:
- webhooks.yaml

View file

@ -1,10 +1,4 @@
## Description ## Description
This test verifies the resource validation webhook is configured correctly when a policy targets all `Scale` resource. This test tries to create a policy targeting the `Scale` kind.
It should be equivalent to using `*/scale` The `Scale` kind doesn't map to a top level resource and therefore the policy is expected to be rejected.
## Steps
1. - Create a policy targeting `Scale`
- Assert policy gets ready
1. - Assert that the resource validation webhook is configured correctly

View file

@ -1,9 +0,0 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -1,34 +0,0 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
webhook.kyverno.io/managed-by: kyverno
name: kyverno-resource-validating-webhook-cfg
webhooks:
- rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
- DELETE
- CONNECT
resources:
- replicationcontrollers/scale
scope: '*'
- apiGroups:
- apps
apiVersions:
- v1
operations:
- CREATE
- UPDATE
- DELETE
- CONNECT
resources:
- deployments/scale
- replicasets/scale
- statefulsets/scale
scope: '*'