diff --git a/main.go b/main.go index 749b974e1e..ee3a7745d0 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,6 @@ import ( "github.com/nirmata/kyverno/pkg/policyviolation" "github.com/nirmata/kyverno/pkg/sharedinformer" "github.com/nirmata/kyverno/pkg/utils" - "github.com/nirmata/kyverno/pkg/violation" "github.com/nirmata/kyverno/pkg/webhooks" "k8s.io/sample-controller/pkg/signals" ) @@ -64,7 +63,7 @@ func main() { } kubeInformer := utils.NewKubeInformerFactory(clientConfig) eventController := event.NewEventController(client, policyInformerFactory) - violationBuilder := violation.NewPolicyViolationBuilder(client, policyInformerFactory, eventController) + // violationBuilder := violation.NewPolicyViolationBuilder(client, policyInformerFactory, eventController) annotationsController := annotations.NewAnnotationControler(client) // policyController := controller.NewPolicyController( // client, @@ -79,7 +78,7 @@ func main() { if err != nil { glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err) } - server, err := webhooks.NewWebhookServer(client, tlsPair, policyInformerFactory, eventController, violationBuilder, annotationsController, filterK8Resources) + server, err := webhooks.NewWebhookServer(client, tlsPair, policyInformerFactory, eventController, nil, annotationsController, filterK8Resources) if err != nil { glog.Fatalf("Unable to create webhook server: %v\n", err) } diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index f1d551e1e6..8f1112a28c 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -5,10 +5,13 @@ import ( kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" "github.com/nirmata/kyverno/pkg/info" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + // "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) // Mutate performs mutation. Overlay first and then mutation patches func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([][]byte, []*info.RuleInfo) { + // + var allPatches [][]byte patchedDocument := rawResource ris := []*info.RuleInfo{} @@ -17,16 +20,22 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio if rule.Mutation == nil { continue } - ri := info.NewRuleInfo(rule.Name, info.Mutation) + // check if the resource satisfies the filter conditions defined in the rule + //TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that + // dont statisfy a policy rule resource description ok := ResourceMeetsDescription(rawResource, rule.MatchResources.ResourceDescription, rule.ExcludeResources.ResourceDescription, gvk) if !ok { - glog.V(3).Infof("Not applicable on specified resource kind%s", gvk.Kind) + name := ParseNameFromObject(rawResource) + namespace := ParseNamespaceFromObject(rawResource) + glog.V(3).Infof("resource %s/%s does not satisfy the resource description for the rule ", namespace, name) continue } + ri := info.NewRuleInfo(rule.Name, info.Mutation) + // Process Overlay if rule.Mutation.Overlay != nil { - overlayPatches, err := ProcessOverlay(rule, rawResource, gvk) + overlayPatches, err := processOverlay(rule, rawResource, gvk) if err == nil { if len(overlayPatches) == 0 { // if array elements dont match then we skip(nil patch, no error) @@ -34,28 +43,32 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio // policy is not applicable continue } - ri.Addf("Rule %s: Overlay succesfully applied.", rule.Name) - // merge the json patches + glog.V(4).Infof("overlay applied succesfully on resource") + ri.Add("Overlay succesfully applied") patch := JoinPatches(overlayPatches) + allPatches = append(allPatches, overlayPatches...) + // update rule information // strip slashes from string ri.Changes = string(patch) - allPatches = append(allPatches, overlayPatches...) } else { + glog.V(4).Infof("failed to apply overlay: %v", err) ri.Fail() - ri.Addf("overlay application has failed, err %v.", err) + ri.Addf("failed to apply overlay: %v", err) } } // Process Patches if len(rule.Mutation.Patches) != 0 { - rulePatches, errs := ProcessPatches(rule, patchedDocument) + rulePatches, errs := processPatches(rule, patchedDocument) if len(errs) > 0 { ri.Fail() for _, err := range errs { + glog.V(4).Infof("failed to apply patches: %v", err) ri.Addf("patches application has failed, err %v.", err) } } else { - ri.Addf("Rule %s: Patches succesfully applied.", rule.Name) + glog.V(4).Infof("patches applied succesfully on resource") + ri.Addf("Patches succesfully applied.") allPatches = append(allPatches, rulePatches...) } } diff --git a/pkg/engine/overlay.go b/pkg/engine/overlay.go index 7fea8f4cec..fb4c556471 100644 --- a/pkg/engine/overlay.go +++ b/pkg/engine/overlay.go @@ -17,7 +17,7 @@ import ( // ProcessOverlay handles validating admission request // Checks the target resources for rules defined in the policy -func ProcessOverlay(rule kubepolicy.Rule, rawResource []byte, gvk metav1.GroupVersionKind) ([][]byte, error) { +func processOverlay(rule kubepolicy.Rule, rawResource []byte, gvk metav1.GroupVersionKind) ([][]byte, error) { var resource interface{} if err := json.Unmarshal(rawResource, &resource); err != nil { diff --git a/pkg/engine/patches.go b/pkg/engine/patches.go index 7b7a19bd8e..8f7d69c76e 100644 --- a/pkg/engine/patches.go +++ b/pkg/engine/patches.go @@ -12,7 +12,7 @@ import ( // ProcessPatches Returns array from separate patches that can be applied to the document // Returns error ONLY in case when creation of resource should be denied. -func ProcessPatches(rule kubepolicy.Rule, resource []byte) (allPatches [][]byte, errs []error) { +func processPatches(rule kubepolicy.Rule, resource []byte) (allPatches [][]byte, errs []error) { if len(resource) == 0 { errs = append(errs, errors.New("Source document for patching is empty")) return nil, errs diff --git a/pkg/engine/patches_test.go b/pkg/engine/patches_test.go index 0f6bbcfe1b..2c58a15566 100644 --- a/pkg/engine/patches_test.go +++ b/pkg/engine/patches_test.go @@ -35,7 +35,7 @@ const endpointsDocument string = `{ func TestProcessPatches_EmptyPatches(t *testing.T) { var emptyRule = types.Rule{} - patches, err := ProcessPatches(emptyRule, []byte(endpointsDocument)) + patches, err := processPatches(emptyRule, []byte(endpointsDocument)) assert.Check(t, len(err) == 1) assert.Assert(t, len(patches) == 0) } @@ -64,14 +64,14 @@ func makeRuleWithPatches(patches []types.Patch) types.Rule { func TestProcessPatches_EmptyDocument(t *testing.T) { rule := makeRuleWithPatch(makeAddIsMutatedLabelPatch()) - patchesBytes, err := ProcessPatches(rule, nil) + patchesBytes, err := processPatches(rule, nil) assert.Assert(t, err != nil) assert.Assert(t, len(patchesBytes) == 0) } func TestProcessPatches_AllEmpty(t *testing.T) { emptyRule := types.Rule{} - patchesBytes, err := ProcessPatches(emptyRule, nil) + patchesBytes, err := processPatches(emptyRule, nil) assert.Check(t, len(err) == 1) assert.Assert(t, len(patchesBytes) == 0) } @@ -80,7 +80,7 @@ func TestProcessPatches_AddPathDoesntExist(t *testing.T) { patch := makeAddIsMutatedLabelPatch() patch.Path = "/metadata/additional/is-mutated" rule := makeRuleWithPatch(patch) - patchesBytes, err := ProcessPatches(rule, []byte(endpointsDocument)) + patchesBytes, err := processPatches(rule, []byte(endpointsDocument)) assert.Check(t, len(err) == 1) assert.Assert(t, len(patchesBytes) == 0) } @@ -88,7 +88,7 @@ func TestProcessPatches_AddPathDoesntExist(t *testing.T) { func TestProcessPatches_RemovePathDoesntExist(t *testing.T) { patch := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"} rule := makeRuleWithPatch(patch) - patchesBytes, err := ProcessPatches(rule, []byte(endpointsDocument)) + patchesBytes, err := processPatches(rule, []byte(endpointsDocument)) assert.Check(t, len(err) == 0) assert.Assert(t, len(patchesBytes) == 0) } @@ -97,7 +97,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_EmptyResult(t *testing.T) { patch1 := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"} patch2 := types.Patch{Path: "/spec/labels/label3", Operation: "add", Value: "label3Value"} rule := makeRuleWithPatches([]types.Patch{patch1, patch2}) - patchesBytes, err := ProcessPatches(rule, []byte(endpointsDocument)) + patchesBytes, err := processPatches(rule, []byte(endpointsDocument)) assert.Check(t, len(err) == 1) assert.Assert(t, len(patchesBytes) == 0) } @@ -107,7 +107,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_ContinueOnError_NotEmptyResul patch2 := types.Patch{Path: "/spec/labels/label2", Operation: "remove", Value: "label2Value"} patch3 := types.Patch{Path: "/metadata/labels/label3", Operation: "add", Value: "label3Value"} rule := makeRuleWithPatches([]types.Patch{patch1, patch2, patch3}) - patchesBytes, err := ProcessPatches(rule, []byte(endpointsDocument)) + patchesBytes, err := processPatches(rule, []byte(endpointsDocument)) assert.Check(t, len(err) == 0) assert.Assert(t, len(patchesBytes) != 0) assertEqStringAndData(t, `{"path":"/metadata/labels/label3","op":"add","value":"label3Value"}`, patchesBytes[0]) @@ -116,7 +116,7 @@ func TestProcessPatches_AddAndRemovePathsDontExist_ContinueOnError_NotEmptyResul func TestProcessPatches_RemovePathDoesntExist_EmptyResult(t *testing.T) { patch := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"} rule := makeRuleWithPatch(patch) - patchesBytes, err := ProcessPatches(rule, []byte(endpointsDocument)) + patchesBytes, err := processPatches(rule, []byte(endpointsDocument)) assert.Check(t, len(err) == 0) assert.Assert(t, len(patchesBytes) == 0) } @@ -125,7 +125,7 @@ func TestProcessPatches_RemovePathDoesntExist_NotEmptyResult(t *testing.T) { patch1 := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"} patch2 := types.Patch{Path: "/metadata/labels/label2", Operation: "add", Value: "label2Value"} rule := makeRuleWithPatches([]types.Patch{patch1, patch2}) - patchesBytes, err := ProcessPatches(rule, []byte(endpointsDocument)) + patchesBytes, err := processPatches(rule, []byte(endpointsDocument)) assert.Check(t, len(err) == 0) assert.Assert(t, len(patchesBytes) == 1) assertEqStringAndData(t, `{"path":"/metadata/labels/label2","op":"add","value":"label2Value"}`, patchesBytes[0]) diff --git a/pkg/info/info.go b/pkg/info/info.go index 8d61b764f0..05777a4cdc 100644 --- a/pkg/info/info.go +++ b/pkg/info/info.go @@ -114,9 +114,9 @@ func (ri RuleType) String() string { //RuleInfo defines rule struct type RuleInfo struct { Name string + RuleType RuleType Msgs []string Changes string // this will store the mutation patch being applied by the rule - RuleType RuleType success bool } diff --git a/pkg/policyviolation/helpers.go b/pkg/policyviolation/helpers.go new file mode 100644 index 0000000000..69d8d85ae4 --- /dev/null +++ b/pkg/policyviolation/helpers.go @@ -0,0 +1,17 @@ +package policyviolation + +import ( + kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1" +) + +//BuildPolicyViolation returns an value of type PolicyViolation +func BuildPolicyViolation(policy string, resource kyverno.ResourceSpec, fRules []kyverno.ViolatedRule) kyverno.PolicyViolation { + pv := kyverno.PolicyViolation{ + Spec: kyverno.PolicyViolationSpec{ + Policy: policy, + ResourceSpec: resource, + ViolatedRules: fRules, + }, + } + return pv +}