1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-05 15:37:19 +00:00
kyverno/pkg/engine/exceptions.go
Rakshit Gondwal b574802c12
feat: support conditions in PolicyException (#8577)
* feat: support conditions in PolicyException

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* fix matchesException func

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* add codegen-all files

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* fix after review

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* remove variable validation from PolicyException

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* fix after review

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* add kuttl tests

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* remove ValidateVariables() from tests

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* fix errors

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* remove check-variables kuttl test

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* fix after review

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>

* add sleep step to kuttl

Signed-off-by: Rakshit Gondwal <98955085+rakshitgondwal@users.noreply.github.com>

* miinor fix

Signed-off-by: Rakshit Gondwal <98955085+rakshitgondwal@users.noreply.github.com>

* add readme for kuttl test

Signed-off-by: Rakshit Gondwal <98955085+rakshitgondwal@users.noreply.github.com>

---------

Signed-off-by: Rakshit Gondwal <rakshitgondwal3@gmail.com>
Signed-off-by: Rakshit Gondwal <98955085+rakshitgondwal@users.noreply.github.com>
Signed-off-by: Jim Bugwadia <jim@nirmata.com>
Co-authored-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
Co-authored-by: Jim Bugwadia <jim@nirmata.com>
2023-10-24 10:45:52 +00:00

108 lines
3.2 KiB
Go

package engine
import (
"fmt"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov2beta1 "github.com/kyverno/kyverno/api/kyverno/v2beta1"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/utils/conditions"
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,
) ([]*kyvernov2beta1.PolicyException, error) {
if selector == nil {
return nil, nil
}
polexs, err := selector.List(labels.Everything())
if err != nil {
return nil, err
}
var result []*kyvernov2beta1.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,
logger logr.Logger,
) (*kyvernov2beta1.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 {
if candidate.Spec.Conditions != nil {
passed, err := conditions.CheckAnyAllConditions(logger, policyContext.JSONContext(), *candidate.Spec.Conditions)
if err != nil {
return nil, err
}
if !passed {
return nil, fmt.Errorf("conditions did not pass")
}
}
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, logger)
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)
}
}