1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00
kyverno/pkg/validatingadmissionpolicy/kyvernopolicy_checker.go
Mariam Fahmy 2140a0239b
chore: rename validationFailureAction to failureAction under the rule (#10893)
Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
Co-authored-by: Jim Bugwadia <jim@nirmata.com>
2024-08-27 20:07:57 +00:00

223 lines
6.5 KiB
Go

package validatingadmissionpolicy
import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
"github.com/kyverno/kyverno/ext/wildcard"
)
// CanGenerateVAP check if Kyverno policy and a PolicyException can be translated to a Kubernetes ValidatingAdmissionPolicy
func CanGenerateVAP(spec *kyvernov1.Spec, exceptions []kyvernov2.PolicyException) (bool, string) {
var msg string
if ok, msg := checkPolicy(spec); !ok {
return false, msg
}
if ok, msg := checkExceptions(exceptions); !ok {
return false, msg
}
return true, msg
}
func checkExceptions(exceptions []kyvernov2.PolicyException) (bool, string) {
var msg string
for _, exception := range exceptions {
spec := exception.Spec
for _, exception := range spec.Exceptions {
if len(exception.RuleNames) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple ruleNames in PolicyException is not applicable."
return false, msg
}
}
if spec.Conditions != nil {
msg = "skip generating ValidatingAdmissionPolicy: Conditions in PolicyException is not applicable."
return false, msg
}
exclude := spec.Match
if ok, msg := checkResourceFilter(exclude.Any, false); !ok {
return false, msg
}
if len(exclude.All) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' in the PolicyException's match block is not applicable."
return false, msg
}
if ok, msg := checkResourceFilter(exclude.All, false); !ok {
return false, msg
}
}
return true, msg
}
func checkPolicy(spec *kyvernov1.Spec) (bool, string) {
var msg string
if ok, msg := checkRuleCount(spec); !ok {
return false, msg
}
rule := spec.Rules[0]
if ok, msg := checkRuleType(rule); !ok {
return false, msg
}
if ok, msg := checkValidationFailureActionOverrides(spec.ValidationFailureActionOverrides); !ok {
return false, msg
}
if ok, msg := checkValidationFailureActionOverrides(rule.Validation.FailureActionOverrides); !ok {
return false, msg
}
// check the matched/excluded resources of the CEL rule.
match, exclude := rule.MatchResources, rule.ExcludeResources
if ok, msg := checkUserInfo(match.UserInfo); !ok {
return false, msg
}
if ok, msg := checkUserInfo(exclude.UserInfo); !ok {
return false, msg
}
if ok, msg := checkResources(match.ResourceDescription, true); !ok {
return false, msg
}
if ok, msg := checkResources(exclude.ResourceDescription, false); !ok {
return false, msg
}
if ok, msg := checkResourceFilter(match.Any, true); !ok {
return false, msg
}
if len(match.All) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' in the match block is not applicable."
return false, msg
}
if ok, msg := checkResourceFilter(match.All, true); !ok {
return false, msg
}
if ok, msg := checkResourceFilter(exclude.Any, false); !ok {
return false, msg
}
if len(exclude.All) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' in the exclude block is not applicable."
return false, msg
}
if ok, msg := checkResourceFilter(exclude.All, false); !ok {
return false, msg
}
return true, msg
}
func checkRuleCount(spec *kyvernov1.Spec) (bool, string) {
var msg string
if len(spec.Rules) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple rules are not applicable."
return false, msg
}
return true, msg
}
func checkRuleType(rule kyvernov1.Rule) (bool, string) {
var msg string
if !rule.HasValidateCEL() {
msg = "skip generating ValidatingAdmissionPolicy for non CEL rules."
return false, msg
}
return true, msg
}
func checkResources(resource kyvernov1.ResourceDescription, isMatch bool) (bool, string) {
var msg string
if !isMatch {
if len(resource.Kinds) != 0 && len(resource.Namespaces) != 0 {
msg = "skip generating ValidatingAdmissionPolicy: excluding a resource within a namespace is not applicable."
return false, msg
}
}
if len(resource.Annotations) != 0 {
msg = "skip generating ValidatingAdmissionPolicy: Annotations in resource description is not applicable."
return false, msg
}
if resource.Name != "" && wildcard.ContainsWildcard(resource.Name) {
msg = "skip generating ValidatingAdmissionPolicy: wildcards in resource name is not applicable."
return false, msg
}
for _, name := range resource.Names {
if wildcard.ContainsWildcard(name) {
msg = "skip generating ValidatingAdmissionPolicy: wildcards in resource name is not applicable."
return false, msg
}
}
for _, ns := range resource.Namespaces {
if wildcard.ContainsWildcard(ns) {
msg = "skip generating ValidatingAdmissionPolicy: wildcards in namespace name is not applicable."
return false, msg
}
}
return true, msg
}
func checkUserInfo(info kyvernov1.UserInfo) (bool, string) {
var msg string
if !info.IsEmpty() {
msg = "skip generating ValidatingAdmissionPolicy: Roles / ClusterRoles / Subjects in `any/all` is not applicable."
return false, msg
}
return true, msg
}
func checkResourceFilter(resFilters kyvernov1.ResourceFilters, isMatch bool) (bool, string) {
var msg string
containsNamespaceSelector := false
containsObjectSelector := false
for _, value := range resFilters {
if ok, msg := checkUserInfo(value.UserInfo); !ok {
return false, msg
}
if ok, msg := checkResources(value.ResourceDescription, isMatch); !ok {
return false, msg
}
if value.NamespaceSelector != nil {
containsNamespaceSelector = true
}
if value.Selector != nil {
containsObjectSelector = true
}
}
if !isMatch {
if containsNamespaceSelector || containsObjectSelector {
msg = "skip generating ValidatingAdmissionPolicy: NamespaceSelector / ObjectSelector in the exclude block is not applicable."
return false, msg
}
} else {
if len(resFilters) > 1 && (containsNamespaceSelector || containsObjectSelector) {
return false, "skip generating ValidatingAdmissionPolicy: NamespaceSelector / ObjectSelector across multiple resources in the match block are not applicable."
}
}
return true, msg
}
func checkValidationFailureActionOverrides(validationFailureActionOverrides []kyvernov1.ValidationFailureActionOverride) (bool, string) {
var msg string
if len(validationFailureActionOverrides) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple validationFailureActionOverrides are not applicable."
return false, msg
}
if len(validationFailureActionOverrides) != 0 && len(validationFailureActionOverrides[0].Namespaces) != 0 {
msg = "skip generating ValidatingAdmissionPolicy: Namespaces in validationFailureActionOverrides is not applicable."
return false, msg
}
return true, msg
}