mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-09 17:37:12 +00:00
* feat: generate validating admission policies and their bindings from Kyverno policies Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * feat: add generate VAPs feature flag Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * fix: use container flags instead of feature flags Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * fix: limit VAP generation to cluster policies Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * feat: add policy checks for generating VAPs Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * chore: rename package Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * feat: translate match/exclude resources in Kyverno policies to their alternatives in validating admission policies Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * feat: add vap info in kyverno policy status Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * fix: delete the translation of Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * feat: add kuttl tests Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * feat: add generateValidatingAdmissionPolicy feature flag in the helm chart Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * fix Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * chore: update codegen Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * feat: add validating admission policy kuttl tests in the workflow Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * fix: check K8s server version Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * fix lint issue Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * fix Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * fix: remove the kind config of VAPs Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> --------- Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
148 lines
5 KiB
Go
148 lines
5 KiB
Go
package validatingadmissionpolicygenerate
|
|
|
|
import (
|
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
|
)
|
|
|
|
func checkResources(resource kyvernov1.ResourceDescription) (bool, string) {
|
|
var msg string
|
|
if len(resource.Namespaces) != 0 || len(resource.Annotations) != 0 {
|
|
msg = "skip generating validating admission policy: Namespaces / Annotations in resource description isn't applicable."
|
|
return false, msg
|
|
}
|
|
return true, msg
|
|
}
|
|
|
|
func checkUserInfo(info kyvernov1.UserInfo) (bool, string) {
|
|
var msg string
|
|
if !info.IsEmpty() {
|
|
msg = "skip generating validating admission policy: Roles / ClusterRoles / Subjects in `any/all` isn't applicable."
|
|
return false, msg
|
|
}
|
|
return true, msg
|
|
}
|
|
|
|
func canGenerateVAP(spec *kyvernov1.Spec) (bool, string) {
|
|
var msg string
|
|
if len(spec.Rules) > 1 {
|
|
msg = "skip generating validating admission policy: multiple rules aren't applicable."
|
|
return false, msg
|
|
}
|
|
|
|
rule := spec.Rules[0]
|
|
if !rule.HasValidateCEL() {
|
|
msg = "skip generating validating admission policy for non CEL rules."
|
|
return false, msg
|
|
}
|
|
|
|
if len(spec.ValidationFailureActionOverrides) > 1 {
|
|
msg = "skip generating validating admission policy: multiple validationFailureActionOverrides aren't applicable."
|
|
return false, msg
|
|
}
|
|
|
|
if len(spec.ValidationFailureActionOverrides) != 0 && len(spec.ValidationFailureActionOverrides[0].Namespaces) != 0 {
|
|
msg = "skip generating validating admission policy: Namespaces in validationFailureActionOverrides isn't applicable."
|
|
return false, msg
|
|
}
|
|
|
|
// check the matched/excluded resources of the CEL rule.
|
|
match, exclude := rule.MatchResources, rule.ExcludeResources
|
|
if !exclude.UserInfo.IsEmpty() || !exclude.ResourceDescription.IsEmpty() || exclude.All != nil || exclude.Any != nil {
|
|
msg = "skip generating validating admission policy: Exclude isn't applicable."
|
|
return false, msg
|
|
}
|
|
if ok, msg := checkUserInfo(match.UserInfo); !ok {
|
|
return false, msg
|
|
}
|
|
if ok, msg := checkResources(match.ResourceDescription); !ok {
|
|
return false, msg
|
|
}
|
|
|
|
var (
|
|
containsNamespaceSelector = false
|
|
containsObjectSelector = false
|
|
)
|
|
|
|
// since 'any' specify resources which will be ORed, it can be converted into multiple NamedRuleWithOperations in validating admission policy
|
|
for _, value := range match.Any {
|
|
if ok, msg := checkUserInfo(value.UserInfo); !ok {
|
|
return false, msg
|
|
}
|
|
if ok, msg := checkResources(value.ResourceDescription); !ok {
|
|
return false, msg
|
|
}
|
|
|
|
// since namespace/object selectors are applied to all NamedRuleWithOperations in validating admission policy, then
|
|
// multiple namespace/object selectors aren't applicable across the `any` clause.
|
|
if value.NamespaceSelector != nil {
|
|
if containsNamespaceSelector {
|
|
msg = "skip generating validating admission policy: multiple NamespaceSelector across 'any' aren't applicable."
|
|
return false, msg
|
|
}
|
|
containsNamespaceSelector = true
|
|
}
|
|
if value.Selector != nil {
|
|
if containsObjectSelector {
|
|
msg = "skip generating validating admission policy: multiple ObjectSelector across 'any' aren't applicable."
|
|
return false, msg
|
|
}
|
|
containsObjectSelector = true
|
|
}
|
|
}
|
|
// since 'all' specify resources which will be ANDed, we can't have more than one resource.
|
|
if match.All != nil {
|
|
if len(match.All) > 1 {
|
|
msg = "skip generating validating admission policy: multiple 'all' isn't applicable."
|
|
return false, msg
|
|
} else {
|
|
if ok, msg := checkUserInfo(match.All[0].UserInfo); !ok {
|
|
return false, msg
|
|
}
|
|
if ok, msg := checkResources(match.All[0].ResourceDescription); !ok {
|
|
return false, msg
|
|
}
|
|
}
|
|
}
|
|
|
|
// since 'any' specify resources which will be ORed, it can be converted into multiple NamedRuleWithOperations in validating admission policy
|
|
for _, value := range exclude.Any {
|
|
if ok, msg := checkUserInfo(value.UserInfo); !ok {
|
|
return false, msg
|
|
}
|
|
if ok, msg := checkResources(value.ResourceDescription); !ok {
|
|
return false, msg
|
|
}
|
|
|
|
// since namespace/object selectors are applied to all NamedRuleWithOperations in validating admission policy, then
|
|
// multiple namespace/object selectors aren't applicable across the `any` clause.
|
|
if value.NamespaceSelector != nil {
|
|
if containsNamespaceSelector {
|
|
msg = "skip generating validating admission policy: multiple NamespaceSelector across 'any' aren't applicable."
|
|
return false, msg
|
|
}
|
|
containsNamespaceSelector = true
|
|
}
|
|
if value.Selector != nil {
|
|
if containsObjectSelector {
|
|
msg = "skip generating validating admission policy: multiple ObjectSelector across 'any' aren't applicable."
|
|
return false, msg
|
|
}
|
|
containsObjectSelector = true
|
|
}
|
|
}
|
|
// since 'all' specify resources which will be ANDed, we can't have more than one resource.
|
|
if exclude.All != nil {
|
|
if len(exclude.All) > 1 {
|
|
msg = "skip generating validating admission policy: multiple 'all' isn't applicable."
|
|
return false, msg
|
|
} else {
|
|
if ok, msg := checkUserInfo(exclude.All[0].UserInfo); !ok {
|
|
return false, msg
|
|
}
|
|
if ok, msg := checkResources(exclude.All[0].ResourceDescription); !ok {
|
|
return false, msg
|
|
}
|
|
}
|
|
}
|
|
return true, msg
|
|
}
|