diff --git a/core/pkg/opaprocessor/processorhandlerutils.go b/core/pkg/opaprocessor/processorhandlerutils.go index 2a087da6..1d544f4a 100644 --- a/core/pkg/opaprocessor/processorhandlerutils.go +++ b/core/pkg/opaprocessor/processorhandlerutils.go @@ -3,6 +3,8 @@ package opaprocessor import ( "context" + corev1 "k8s.io/api/core/v1" + logger "github.com/kubescape/go-logger" "github.com/kubescape/k8s-interface/k8sinterface" "github.com/kubescape/k8s-interface/workloadinterface" @@ -97,7 +99,7 @@ func isEmptyResources(counters reportsummary.ICounters) bool { func getAllSupportedObjects(k8sResources cautils.K8SResources, externalResources cautils.ExternalResources, allResources map[string]workloadinterface.IMetadata, rule *reporthandling.PolicyRule) map[string][]workloadinterface.IMetadata { k8sObjects := getKubernetesObjects(k8sResources, allResources, rule.Match) - externalObjs := getKubenetesObjectsFromExternalResources(externalResources, allResources, rule.DynamicMatch) + externalObjs := getKubernetesObjectsFromExternalResources(externalResources, allResources, rule.DynamicMatch) if len(externalObjs) > 0 { l, ok := k8sObjects[clusterScope] if !ok { @@ -109,7 +111,7 @@ func getAllSupportedObjects(k8sResources cautils.K8SResources, externalResources return k8sObjects } -func getKubenetesObjectsFromExternalResources(externalResources cautils.ExternalResources, allResources map[string]workloadinterface.IMetadata, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata { +func getKubernetesObjectsFromExternalResources(externalResources cautils.ExternalResources, allResources map[string]workloadinterface.IMetadata, match []reporthandling.RuleMatchObjects) []workloadinterface.IMetadata { k8sObjects := []workloadinterface.IMetadata{} for m := range match { @@ -215,16 +217,39 @@ func removePodData(workload workloadinterface.IWorkload) { workloadinterface.RemoveFromMap(workload.GetObject(), "metadata", "managedFields") workloadinterface.RemoveFromMap(workload.GetObject(), "status") - containers, err := workload.GetContainers() - if err != nil || len(containers) == 0 { - return + // containers + if containers, err := workload.GetContainers(); err == nil && len(containers) > 0 { + removeContainersData(containers) + workloadinterface.SetInMap(workload.GetObject(), workloadinterface.PodSpec(workload.GetKind()), "containers", containers) } + + // init containers + + if initContainers, err := workload.GetInitContainers(); err == nil && len(initContainers) > 0 { + removeContainersData(initContainers) + workloadinterface.SetInMap(workload.GetObject(), workloadinterface.PodSpec(workload.GetKind()), "initContainers", initContainers) + } + + // ephemeral containers + if ephemeralContainers, err := workload.GetEphemeralContainers(); err == nil && len(ephemeralContainers) > 0 { + removeEphemeralContainersData(ephemeralContainers) + workloadinterface.SetInMap(workload.GetObject(), workloadinterface.PodSpec(workload.GetKind()), "ephemeralContainers", ephemeralContainers) + } +} + +func removeContainersData(containers []corev1.Container) { + for i := range containers { + for j := range containers[i].Env { + containers[i].Env[j].Value = "XXXXXX" + } + } +} +func removeEphemeralContainersData(containers []corev1.EphemeralContainer) { for i := range containers { for j := range containers[i].Env { containers[i].Env[j].Value = "XXXXXX" } } - workloadinterface.SetInMap(workload.GetObject(), workloadinterface.PodSpec(workload.GetKind()), "containers", containers) } func ruleData(rule *reporthandling.PolicyRule) string { diff --git a/core/pkg/opaprocessor/processorhandlerutils_test.go b/core/pkg/opaprocessor/processorhandlerutils_test.go index 1cfe947c..e1f8f2a9 100644 --- a/core/pkg/opaprocessor/processorhandlerutils_test.go +++ b/core/pkg/opaprocessor/processorhandlerutils_test.go @@ -3,21 +3,152 @@ package opaprocessor import ( "testing" + corev1 "k8s.io/api/core/v1" + "github.com/stretchr/testify/assert" "github.com/kubescape/k8s-interface/workloadinterface" ) func TestRemoveData(t *testing.T) { + type args struct { + w string + } + tests := []struct { + name string + args args + }{ + { + name: "remove data", + args: args{ + w: `{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"demoservice-server", "annotations": {"name": "kubectl.kubernetes.io/last-applied-configuration", "value": "blabla"}},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"demoservice-server"}},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"demoservice-server"}},"spec":{"containers":[{"env":[{"name":"SERVER_PORT","value":"8089"},{"name":"SLEEP_DURATION","value":"1"},{"name":"DEMO_FOLDERS","value":"/app"},{"name":"ARMO_TEST_NAME","value":"auto_attach_deployment"},{"name":"CAA_ENABLE_CRASH_REPORTER","value":"1"}],"image":"quay.io/armosec/demoservice:v25","imagePullPolicy":"IfNotPresent","name":"demoservice","ports":[{"containerPort":8089,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File"}],"dnsPolicy":"ClusterFirst","restartPolicy":"Always","schedulerName":"default-scheduler","securityContext":{},"terminationGracePeriodSeconds":30}}}}`, + }, + }, + { + name: "remove data with init containers and ephemeral containers", + args: args{ + w: `{"apiVersion": "v1", "kind": "Pod", "metadata": {"name": "example-pod", "namespace": "default"}, "spec": {"containers": [{"name": "container1", "image": "nginx", "ports": [{"containerPort": 80}], "env": [{"name": "CONTAINER_ENV", "value": "container_value"}]}], "initContainers": [{"name": "init-container1", "image": "busybox", "command": ["sh", "-c", "echo 'Init Container'"], "env": [{"name": "INIT_CONTAINER_ENV", "value": "init_container_value"}]}], "ephemeralContainers": [{"name": "debug-container", "image": "busybox", "command": ["sh", "-c", "echo 'Ephemeral Container'"], "targetContainerName": "container1", "env": [{"name": "EPHEMERAL_CONTAINER_ENV", "value": "ephemeral_container_value"}]}]}}`, + }, + }, + { + name: "remove secret data", + args: args{ + w: `{"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "example-secret", "namespace": "default", "annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{}"}}, "type": "Opaque", "data": {"username": "dXNlcm5hbWU=", "password": "cGFzc3dvcmQ="}}`, + }, + }, + { + name: "remove configMap data", + args: args{ + w: `{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "example-configmap", "namespace": "default", "annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{}"}}, "data": {"exampleKey": "exampleValue"}}`, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + obj, _ := workloadinterface.NewWorkload([]byte(tt.args.w)) + removeData(obj) - w := `{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"demoservice-server"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"demoservice-server"}},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"demoservice-server"}},"spec":{"containers":[{"env":[{"name":"SERVER_PORT","value":"8089"},{"name":"SLEEP_DURATION","value":"1"},{"name":"DEMO_FOLDERS","value":"/app"},{"name":"ARMO_TEST_NAME","value":"auto_attach_deployment"},{"name":"CAA_ENABLE_CRASH_REPORTER","value":"1"}],"image":"quay.io/armosec/demoservice:v25","imagePullPolicy":"IfNotPresent","name":"demoservice","ports":[{"containerPort":8089,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File"}],"dnsPolicy":"ClusterFirst","restartPolicy":"Always","schedulerName":"default-scheduler","securityContext":{},"terminationGracePeriodSeconds":30}}}}` - obj, _ := workloadinterface.NewWorkload([]byte(w)) - removeData(obj) + workload := workloadinterface.NewWorkloadObj(obj.GetObject()) - workload := workloadinterface.NewWorkloadObj(obj.GetObject()) - c, _ := workload.GetContainers() - for i := range c { - for _, e := range c[i].Env { + _, found := workload.GetAnnotation("kubectl.kubernetes.io/last-applied-configuration") + assert.False(t, found) + + _, found = workloadinterface.InspectMap(workload.GetObject(), "metadata", "managedFields") + assert.False(t, found) + + _, found = workloadinterface.InspectMap(workload.GetObject(), "status") + assert.False(t, found) + + if d, ok := workloadinterface.InspectMap(workload.GetObject(), "data"); ok { + data, ok := d.(map[string]interface{}) + assert.True(t, ok) + for key := range data { + assert.Equal(t, "XXXXXX", data[key]) + } + } + + if c, _ := workload.GetContainers(); c != nil { + for i := range c { + for _, e := range c[i].Env { + assert.Equal(t, "XXXXXX", e.Value, e.Name) + } + } + } + + if ic, _ := workload.GetInitContainers(); ic != nil { + for i := range ic { + for _, e := range ic[i].Env { + assert.Equal(t, "XXXXXX", e.Value, e.Name) + } + } + } + + if ec, _ := workload.GetEphemeralContainers(); ec != nil { + for i := range ec { + for _, e := range ec[i].Env { + assert.Equal(t, "XXXXXX", e.Value, e.Name) + } + } + } + }) + } +} + +func TestRemoveContainersData(t *testing.T) { + containers := []corev1.Container{ + { + Env: []corev1.EnvVar{ + { + Name: "TEST_ENV", + Value: "test_value", + }, + { + Name: "ENV_2", + Value: "bla", + }, + { + Name: "EMPTY_ENV", + Value: "", + }, + }, + }, + } + + removeContainersData(containers) + + for _, c := range containers { + for _, e := range c.Env { + assert.Equal(t, "XXXXXX", e.Value) + } + } +} + +func TestRemoveEphemeralContainersData(t *testing.T) { + containers := []corev1.EphemeralContainer{ + { + EphemeralContainerCommon: corev1.EphemeralContainerCommon{ + Env: []corev1.EnvVar{ + { + Name: "TEST_ENV", + Value: "test_value", + }, + { + Name: "ENV_2", + Value: "bla", + }, + { + Name: "EMPTY_ENV", + Value: "", + }, + }, + }, + }, + } + + removeEphemeralContainersData(containers) + + for _, c := range containers { + for _, e := range c.Env { assert.Equal(t, "XXXXXX", e.Value) } }