1
0
Fork 0
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:
Eileen 2022-12-20 23:35:26 -05:00 committed by GitHub
parent 14445bf417
commit baa41bcf79
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 22 deletions

View file

@ -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
}

View file

@ -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)

View file

@ -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()

View file

@ -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
}