1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-09 17:37:12 +00:00
kyverno/pkg/validation/cleanuppolicy/validate.go
Md Sahil 0873a9fc02
Support for Context vars in cleanup (#6084)
* Added Context in CleanupPolicySpec

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Added context.go file with loadVariable()

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Added loadAPIData() in context.go and called from handlers.go

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Added conditionals for not supported context variables

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Reverted versions in CRDs

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Reverted CRDs to v0.11.1

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Imported fmt in handlers.go

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Added Context in CleanupPolicySpec

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Added context.go file with loadVariable()

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Added loadAPIData() in context.go and called from handlers.go

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Added conditionals for not supported context variables

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Reverted versions in CRDs

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Reverted CRDs to v0.11.1

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Imported fmt in handlers.go

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Removed duplicate import

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* make verify-codegen

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Updated kuttl test

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Fixed kuttl failure

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* moved policy check to validation

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Reused functions

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Added kuttl test

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Added more configMap

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* removed unecessary check

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* auto codegen

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* updated codegen

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

* Renamed ApplyJMESPath() to applyJMESPath()

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>

---------

Signed-off-by: MdSahil-oss <Mohdssahil1@gmail.com>
Co-authored-by: shuting <shuting@nirmata.com>
Co-authored-by: Chip Zoller <chipzoller@gmail.com>
Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
2023-04-20 15:06:13 +08:00

105 lines
3.4 KiB
Go

package cleanuppolicy
import (
"context"
"fmt"
"regexp"
"github.com/go-logr/logr"
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
"github.com/kyverno/kyverno/pkg/auth"
"github.com/kyverno/kyverno/pkg/clients/dclient"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/variables"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/discovery"
)
// FetchClusteredResources retieves the list of clustered resources
func FetchClusteredResources(logger logr.Logger, client dclient.Interface) (sets.Set[string], error) {
res, err := discovery.ServerPreferredResources(client.Discovery().DiscoveryInterface())
if err != nil {
if discovery.IsGroupDiscoveryFailedError(err) {
err := err.(*discovery.ErrGroupDiscoveryFailed)
for gv, err := range err.Groups {
logger.Error(err, "failed to list api resources", "group", gv)
}
} else {
return nil, err
}
}
clusterResources := sets.New[string]()
for _, resList := range res {
for _, r := range resList.APIResources {
if !r.Namespaced {
clusterResources.Insert(r.Kind)
}
}
}
return clusterResources, nil
}
// Validate checks policy is valid
func Validate(ctx context.Context, logger logr.Logger, client dclient.Interface, policy kyvernov2alpha1.CleanupPolicyInterface) error {
clusteredResources, err := FetchClusteredResources(logger, client)
if err != nil {
return err
}
if err := validatePolicy(clusteredResources, policy); err != nil {
return err
}
if err := validateAuth(ctx, client, policy); err != nil {
return err
}
if err := validateVariables(logger, policy); err != nil {
return err
}
return nil
}
// validatePolicy checks the policy and rules declarations for required configurations
func validatePolicy(clusterResources sets.Set[string], policy kyvernov2alpha1.CleanupPolicyInterface) error {
errs := policy.Validate(clusterResources)
return errs.ToAggregate()
}
// validateAuth checks the the delete action is allowed
func validateAuth(ctx context.Context, client dclient.Interface, policy kyvernov2alpha1.CleanupPolicyInterface) error {
namespace := policy.GetNamespace()
spec := policy.GetSpec()
kinds := sets.New(spec.MatchResources.GetKinds()...)
for kind := range kinds {
checker := auth.NewCanI(client.Discovery(), client.GetKubeClient().AuthorizationV1().SelfSubjectAccessReviews(), kind, namespace, "delete", "")
allowedDeletion, err := checker.RunAccessCheck(ctx)
if err != nil {
return err
}
if !allowedDeletion {
return fmt.Errorf("cleanup controller has no permission to delete kind %s", kind)
}
checker = auth.NewCanI(client.Discovery(), client.GetKubeClient().AuthorizationV1().SelfSubjectAccessReviews(), kind, namespace, "list", "")
allowedList, err := checker.RunAccessCheck(ctx)
if err != nil {
return err
}
if !allowedList {
return fmt.Errorf("cleanup controller has no permission to list kind %s", kind)
}
}
return nil
}
func validateVariables(logger logr.Logger, policy kyvernov2alpha1.CleanupPolicyInterface) error {
ctx := enginecontext.NewMockContext(allowedVariables)
c := policy.GetSpec().Conditions
conditionCopy := c.DeepCopy()
if _, err := variables.SubstituteAllInType(logger, ctx, conditionCopy); !variables.CheckNotFoundErr(err) {
return fmt.Errorf("variable substitution failed for policy %s: %s", policy.GetName(), err.Error())
}
return nil
}
var allowedVariables = regexp.MustCompile(`([a-z_0-9]+)|(target\.|images\.|([a-z_0-9]+\()[^{}])`)