1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/policymutation/policymutation.go

170 lines
6.2 KiB
Go
Raw Normal View History

2020-07-10 18:12:19 +05:30
package policymutation
import (
"fmt"
"strconv"
"strings"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/toggle"
jsonutils "github.com/kyverno/kyverno/pkg/utils/json"
2020-07-10 18:12:19 +05:30
)
2020-11-17 13:07:30 -08:00
// GenerateJSONPatchesForDefaults generates default JSON patches for
// - ValidationFailureAction
// - Background
// - auto-gen annotation and rules
func GenerateJSONPatchesForDefaults(policy kyvernov1.PolicyInterface, log logr.Logger) ([]byte, []string) {
2020-07-10 18:12:19 +05:30
var patches [][]byte
var updateMsgs []string
spec := policy.GetSpec()
// if autogenInternals is enabled, we don't mutate most of the policy fields
if !toggle.AutogenInternals() {
// default 'ValidationFailureAction'
if patch, updateMsg := defaultvalidationFailureAction(spec, log); patch != nil {
patches = append(patches, patch)
updateMsgs = append(updateMsgs, updateMsg)
}
// default 'Background'
if patch, updateMsg := defaultBackgroundFlag(spec, log); patch != nil {
patches = append(patches, patch)
updateMsgs = append(updateMsgs, updateMsg)
}
if patch, updateMsg := defaultFailurePolicy(spec, log); patch != nil {
patches = append(patches, patch)
updateMsgs = append(updateMsgs, updateMsg)
}
patch, errs := GeneratePodControllerRule(policy, log)
if len(errs) > 0 {
var errMsgs []string
for _, err := range errs {
errMsgs = append(errMsgs, err.Error())
log.Error(err, "failed to generate pod controller rule")
}
updateMsgs = append(updateMsgs, strings.Join(errMsgs, ";"))
2020-07-10 18:12:19 +05:30
}
patches = append(patches, patch...)
2020-07-10 18:12:19 +05:30
}
return jsonutils.JoinPatches(patches...), updateMsgs
}
func defaultBackgroundFlag(spec *kyvernov1.Spec, log logr.Logger) ([]byte, string) {
2020-07-10 18:12:19 +05:30
// set 'Background' flag to 'true' if not specified
if spec.Background == nil {
defaultVal := true
2020-07-11 18:12:35 +05:30
log.V(4).Info("setting default value", "spec.background", true)
patchByte, err := jsonutils.MarshalPatchOperation("/spec/background", "add", &defaultVal)
2020-07-10 18:12:19 +05:30
if err != nil {
2020-07-11 18:12:35 +05:30
log.Error(err, "failed to set default value", "spec.background", true)
2020-07-10 18:12:19 +05:30
return nil, ""
}
2020-07-11 18:12:35 +05:30
log.V(3).Info("generated JSON Patch to set default", "spec.background", true)
2020-07-10 18:12:19 +05:30
return patchByte, fmt.Sprintf("default 'Background' to '%s'", strconv.FormatBool(true))
}
return nil, ""
}
func defaultvalidationFailureAction(spec *kyvernov1.Spec, log logr.Logger) ([]byte, string) {
2020-07-10 18:12:19 +05:30
// set ValidationFailureAction to "audit" if not specified
if spec.ValidationFailureAction == "" {
audit := kyvernov1.Audit
log.V(4).Info("setting default value", "spec.validationFailureAction", audit)
patchByte, err := jsonutils.MarshalPatchOperation("/spec/validationFailureAction", "add", audit)
2020-07-10 18:12:19 +05:30
if err != nil {
log.Error(err, "failed to default value", "spec.validationFailureAction", audit)
2020-07-10 18:12:19 +05:30
return nil, ""
}
log.V(3).Info("generated JSON Patch to set default", "spec.validationFailureAction", audit)
return patchByte, fmt.Sprintf("default 'ValidationFailureAction' to '%s'", audit)
2020-07-10 18:12:19 +05:30
}
return nil, ""
}
func defaultFailurePolicy(spec *kyvernov1.Spec, log logr.Logger) ([]byte, string) {
Dynamic webhooks (#2425) * support k8s 1.22, update admissionregistration.k8s.io/v1beta1 to admissionregistration.k8s.io/v1 Signed-off-by: ShutingZhao <shutting06@gmail.com> * - add failurePolicy to policy spec; - fix typo Signed-off-by: ShutingZhao <shutting06@gmail.com> * - add schema validation for failurePolicy; - add a printer column Signed-off-by: ShutingZhao <shutting06@gmail.com> * set default failure policy to fail if not defined Signed-off-by: ShutingZhao <shutting06@gmail.com> * resolve conflicts Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix missing type for printerColumn Signed-off-by: ShutingZhao <shutting06@gmail.com> * refactor policy controller Signed-off-by: ShutingZhao <shutting06@gmail.com> * add webhook config manager Signed-off-by: ShutingZhao <shutting06@gmail.com> * - build webhook objects per policy update; - add fail webhook to default webhook configurations Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix panic on policy update Signed-off-by: ShutingZhao <shutting06@gmail.com> * build default webhook: match empty if autoUpdateWebhooks is enabled, otherwise match all Signed-off-by: ShutingZhao <shutting06@gmail.com> * - set default webhook configs rule to empty; - handle policy deletion Signed-off-by: ShutingZhao <shutting06@gmail.com> * reset webhook config if policies with a specific failurePolicy are cleaned up Signed-off-by: ShutingZhao <shutting06@gmail.com> * handle wildcard pocliy Signed-off-by: ShutingZhao <shutting06@gmail.com> * update default webhook timeout to 10s Signed-off-by: ShutingZhao <shutting06@gmail.com> * cleanups Signed-off-by: ShutingZhao <shutting06@gmail.com> * added webhook informer to re-create it immediately if missing Signed-off-by: ShutingZhao <shutting06@gmail.com> * update tag webhookTimeoutSeconds description Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix e2e tests Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix linter issue Signed-off-by: ShutingZhao <shutting06@gmail.com> * correct metric endpoint Signed-off-by: ShutingZhao <shutting06@gmail.com> * add pol.generate.kind to webhooks Signed-off-by: ShutingZhao <shutting06@gmail.com>
2021-10-05 00:15:09 -07:00
// set failurePolicy to Fail if not present
if spec.FailurePolicy == nil {
failurePolicy := string(kyvernov1.Fail)
Dynamic webhooks (#2425) * support k8s 1.22, update admissionregistration.k8s.io/v1beta1 to admissionregistration.k8s.io/v1 Signed-off-by: ShutingZhao <shutting06@gmail.com> * - add failurePolicy to policy spec; - fix typo Signed-off-by: ShutingZhao <shutting06@gmail.com> * - add schema validation for failurePolicy; - add a printer column Signed-off-by: ShutingZhao <shutting06@gmail.com> * set default failure policy to fail if not defined Signed-off-by: ShutingZhao <shutting06@gmail.com> * resolve conflicts Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix missing type for printerColumn Signed-off-by: ShutingZhao <shutting06@gmail.com> * refactor policy controller Signed-off-by: ShutingZhao <shutting06@gmail.com> * add webhook config manager Signed-off-by: ShutingZhao <shutting06@gmail.com> * - build webhook objects per policy update; - add fail webhook to default webhook configurations Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix panic on policy update Signed-off-by: ShutingZhao <shutting06@gmail.com> * build default webhook: match empty if autoUpdateWebhooks is enabled, otherwise match all Signed-off-by: ShutingZhao <shutting06@gmail.com> * - set default webhook configs rule to empty; - handle policy deletion Signed-off-by: ShutingZhao <shutting06@gmail.com> * reset webhook config if policies with a specific failurePolicy are cleaned up Signed-off-by: ShutingZhao <shutting06@gmail.com> * handle wildcard pocliy Signed-off-by: ShutingZhao <shutting06@gmail.com> * update default webhook timeout to 10s Signed-off-by: ShutingZhao <shutting06@gmail.com> * cleanups Signed-off-by: ShutingZhao <shutting06@gmail.com> * added webhook informer to re-create it immediately if missing Signed-off-by: ShutingZhao <shutting06@gmail.com> * update tag webhookTimeoutSeconds description Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix e2e tests Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix linter issue Signed-off-by: ShutingZhao <shutting06@gmail.com> * correct metric endpoint Signed-off-by: ShutingZhao <shutting06@gmail.com> * add pol.generate.kind to webhooks Signed-off-by: ShutingZhao <shutting06@gmail.com>
2021-10-05 00:15:09 -07:00
log.V(4).Info("setting default value", "spec.failurePolicy", failurePolicy)
patchByte, err := jsonutils.MarshalPatchOperation("/spec/failurePolicy", "add", failurePolicy)
Dynamic webhooks (#2425) * support k8s 1.22, update admissionregistration.k8s.io/v1beta1 to admissionregistration.k8s.io/v1 Signed-off-by: ShutingZhao <shutting06@gmail.com> * - add failurePolicy to policy spec; - fix typo Signed-off-by: ShutingZhao <shutting06@gmail.com> * - add schema validation for failurePolicy; - add a printer column Signed-off-by: ShutingZhao <shutting06@gmail.com> * set default failure policy to fail if not defined Signed-off-by: ShutingZhao <shutting06@gmail.com> * resolve conflicts Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix missing type for printerColumn Signed-off-by: ShutingZhao <shutting06@gmail.com> * refactor policy controller Signed-off-by: ShutingZhao <shutting06@gmail.com> * add webhook config manager Signed-off-by: ShutingZhao <shutting06@gmail.com> * - build webhook objects per policy update; - add fail webhook to default webhook configurations Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix panic on policy update Signed-off-by: ShutingZhao <shutting06@gmail.com> * build default webhook: match empty if autoUpdateWebhooks is enabled, otherwise match all Signed-off-by: ShutingZhao <shutting06@gmail.com> * - set default webhook configs rule to empty; - handle policy deletion Signed-off-by: ShutingZhao <shutting06@gmail.com> * reset webhook config if policies with a specific failurePolicy are cleaned up Signed-off-by: ShutingZhao <shutting06@gmail.com> * handle wildcard pocliy Signed-off-by: ShutingZhao <shutting06@gmail.com> * update default webhook timeout to 10s Signed-off-by: ShutingZhao <shutting06@gmail.com> * cleanups Signed-off-by: ShutingZhao <shutting06@gmail.com> * added webhook informer to re-create it immediately if missing Signed-off-by: ShutingZhao <shutting06@gmail.com> * update tag webhookTimeoutSeconds description Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix e2e tests Signed-off-by: ShutingZhao <shutting06@gmail.com> * fix linter issue Signed-off-by: ShutingZhao <shutting06@gmail.com> * correct metric endpoint Signed-off-by: ShutingZhao <shutting06@gmail.com> * add pol.generate.kind to webhooks Signed-off-by: ShutingZhao <shutting06@gmail.com>
2021-10-05 00:15:09 -07:00
if err != nil {
log.Error(err, "failed to set default value", "spec.failurePolicy", failurePolicy)
return nil, ""
}
log.V(3).Info("generated JSON Patch to set default", "spec.failurePolicy", failurePolicy)
return patchByte, fmt.Sprintf("default failurePolicy to '%s'", failurePolicy)
}
return nil, ""
}
2020-07-10 18:12:19 +05:30
// podControllersKey annotation could be:
// scenario A: not exist, set default to "all", which generates on all pod controllers
// - if name / selector exist in resource description -> skip
// as these fields may not be applicable to pod controllers
// scenario B: "none", user explicitly disable this feature -> skip
// scenario C: some certain controllers that user set -> generate on defined controllers
2020-12-01 22:50:40 -08:00
// copy entire match / exclude block, it's users' responsibility to
// make sure all fields are applicable to pod controllers
2020-07-10 18:12:19 +05:30
// GeneratePodControllerRule returns two patches: rulePatches and annotation patch(if necessary)
func GeneratePodControllerRule(policy kyvernov1.PolicyInterface, log logr.Logger) (patches [][]byte, errs []error) {
spec := policy.GetSpec()
applyAutoGen, desiredControllers := autogen.CanAutoGen(spec)
if !applyAutoGen {
desiredControllers = "none"
}
2020-07-10 18:12:19 +05:30
ann := policy.GetAnnotations()
actualControllers, ok := ann[kyvernov1.PodControllersAnnotation]
2020-07-10 18:12:19 +05:30
// - scenario A
// - predefined controllers are invalid, overwrite the value
if !ok || !applyAutoGen {
actualControllers = desiredControllers
annPatch, err := defaultPodControllerAnnotation(ann, actualControllers)
if err != nil {
errs = append(errs, fmt.Errorf("failed to generate pod controller annotation for policy '%s': %v", policy.GetName(), err))
} else {
patches = append(patches, annPatch)
2020-07-10 18:12:19 +05:30
}
} else {
if !applyAutoGen {
actualControllers = desiredControllers
}
2020-07-10 18:12:19 +05:30
}
// scenario B
if actualControllers == "none" {
return patches, nil
2020-07-10 18:12:19 +05:30
}
log.V(3).Info("auto generating rule for pod controllers", "controllers", actualControllers)
2020-07-10 18:12:19 +05:30
p, err := autogen.GenerateRulePatches(spec, actualControllers)
2020-07-10 18:12:19 +05:30
patches = append(patches, p...)
errs = append(errs, err...)
return
}
// defaultPodControllerAnnotation inserts an annotation
// "pod-policies.kyverno.io/autogen-controllers=<controllers>" to policy
func defaultPodControllerAnnotation(ann map[string]string, controllers string) ([]byte, error) {
2020-07-10 18:12:19 +05:30
if ann == nil {
ann = make(map[string]string)
ann[kyvernov1.PodControllersAnnotation] = controllers
patchByte, err := jsonutils.MarshalPatchOperation("/metadata/annotations", "add", ann)
2020-07-10 18:12:19 +05:30
if err != nil {
return nil, err
}
return patchByte, nil
}
patchByte, err := jsonutils.MarshalPatchOperation("/metadata/annotations/pod-policies.kyverno.io~1autogen-controllers", "add", controllers)
2020-07-10 18:12:19 +05:30
if err != nil {
return nil, err
}
return patchByte, nil
}