1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00
kyverno/pkg/validatingadmissionpolicy/matcher.go
2024-12-12 07:13:09 +00:00

91 lines
2.8 KiB
Go

package validatingadmissionpolicy
import (
admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/plugin/webhook/predicates/rules"
)
// matches checks the following:
// - if the namespace selector matches the resource namespace
// - if the object selector matches the resource
// - if the resource is excluded by the policy/binding
// - if the resource matches the policy/binding rules
func matches(attr admission.Attributes, namespaceSelectorMap map[string]map[string]string, matchCriteria admissionregistrationv1alpha1.MatchResources) (bool, error) {
// check if the namespace selector matches the resource namespace
if matchCriteria.NamespaceSelector != nil {
if len(matchCriteria.NamespaceSelector.MatchLabels) > 0 || len(matchCriteria.NamespaceSelector.MatchExpressions) > 0 {
selector, err := metav1.LabelSelectorAsSelector(matchCriteria.NamespaceSelector)
if err != nil {
return false, err
}
if nsLabels, ok := namespaceSelectorMap[attr.GetNamespace()]; ok {
if !selector.Matches(labels.Set(nsLabels)) {
return false, nil
}
} else {
return false, nil
}
}
}
// check if the object selector matches the resource
if matchCriteria.ObjectSelector != nil {
if len(matchCriteria.ObjectSelector.MatchLabels) > 0 || len(matchCriteria.ObjectSelector.MatchExpressions) > 0 {
selector, err := metav1.LabelSelectorAsSelector(matchCriteria.ObjectSelector)
if err != nil {
return false, err
}
accessor, err := meta.Accessor(attr.GetObject())
if err != nil {
return false, err
}
if len(accessor.GetLabels()) != 0 {
if !selector.Matches(labels.Set(accessor.GetLabels())) {
return false, nil
}
}
}
}
// check if the resource is excluded by the policy/binding
if len(matchCriteria.ExcludeResourceRules) != 0 {
if matchesResourceRules(matchCriteria.ExcludeResourceRules, attr) {
return false, nil
}
}
// check if the resource is matched by the policy/binding
if len(matchCriteria.ResourceRules) != 0 {
return matchesResourceRules(matchCriteria.ResourceRules, attr), nil
}
return true, nil
}
func matchesResourceRules(resourceRules []admissionregistrationv1alpha1.NamedRuleWithOperations, attr admission.Attributes) bool {
for _, r := range resourceRules {
ruleMatcher := rules.Matcher{
Rule: r.RuleWithOperations,
Attr: attr,
}
if !ruleMatcher.Matches() {
continue
}
// an empty name list always matches
if len(r.ResourceNames) == 0 {
return true
}
name := attr.GetName()
for _, matchedName := range r.ResourceNames {
if name == matchedName {
return true
}
}
}
return false
}