mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
9078acb92a
* fix: helm template for cleanup jobs image Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix: exceptions not considered on delete Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * kuttl test Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
97 lines
2.9 KiB
Go
97 lines
2.9 KiB
Go
package engine
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/go-logr/logr"
|
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
|
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
|
matched "github.com/kyverno/kyverno/pkg/utils/match"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/client-go/tools/cache"
|
|
)
|
|
|
|
func findExceptions(
|
|
selector engineapi.PolicyExceptionSelector,
|
|
policy kyvernov1.PolicyInterface,
|
|
rule string,
|
|
) ([]*kyvernov2alpha1.PolicyException, error) {
|
|
if selector == nil {
|
|
return nil, nil
|
|
}
|
|
polexs, err := selector.List(labels.Everything())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var result []*kyvernov2alpha1.PolicyException
|
|
policyName, err := cache.MetaNamespaceKeyFunc(policy)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to compute policy key: %w", err)
|
|
}
|
|
for _, polex := range polexs {
|
|
if polex.Contains(policyName, rule) {
|
|
result = append(result, polex)
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// matchesException checks if an exception applies to the resource being admitted
|
|
func matchesException(
|
|
selector engineapi.PolicyExceptionSelector,
|
|
policyContext engineapi.PolicyContext,
|
|
rule kyvernov1.Rule,
|
|
) (*kyvernov2alpha1.PolicyException, error) {
|
|
candidates, err := findExceptions(selector, policyContext.Policy(), rule.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
gvk, subresource := policyContext.ResourceKind()
|
|
resource := policyContext.NewResource()
|
|
if resource.Object == nil {
|
|
resource = policyContext.OldResource()
|
|
}
|
|
for _, candidate := range candidates {
|
|
err := matched.CheckMatchesResources(
|
|
resource,
|
|
candidate.Spec.Match,
|
|
policyContext.NamespaceLabels(),
|
|
policyContext.AdmissionInfo(),
|
|
gvk,
|
|
subresource,
|
|
)
|
|
// if there's no error it means a match
|
|
if err == nil {
|
|
return candidate, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
// hasPolicyExceptions returns nil when there are no matching exceptions.
|
|
// A rule response is returned when an exception is matched, or there is an error.
|
|
func (e *engine) hasPolicyExceptions(
|
|
logger logr.Logger,
|
|
ruleType engineapi.RuleType,
|
|
ctx engineapi.PolicyContext,
|
|
rule kyvernov1.Rule,
|
|
) *engineapi.RuleResponse {
|
|
// if matches, check if there is a corresponding policy exception
|
|
exception, err := matchesException(e.exceptionSelector, ctx, rule)
|
|
if err != nil {
|
|
logger.Error(err, "failed to match exceptions")
|
|
return nil
|
|
}
|
|
if exception == nil {
|
|
return nil
|
|
}
|
|
key, err := cache.MetaNamespaceKeyFunc(exception)
|
|
if err != nil {
|
|
logger.Error(err, "failed to compute policy exception key", "namespace", exception.GetNamespace(), "name", exception.GetName())
|
|
return engineapi.RuleError(rule.Name, ruleType, "failed to compute exception key", err)
|
|
} else {
|
|
logger.V(3).Info("policy rule skipped due to policy exception", "exception", key)
|
|
return engineapi.RuleSkip(rule.Name, ruleType, "rule skipped due to policy exception "+key).WithException(exception)
|
|
}
|
|
}
|