mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
feat: add exception logic (#5712)
Signed-off-by: Eileen Yu <eileenylj@gmail.com> Signed-off-by: Eileen Yu <eileenylj@gmail.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com>
This commit is contained in:
parent
14445bf417
commit
baa41bcf79
4 changed files with 58 additions and 22 deletions
|
@ -69,12 +69,18 @@ func filterRule(rclient registryclient.Client, rule kyvernov1.Rule, policyContex
|
|||
return nil
|
||||
}
|
||||
|
||||
logger := logging.WithName("exception")
|
||||
// check if there is a corresponding policy exception
|
||||
ruleResp := hasPolicyExceptions(policyContext, &rule, logger)
|
||||
if ruleResp != nil {
|
||||
return ruleResp
|
||||
}
|
||||
|
||||
ruleType := response.Mutation
|
||||
if rule.HasGenerate() {
|
||||
ruleType = response.Generation
|
||||
}
|
||||
|
||||
var err error
|
||||
startTime := time.Now()
|
||||
|
||||
policy := policyContext.policy
|
||||
|
@ -85,13 +91,13 @@ func filterRule(rclient registryclient.Client, rule kyvernov1.Rule, policyContex
|
|||
excludeGroupRole := policyContext.excludeGroupRole
|
||||
namespaceLabels := policyContext.namespaceLabels
|
||||
|
||||
logger := logging.WithName(string(ruleType)).WithValues("policy", policy.GetName(),
|
||||
logger = logging.WithName(string(ruleType)).WithValues("policy", policy.GetName(),
|
||||
"kind", newResource.GetKind(), "namespace", newResource.GetNamespace(), "name", newResource.GetName())
|
||||
|
||||
kindsInPolicy := append(rule.MatchResources.GetKinds(), rule.ExcludeResources.GetKinds()...)
|
||||
subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(kindsInPolicy, policyContext)
|
||||
|
||||
if err = MatchesResourceDescription(subresourceGVKToAPIResource, newResource, rule, admissionInfo, excludeGroupRole, namespaceLabels, "", policyContext.subresource); err != nil {
|
||||
if err := MatchesResourceDescription(subresourceGVKToAPIResource, newResource, rule, admissionInfo, excludeGroupRole, namespaceLabels, "", policyContext.subresource); err != nil {
|
||||
if ruleType == response.Generation {
|
||||
// if the oldResource matched, return "false" to delete GR for it
|
||||
if err = MatchesResourceDescription(subresourceGVKToAPIResource, oldResource, rule, admissionInfo, excludeGroupRole, namespaceLabels, "", policyContext.subresource); err == nil {
|
||||
|
@ -113,7 +119,7 @@ func filterRule(rclient registryclient.Client, rule kyvernov1.Rule, policyContex
|
|||
policyContext.jsonContext.Checkpoint()
|
||||
defer policyContext.jsonContext.Restore()
|
||||
|
||||
if err = LoadContext(context.TODO(), logger, rclient, rule.Context, policyContext, rule.Name); err != nil {
|
||||
if err := LoadContext(context.TODO(), logger, rclient, rule.Context, policyContext, rule.Name); err != nil {
|
||||
logger.V(4).Info("cannot add external data to the context", "reason", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -108,9 +108,15 @@ func VerifyAndPatchImages(
|
|||
return
|
||||
}
|
||||
|
||||
// check if there is a corresponding policy exception
|
||||
ruleResp := hasPolicyExceptions(policyContext, rule, logger)
|
||||
if ruleResp != nil {
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||
return
|
||||
}
|
||||
|
||||
logger.V(3).Info("processing image verification rule", "ruleSelector", applyRules)
|
||||
|
||||
var err error
|
||||
ruleImages, imageRefs, err := extractMatchingImages(policyContext, rule)
|
||||
if err != nil {
|
||||
appendResponse(resp, rule, fmt.Sprintf("failed to extract images: %s", err.Error()), response.RuleStatusError)
|
||||
|
|
|
@ -47,7 +47,9 @@ func Mutate(ctx context.Context, rclient registryclient.Client, policyContext *P
|
|||
var err error
|
||||
applyRules := policy.GetSpec().GetApplyRules()
|
||||
|
||||
for _, rule := range autogen.ComputeRules(policy) {
|
||||
computeRules := autogen.ComputeRules(policy)
|
||||
|
||||
for i, rule := range computeRules {
|
||||
if !rule.HasMutate() {
|
||||
continue
|
||||
}
|
||||
|
@ -70,6 +72,13 @@ func Mutate(ctx context.Context, rclient registryclient.Client, policyContext *P
|
|||
return
|
||||
}
|
||||
|
||||
// check if there is a corresponding policy exception
|
||||
ruleResp := hasPolicyExceptions(policyContext, &computeRules[i], logger)
|
||||
if ruleResp != nil {
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||
return
|
||||
}
|
||||
|
||||
logger.V(3).Info("processing mutate rule", "applyRules", applyRules)
|
||||
resource, err := policyContext.jsonContext.Query("request.object")
|
||||
policyContext.jsonContext.Reset()
|
||||
|
|
|
@ -135,22 +135,10 @@ func validateResource(ctx context.Context, log logr.Logger, rclient registryclie
|
|||
if !matches(log, rule, enginectx) {
|
||||
return nil
|
||||
}
|
||||
// if matches, check if there is a corresponding policy exception
|
||||
exception, err := matchesException(enginectx, rule)
|
||||
// if we found an exception
|
||||
if err == nil && exception != nil {
|
||||
key, err := cache.MetaNamespaceKeyFunc(exception)
|
||||
// TODO: increase metrics
|
||||
if err != nil {
|
||||
log.Error(err, "failed to compute policy exception key", "namespace", exception.GetNamespace(), "name", exception.GetName())
|
||||
} else {
|
||||
log.V(3).Info("policy rule skipped due to policy exception", "exception", key)
|
||||
return &response.RuleResponse{
|
||||
Name: rule.Name,
|
||||
Message: "Rule skipped because of PolicyException" + key,
|
||||
Status: response.RuleStatusSkip,
|
||||
}
|
||||
}
|
||||
// check if there is a corresponding policy exception
|
||||
ruleResp := hasPolicyExceptions(enginectx, rule, log)
|
||||
if ruleResp != nil {
|
||||
return ruleResp
|
||||
}
|
||||
log.V(3).Info("processing validation rule", "matchCount", matchCount, "applyRules", applyRules)
|
||||
enginectx.jsonContext.Reset()
|
||||
|
@ -800,3 +788,30 @@ func matchesException(policyContext *PolicyContext, rule *kyvernov1.Rule) (*kyve
|
|||
}
|
||||
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 hasPolicyExceptions(ctx *PolicyContext, rule *kyvernov1.Rule, log logr.Logger) *response.RuleResponse {
|
||||
// if matches, check if there is a corresponding policy exception
|
||||
exception, err := matchesException(ctx, rule)
|
||||
// if we found an exception
|
||||
if err == nil && exception != nil {
|
||||
key, err := cache.MetaNamespaceKeyFunc(exception)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to compute policy exception key", "namespace", exception.GetNamespace(), "name", exception.GetName())
|
||||
return &response.RuleResponse{
|
||||
Name: rule.Name,
|
||||
Message: "failed to find matched exception " + key,
|
||||
Status: response.RuleStatusError,
|
||||
}
|
||||
}
|
||||
|
||||
log.V(3).Info("policy rule skipped due to policy exception", "exception", key)
|
||||
return &response.RuleResponse{
|
||||
Name: rule.Name,
|
||||
Message: "rule skipped due to policy exception " + key,
|
||||
Status: response.RuleStatusSkip,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue