1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 07:57:07 +00:00
kyverno/pkg/policy/apply.go

152 lines
5.1 KiB
Go
Raw Normal View History

package policy
import (
2019-08-26 13:34:42 -07:00
"fmt"
"reflect"
"strings"
"time"
jsonpatch "github.com/evanphx/json-patch/v5"
2020-03-17 11:05:20 -07:00
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
jsonutils "github.com/kyverno/kyverno/pkg/utils/json"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// applyPolicy applies policy on a resource
func applyPolicy(policy kyvernov1.PolicyInterface, resource unstructured.Unstructured,
logger logr.Logger, excludeGroupRole []string,
client dclient.Interface, namespaceLabels map[string]string,
) (responses []*response.EngineResponse) {
startTime := time.Now()
defer func() {
2020-05-17 09:54:32 -07:00
name := resource.GetKind() + "/" + resource.GetName()
ns := resource.GetNamespace()
if ns != "" {
name = ns + "/" + name
}
logger.V(3).Info("applyPolicy", "resource", name, "processingTime", time.Since(startTime).String())
}()
2019-08-26 13:34:42 -07:00
2020-12-23 15:10:07 -08:00
var engineResponses []*response.EngineResponse
var engineResponseMutation, engineResponseValidation *response.EngineResponse
2019-08-26 13:34:42 -07:00
var err error
ctx := context.NewContext()
err = context.AddResource(ctx, transformResource(resource))
if err != nil {
logger.Error(err, "failed to add transform resource to ctx")
}
err = ctx.AddNamespace(resource.GetNamespace())
if err != nil {
logger.Error(err, "failed to add namespace to ctx")
}
if err := ctx.AddImageInfos(&resource); err != nil {
logger.Error(err, "unable to add image info to variables context")
}
engineResponseMutation, err = mutation(policy, resource, logger, ctx, namespaceLabels)
if err != nil {
2020-03-17 11:05:20 -07:00
logger.Error(err, "failed to process mutation rule")
}
api server lookups (#1514) * initial commit for api server lookups Signed-off-by: Jim Bugwadia <jim@nirmata.com> * initial commit for API server lookups Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Enhancing dockerfiles (multi-stage) of kyverno components and adding non-root user to the docker images (#1495) * Dockerfile refactored Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * Adding non-root commands to docker images and enhanced the dockerfiles Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * changing base image to scratch Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * Minor typo fix Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * changing dockerfiles to use /etc/passwd to use non-root user' Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * minor typo Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * minor typo Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert cli image name (#1507) Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Refactor resourceCache; Reduce throttling requests (background controller) (#1500) * skip sending API request for filtered resource * fix PR comment Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fixes https://github.com/kyverno/kyverno/issues/1490 Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix bug - namespace is not returned properly Signed-off-by: Shuting Zhao <shutting06@gmail.com> * reduce throttling - list resource using lister * refactor resource cache * fix test Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix label selector Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix build failure Signed-off-by: Shuting Zhao <shutting06@gmail.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix merge issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix unit test Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add nil check for API client Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Raj Babu Das <mail.rajdas@gmail.com> Co-authored-by: shuting <shutting06@gmail.com>
2021-02-01 12:59:13 -08:00
policyCtx := &engine.PolicyContext{
Policy: policy,
api server lookups (#1514) * initial commit for api server lookups Signed-off-by: Jim Bugwadia <jim@nirmata.com> * initial commit for API server lookups Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Enhancing dockerfiles (multi-stage) of kyverno components and adding non-root user to the docker images (#1495) * Dockerfile refactored Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * Adding non-root commands to docker images and enhanced the dockerfiles Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * changing base image to scratch Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * Minor typo fix Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * changing dockerfiles to use /etc/passwd to use non-root user' Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * minor typo Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * minor typo Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert cli image name (#1507) Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Refactor resourceCache; Reduce throttling requests (background controller) (#1500) * skip sending API request for filtered resource * fix PR comment Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fixes https://github.com/kyverno/kyverno/issues/1490 Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix bug - namespace is not returned properly Signed-off-by: Shuting Zhao <shutting06@gmail.com> * reduce throttling - list resource using lister * refactor resource cache * fix test Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix label selector Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix build failure Signed-off-by: Shuting Zhao <shutting06@gmail.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix merge issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix unit test Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add nil check for API client Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Raj Babu Das <mail.rajdas@gmail.com> Co-authored-by: shuting <shutting06@gmail.com>
2021-02-01 12:59:13 -08:00
NewResource: resource,
ExcludeGroupRole: excludeGroupRole,
JSONContext: ctx,
Client: client,
NamespaceLabels: namespaceLabels,
api server lookups (#1514) * initial commit for api server lookups Signed-off-by: Jim Bugwadia <jim@nirmata.com> * initial commit for API server lookups Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Enhancing dockerfiles (multi-stage) of kyverno components and adding non-root user to the docker images (#1495) * Dockerfile refactored Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * Adding non-root commands to docker images and enhanced the dockerfiles Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * changing base image to scratch Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * Minor typo fix Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * changing dockerfiles to use /etc/passwd to use non-root user' Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * minor typo Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> * minor typo Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert cli image name (#1507) Signed-off-by: Raj Babu Das <mail.rajdas@gmail.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Refactor resourceCache; Reduce throttling requests (background controller) (#1500) * skip sending API request for filtered resource * fix PR comment Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fixes https://github.com/kyverno/kyverno/issues/1490 Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix bug - namespace is not returned properly Signed-off-by: Shuting Zhao <shutting06@gmail.com> * reduce throttling - list resource using lister * refactor resource cache * fix test Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix label selector Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix build failure Signed-off-by: Shuting Zhao <shutting06@gmail.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix merge issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix unit test Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add nil check for API client Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Raj Babu Das <mail.rajdas@gmail.com> Co-authored-by: shuting <shutting06@gmail.com>
2021-02-01 12:59:13 -08:00
}
engineResponseValidation = engine.Validate(policyCtx)
engineResponses = append(engineResponses, mergeRuleRespose(engineResponseMutation, engineResponseValidation))
2019-08-26 13:34:42 -07:00
return engineResponses
}
func mutation(policy kyvernov1.PolicyInterface, resource unstructured.Unstructured, log logr.Logger, jsonContext context.Interface, namespaceLabels map[string]string) (*response.EngineResponse, error) {
2020-12-23 15:10:07 -08:00
policyContext := &engine.PolicyContext{
Policy: policy,
NewResource: resource,
JSONContext: jsonContext,
NamespaceLabels: namespaceLabels,
2020-12-23 15:10:07 -08:00
}
engineResponse := engine.Mutate(policyContext)
if !engineResponse.IsSuccessful() {
2020-03-17 11:05:20 -07:00
log.V(4).Info("failed to apply mutation rules; reporting them")
2019-08-26 13:34:42 -07:00
return engineResponse, nil
2019-08-20 16:57:19 -07:00
}
// Verify if the JSON patches returned by the Mutate are already applied to the resource
2019-08-26 13:34:42 -07:00
if reflect.DeepEqual(resource, engineResponse.PatchedResource) {
// resources matches
log.V(4).Info("resource already satisfies the policy")
2019-08-26 13:34:42 -07:00
return engineResponse, nil
2019-08-20 16:57:19 -07:00
}
2020-03-17 11:05:20 -07:00
return getFailedOverallRuleInfo(resource, engineResponse, log)
2019-08-26 13:34:42 -07:00
}
2019-08-20 16:57:19 -07:00
2019-08-26 13:34:42 -07:00
// getFailedOverallRuleInfo gets detailed info for over-all mutation failure
2020-12-23 15:10:07 -08:00
func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse *response.EngineResponse, log logr.Logger) (*response.EngineResponse, error) {
2019-08-26 13:34:42 -07:00
rawResource, err := resource.MarshalJSON()
if err != nil {
2020-10-27 00:41:16 +05:30
log.Error(err, "failed to marshall resource")
2020-12-23 15:10:07 -08:00
return &response.EngineResponse{}, err
}
2019-08-26 13:34:42 -07:00
// resource does not match so there was a mutation rule violated
for index, rule := range engineResponse.PolicyResponse.Rules {
2020-05-26 23:07:48 -07:00
log.V(4).Info("verifying if policy rule was applied before", "rule", rule.Name)
patches := rule.Patches
patch, err := jsonpatch.DecodePatch(jsonutils.JoinPatches(patches...))
2019-08-26 13:34:42 -07:00
if err != nil {
log.Error(err, "failed to decode JSON patch", "patches", patches)
2020-12-23 15:10:07 -08:00
return &response.EngineResponse{}, err
2019-08-26 13:34:42 -07:00
}
2019-08-26 13:34:42 -07:00
// apply the patches returned by mutate to the original resource
patchedResource, err := patch.Apply(rawResource)
if err != nil {
log.Error(err, "failed to apply JSON patch", "patches", patches)
2020-12-23 15:10:07 -08:00
return &response.EngineResponse{}, err
2019-08-26 13:34:42 -07:00
}
2019-08-26 13:34:42 -07:00
if !jsonpatch.Equal(patchedResource, rawResource) {
2020-03-17 11:05:20 -07:00
log.V(4).Info("policy rule conditions not satisfied by resource", "rule", rule.Name)
engineResponse.PolicyResponse.Rules[index].Status = response.RuleStatusFail
engineResponse.PolicyResponse.Rules[index].Message = fmt.Sprintf("mutation json patches not found at resource path %s", extractPatchPath(patches, log))
2019-08-26 13:34:42 -07:00
}
}
2019-08-26 13:34:42 -07:00
return engineResponse, nil
}
2020-03-17 11:05:20 -07:00
func extractPatchPath(patches [][]byte, log logr.Logger) string {
var resultPath []string
// extract the patch path and value
for _, patch := range patches {
if data, err := jsonutils.UnmarshalPatchOperation(patch); err != nil {
2020-03-17 11:05:20 -07:00
log.Error(err, "failed to decode the generate patch", "patch", string(patch))
continue
} else {
resultPath = append(resultPath, data.Path)
}
}
return strings.Join(resultPath, ";")
}
2020-12-23 15:10:07 -08:00
func mergeRuleRespose(mutation, validation *response.EngineResponse) *response.EngineResponse {
mutation.PolicyResponse.Rules = append(mutation.PolicyResponse.Rules, validation.PolicyResponse.Rules...)
return mutation
}