diff --git a/core/pkg/hostsensorutils/utils.go b/core/pkg/hostsensorutils/utils.go index 055387b9..dd9f9c10 100644 --- a/core/pkg/hostsensorutils/utils.go +++ b/core/pkg/hostsensorutils/utils.go @@ -14,7 +14,7 @@ var ( LinuxKernelVariables = "LinuxKernelVariables" KubeletCommandLine = "KubeletCommandLine" - MapResourceToApiGroup = map[string]string{ + MapHostSensorResourceToApiGroup = map[string]string{ KubeletConfiguration: "hostdata.kubescape.cloud/v1beta0", OsReleaseFile: "hostdata.kubescape.cloud/v1beta0", KubeletCommandLine: "hostdata.kubescape.cloud/v1beta0", @@ -26,7 +26,7 @@ var ( ) func addInfoToMap(resource string, infoMap map[string]apis.StatusInfo, err error) { - group, version := k8sinterface.SplitApiVersion(MapResourceToApiGroup[resource]) + group, version := k8sinterface.SplitApiVersion(MapHostSensorResourceToApiGroup[resource]) r := k8sinterface.JoinResourceTriplets(group, version, resource) infoMap[r] = apis.StatusInfo{ InnerStatus: apis.StatusSkipped, diff --git a/core/pkg/resourcehandler/k8sresources.go b/core/pkg/resourcehandler/k8sresources.go index d02e9659..b16b0bcf 100644 --- a/core/pkg/resourcehandler/k8sresources.go +++ b/core/pkg/resourcehandler/k8sresources.go @@ -18,6 +18,7 @@ import ( "github.com/armosec/armoapi-go/armotypes" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" k8slabels "k8s.io/apimachinery/pkg/labels" @@ -86,6 +87,9 @@ func (k8sHandler *K8sResourceHandler) GetResources(sessionObj *cautils.OPASessio if err := k8sHandler.registryAdaptors.collectImagesVulnerabilities(k8sResourcesMap, allResources, armoResourceMap); err != nil { logger.L().Warning("failed to collect image vulnerabilities", helpers.Error(err)) } + if isEmptyImgVulns(*armoResourceMap) { + cautils.SetInfoMapForResources("image scanning not configured. For more information: https://hub.armo.cloud/docs/cluster-vulnerability-scanning", imgVulnResources, sessionObj.InfoMap) + } } hostResources := cautils.MapHostResources(armoResourceMap) @@ -103,7 +107,7 @@ func (k8sHandler *K8sResourceHandler) GetResources(sessionObj *cautils.OPASessio sessionObj.InfoMap = infoMap } } else { - cautils.SetInfoMapForResources("enable-host-scan flag not used", hostResources, sessionObj.InfoMap) + cautils.SetInfoMapForResources("enable-host-scan flag not used. For more information: https://hub.armo.cloud/docs/host-sensor", hostResources, sessionObj.InfoMap) } } @@ -287,17 +291,31 @@ func getCloudProviderDescription(allResources map[string]workloadinterface.IMeta } func (k8sHandler *K8sResourceHandler) pullWorkerNodesNumber() (int, error) { - // labels used for control plane - listOptions := metav1.ListOptions{ - LabelSelector: "!node-role.kubernetes.io/control-plane,!node-role.kubernetes.io/master", + nodesList, err := k8sHandler.k8s.KubernetesClient.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) + scheduableNodes := v1.NodeList{} + if nodesList != nil { + for _, node := range nodesList.Items { + if len(node.Spec.Taints) == 0 { + scheduableNodes.Items = append(scheduableNodes.Items, node) + } else { + if !isMasterNodeTaints(node.Spec.Taints) { + scheduableNodes.Items = append(scheduableNodes.Items, node) + } + } + } } - nodesList, err := k8sHandler.k8s.KubernetesClient.CoreV1().Nodes().List(context.TODO(), listOptions) if err != nil { return 0, err } - nodesNumber := 0 - if nodesList != nil { - nodesNumber = len(nodesList.Items) + return len(scheduableNodes.Items), nil +} + +// NoSchedule taint with empty value is usually applied to controlplane +func isMasterNodeTaints(taints []v1.Taint) bool { + for _, taint := range taints { + if taint.Effect == v1.TaintEffectNoSchedule && taint.Value == "" { + return true + } } - return nodesNumber, nil + return false } diff --git a/core/pkg/resourcehandler/k8sresources_test.go b/core/pkg/resourcehandler/k8sresources_test.go new file mode 100644 index 00000000..326ddbbc --- /dev/null +++ b/core/pkg/resourcehandler/k8sresources_test.go @@ -0,0 +1,532 @@ +package resourcehandler + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" +) + +func TestIsMasterNodeTaints(t *testing.T) { + noTaintNode := ` +{ +"apiVersion": "v1", +"kind": "Node", +"metadata": { + "annotations": { + "kubeadm.alpha.kubernetes.io/cri-socket": "/var/run/dockershim.sock", + "node.alpha.kubernetes.io/ttl": "0", + "volumes.kubernetes.io/controller-managed-attach-detach": "true" + }, + "creationTimestamp": "2022-05-16T10:52:32Z", + "labels": { + "beta.kubernetes.io/arch": "amd64", + "beta.kubernetes.io/os": "linux", + "kubernetes.io/arch": "amd64", + "kubernetes.io/hostname": "danielg-minikube", + "kubernetes.io/os": "linux", + "minikube.k8s.io/commit": "3e64b11ed75e56e4898ea85f96b2e4af0301f43d", + "minikube.k8s.io/name": "danielg-minikube", + "minikube.k8s.io/updated_at": "2022_05_16T13_52_35_0700", + "minikube.k8s.io/version": "v1.25.1", + "node-role.kubernetes.io/control-plane": "", + "node-role.kubernetes.io/master": "", + "node.kubernetes.io/exclude-from-external-load-balancers": "" + }, + "name": "danielg-minikube", + "resourceVersion": "9432", + "uid": "fc4afcb6-4ca4-4038-ba54-5e16065a614a" +}, +"spec": { + "podCIDR": "10.244.0.0/24", + "podCIDRs": [ + "10.244.0.0/24" + ] +}, +"status": { + "addresses": [ + { + "address": "192.168.49.2", + "type": "InternalIP" + }, + { + "address": "danielg-minikube", + "type": "Hostname" + } + ], + "allocatable": { + "cpu": "4", + "ephemeral-storage": "94850516Ki", + "hugepages-2Mi": "0", + "memory": "10432976Ki", + "pods": "110" + }, + "capacity": { + "cpu": "4", + "ephemeral-storage": "94850516Ki", + "hugepages-2Mi": "0", + "memory": "10432976Ki", + "pods": "110" + }, + "conditions": [ + { + "lastHeartbeatTime": "2022-05-16T14:14:31Z", + "lastTransitionTime": "2022-05-16T10:52:29Z", + "message": "kubelet has sufficient memory available", + "reason": "KubeletHasSufficientMemory", + "status": "False", + "type": "MemoryPressure" + }, + { + "lastHeartbeatTime": "2022-05-16T14:14:31Z", + "lastTransitionTime": "2022-05-16T10:52:29Z", + "message": "kubelet has no disk pressure", + "reason": "KubeletHasNoDiskPressure", + "status": "False", + "type": "DiskPressure" + }, + { + "lastHeartbeatTime": "2022-05-16T14:14:31Z", + "lastTransitionTime": "2022-05-16T10:52:29Z", + "message": "kubelet has sufficient PID available", + "reason": "KubeletHasSufficientPID", + "status": "False", + "type": "PIDPressure" + }, + { + "lastHeartbeatTime": "2022-05-16T14:14:31Z", + "lastTransitionTime": "2022-05-16T10:52:45Z", + "message": "kubelet is posting ready status", + "reason": "KubeletReady", + "status": "True", + "type": "Ready" + } + ], + "daemonEndpoints": { + "kubeletEndpoint": { + "Port": 10250 + } + }, + "images": [ + { + "names": [ + "requarks/wiki@sha256:dd83fff15e77843ff934b25c28c865ac000edf7653e5d11adad1dd51df87439d" + ], + "sizeBytes": 441083858 + }, + { + "names": [ + "mariadb@sha256:821d0411208eaa88f9e1f0daccd1d534f88d19baf724eb9a2777cbedb10b6c66" + ], + "sizeBytes": 400782682 + }, + { + "names": [ + "k8s.gcr.io/etcd@sha256:64b9ea357325d5db9f8a723dcf503b5a449177b17ac87d69481e126bb724c263", + "k8s.gcr.io/etcd:3.5.1-0" + ], + "sizeBytes": 292558922 + }, + { + "names": [ + "kubernetesui/dashboard@sha256:ec27f462cf1946220f5a9ace416a84a57c18f98c777876a8054405d1428cc92e", + "kubernetesui/dashboard:v2.3.1" + ], + "sizeBytes": 220033604 + }, + { + "names": [ + "k8s.gcr.io/kube-apiserver@sha256:f54681a71cce62cbc1b13ebb3dbf1d880f849112789811f98b6aebd2caa2f255", + "k8s.gcr.io/kube-apiserver:v1.23.1" + ], + "sizeBytes": 135162256 + }, + { + "names": [ + "k8s.gcr.io/kube-controller-manager@sha256:a7ed87380108a2d811f0d392a3fe87546c85bc366e0d1e024dfa74eb14468604", + "k8s.gcr.io/kube-controller-manager:v1.23.1" + ], + "sizeBytes": 124971684 + }, + { + "names": [ + "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", + "k8s.gcr.io/kube-proxy:v1.23.1" + ], + "sizeBytes": 112327826 + }, + { + "names": [ + "quay.io/armosec/kubescape@sha256:6196f766be50d94b45d903a911f5ee95ac99bc392a1324c3e063bec41efd98ba", + "quay.io/armosec/kubescape:v2.0.153" + ], + "sizeBytes": 110345054 + }, + { + "names": [ + "nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d" + ], + "sizeBytes": 109129446 + }, + { + "names": [ + "quay.io/armosec/action-trigger@sha256:b93707d10ff86aac8dfa42ad37192d6bcf9aceeb4321b21756e438389c26e07c", + "quay.io/armosec/action-trigger:v0.0.5" + ], + "sizeBytes": 65127067 + }, + { + "names": [ + "quay.io/armosec/images-vulnerabilities-scan@sha256:a5f9ddc04a7fdce6d52ef85a21f0de567d8e04d418c2bc5bf5d72b151c997625", + "quay.io/armosec/images-vulnerabilities-scan:v0.0.7" + ], + "sizeBytes": 61446712 + }, + { + "names": [ + "quay.io/armosec/images-vulnerabilities-scan@sha256:2f879858da89f6542e3223fb18d6d793810cc2ad6e398b66776475e4218b6af5", + "quay.io/armosec/images-vulnerabilities-scan:v0.0.8" + ], + "sizeBytes": 61446528 + }, + { + "names": [ + "quay.io/armosec/cluster-collector@sha256:2c4f733d09f7f4090ace04585230bdfacbbc29a3ade38a2e1233d2c0f730d9b6", + "quay.io/armosec/cluster-collector:v0.0.9" + ], + "sizeBytes": 53699576 + }, + { + "names": [ + "k8s.gcr.io/kube-scheduler@sha256:8be4eb1593cf9ff2d91b44596633b7815a3753696031a1eb4273d1b39427fa8c", + "k8s.gcr.io/kube-scheduler:v1.23.1" + ], + "sizeBytes": 53488305 + }, + { + "names": [ + "k8s.gcr.io/coredns/coredns@sha256:5b6ec0d6de9baaf3e92d0f66cd96a25b9edbce8716f5f15dcd1a616b3abd590e", + "k8s.gcr.io/coredns/coredns:v1.8.6" + ], + "sizeBytes": 46829283 + }, + { + "names": [ + "kubernetesui/metrics-scraper@sha256:36d5b3f60e1a144cc5ada820910535074bdf5cf73fb70d1ff1681537eef4e172", + "kubernetesui/metrics-scraper:v1.0.7" + ], + "sizeBytes": 34446077 + }, + { + "names": [ + "gcr.io/k8s-minikube/storage-provisioner@sha256:18eb69d1418e854ad5a19e399310e52808a8321e4c441c1dddad8977a0d7a944", + "gcr.io/k8s-minikube/storage-provisioner:v5" + ], + "sizeBytes": 31465472 + }, + { + "names": [ + "quay.io/armosec/notification-server@sha256:b6e9b296cd53bd3b2b42c516d8ab43db998acff1124a57aff8d66b3dd7881979", + "quay.io/armosec/notification-server:v0.0.3" + ], + "sizeBytes": 20209940 + }, + { + "names": [ + "quay.io/armosec/kube-host-sensor@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee", + "quay.io/armosec/kube-host-sensor:latest" + ], + "sizeBytes": 11796788 + }, + { + "names": [ + "k8s.gcr.io/pause@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db", + "k8s.gcr.io/pause:3.6" + ], + "sizeBytes": 682696 + } + ], + "nodeInfo": { + "architecture": "amd64", + "bootID": "828cbe73-120b-43cf-aae0-9e2d15b8c873", + "containerRuntimeVersion": "docker://20.10.12", + "kernelVersion": "5.13.0-40-generic", + "kubeProxyVersion": "v1.23.1", + "kubeletVersion": "v1.23.1", + "machineID": "8de776e053e140d6a14c2d2def3d6bb8", + "operatingSystem": "linux", + "osImage": "Ubuntu 20.04.2 LTS", + "systemUUID": "da12dc19-10bf-4033-a440-2d9aa33d6fe3" + } +} +} +` + var l v1.Node + _ = json.Unmarshal([]byte(noTaintNode), &l) + assert.False(t, isMasterNodeTaints(l.Spec.Taints)) + + taintNode := + ` + { + "apiVersion": "v1", + "kind": "Node", + "metadata": { + "annotations": { + "kubeadm.alpha.kubernetes.io/cri-socket": "/var/run/dockershim.sock", + "node.alpha.kubernetes.io/ttl": "0", + "volumes.kubernetes.io/controller-managed-attach-detach": "true" + }, + "creationTimestamp": "2022-05-16T10:52:32Z", + "labels": { + "beta.kubernetes.io/arch": "amd64", + "beta.kubernetes.io/os": "linux", + "kubernetes.io/arch": "amd64", + "kubernetes.io/hostname": "danielg-minikube", + "kubernetes.io/os": "linux", + "minikube.k8s.io/commit": "3e64b11ed75e56e4898ea85f96b2e4af0301f43d", + "minikube.k8s.io/name": "danielg-minikube", + "minikube.k8s.io/updated_at": "2022_05_16T13_52_35_0700", + "minikube.k8s.io/version": "v1.25.1", + "node-role.kubernetes.io/control-plane": "", + "node-role.kubernetes.io/master": "", + "node.kubernetes.io/exclude-from-external-load-balancers": "" + }, + "name": "danielg-minikube", + "resourceVersion": "9871", + "uid": "fc4afcb6-4ca4-4038-ba54-5e16065a614a" + }, + "spec": { + "podCIDR": "10.244.0.0/24", + "podCIDRs": [ + "10.244.0.0/24" + ], + "taints": [ + { + "effect": "NoSchedule", + "key": "key1", + "value": "" + } + ] + }, + "status": { + "addresses": [ + { + "address": "192.168.49.2", + "type": "InternalIP" + }, + { + "address": "danielg-minikube", + "type": "Hostname" + } + ], + "allocatable": { + "cpu": "4", + "ephemeral-storage": "94850516Ki", + "hugepages-2Mi": "0", + "memory": "10432976Ki", + "pods": "110" + }, + "capacity": { + "cpu": "4", + "ephemeral-storage": "94850516Ki", + "hugepages-2Mi": "0", + "memory": "10432976Ki", + "pods": "110" + }, + "conditions": [ + { + "lastHeartbeatTime": "2022-05-16T14:24:45Z", + "lastTransitionTime": "2022-05-16T10:52:29Z", + "message": "kubelet has sufficient memory available", + "reason": "KubeletHasSufficientMemory", + "status": "False", + "type": "MemoryPressure" + }, + { + "lastHeartbeatTime": "2022-05-16T14:24:45Z", + "lastTransitionTime": "2022-05-16T10:52:29Z", + "message": "kubelet has no disk pressure", + "reason": "KubeletHasNoDiskPressure", + "status": "False", + "type": "DiskPressure" + }, + { + "lastHeartbeatTime": "2022-05-16T14:24:45Z", + "lastTransitionTime": "2022-05-16T10:52:29Z", + "message": "kubelet has sufficient PID available", + "reason": "KubeletHasSufficientPID", + "status": "False", + "type": "PIDPressure" + }, + { + "lastHeartbeatTime": "2022-05-16T14:24:45Z", + "lastTransitionTime": "2022-05-16T10:52:45Z", + "message": "kubelet is posting ready status", + "reason": "KubeletReady", + "status": "True", + "type": "Ready" + } + ], + "daemonEndpoints": { + "kubeletEndpoint": { + "Port": 10250 + } + }, + "images": [ + { + "names": [ + "requarks/wiki@sha256:dd83fff15e77843ff934b25c28c865ac000edf7653e5d11adad1dd51df87439d" + ], + "sizeBytes": 441083858 + }, + { + "names": [ + "mariadb@sha256:821d0411208eaa88f9e1f0daccd1d534f88d19baf724eb9a2777cbedb10b6c66" + ], + "sizeBytes": 400782682 + }, + { + "names": [ + "k8s.gcr.io/etcd@sha256:64b9ea357325d5db9f8a723dcf503b5a449177b17ac87d69481e126bb724c263", + "k8s.gcr.io/etcd:3.5.1-0" + ], + "sizeBytes": 292558922 + }, + { + "names": [ + "kubernetesui/dashboard@sha256:ec27f462cf1946220f5a9ace416a84a57c18f98c777876a8054405d1428cc92e", + "kubernetesui/dashboard:v2.3.1" + ], + "sizeBytes": 220033604 + }, + { + "names": [ + "k8s.gcr.io/kube-apiserver@sha256:f54681a71cce62cbc1b13ebb3dbf1d880f849112789811f98b6aebd2caa2f255", + "k8s.gcr.io/kube-apiserver:v1.23.1" + ], + "sizeBytes": 135162256 + }, + { + "names": [ + "k8s.gcr.io/kube-controller-manager@sha256:a7ed87380108a2d811f0d392a3fe87546c85bc366e0d1e024dfa74eb14468604", + "k8s.gcr.io/kube-controller-manager:v1.23.1" + ], + "sizeBytes": 124971684 + }, + { + "names": [ + "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", + "k8s.gcr.io/kube-proxy:v1.23.1" + ], + "sizeBytes": 112327826 + }, + { + "names": [ + "quay.io/armosec/kubescape@sha256:6196f766be50d94b45d903a911f5ee95ac99bc392a1324c3e063bec41efd98ba", + "quay.io/armosec/kubescape:v2.0.153" + ], + "sizeBytes": 110345054 + }, + { + "names": [ + "nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d" + ], + "sizeBytes": 109129446 + }, + { + "names": [ + "quay.io/armosec/action-trigger@sha256:b93707d10ff86aac8dfa42ad37192d6bcf9aceeb4321b21756e438389c26e07c", + "quay.io/armosec/action-trigger:v0.0.5" + ], + "sizeBytes": 65127067 + }, + { + "names": [ + "quay.io/armosec/images-vulnerabilities-scan@sha256:a5f9ddc04a7fdce6d52ef85a21f0de567d8e04d418c2bc5bf5d72b151c997625", + "quay.io/armosec/images-vulnerabilities-scan:v0.0.7" + ], + "sizeBytes": 61446712 + }, + { + "names": [ + "quay.io/armosec/images-vulnerabilities-scan@sha256:2f879858da89f6542e3223fb18d6d793810cc2ad6e398b66776475e4218b6af5", + "quay.io/armosec/images-vulnerabilities-scan:v0.0.8" + ], + "sizeBytes": 61446528 + }, + { + "names": [ + "quay.io/armosec/cluster-collector@sha256:2c4f733d09f7f4090ace04585230bdfacbbc29a3ade38a2e1233d2c0f730d9b6", + "quay.io/armosec/cluster-collector:v0.0.9" + ], + "sizeBytes": 53699576 + }, + { + "names": [ + "k8s.gcr.io/kube-scheduler@sha256:8be4eb1593cf9ff2d91b44596633b7815a3753696031a1eb4273d1b39427fa8c", + "k8s.gcr.io/kube-scheduler:v1.23.1" + ], + "sizeBytes": 53488305 + }, + { + "names": [ + "k8s.gcr.io/coredns/coredns@sha256:5b6ec0d6de9baaf3e92d0f66cd96a25b9edbce8716f5f15dcd1a616b3abd590e", + "k8s.gcr.io/coredns/coredns:v1.8.6" + ], + "sizeBytes": 46829283 + }, + { + "names": [ + "kubernetesui/metrics-scraper@sha256:36d5b3f60e1a144cc5ada820910535074bdf5cf73fb70d1ff1681537eef4e172", + "kubernetesui/metrics-scraper:v1.0.7" + ], + "sizeBytes": 34446077 + }, + { + "names": [ + "gcr.io/k8s-minikube/storage-provisioner@sha256:18eb69d1418e854ad5a19e399310e52808a8321e4c441c1dddad8977a0d7a944", + "gcr.io/k8s-minikube/storage-provisioner:v5" + ], + "sizeBytes": 31465472 + }, + { + "names": [ + "quay.io/armosec/notification-server@sha256:b6e9b296cd53bd3b2b42c516d8ab43db998acff1124a57aff8d66b3dd7881979", + "quay.io/armosec/notification-server:v0.0.3" + ], + "sizeBytes": 20209940 + }, + { + "names": [ + "quay.io/armosec/kube-host-sensor@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee", + "quay.io/armosec/kube-host-sensor:latest" + ], + "sizeBytes": 11796788 + }, + { + "names": [ + "k8s.gcr.io/pause@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db", + "k8s.gcr.io/pause:3.6" + ], + "sizeBytes": 682696 + } + ], + "nodeInfo": { + "architecture": "amd64", + "bootID": "828cbe73-120b-43cf-aae0-9e2d15b8c873", + "containerRuntimeVersion": "docker://20.10.12", + "kernelVersion": "5.13.0-40-generic", + "kubeProxyVersion": "v1.23.1", + "kubeletVersion": "v1.23.1", + "machineID": "8de776e053e140d6a14c2d2def3d6bb8", + "operatingSystem": "linux", + "osImage": "Ubuntu 20.04.2 LTS", + "systemUUID": "da12dc19-10bf-4033-a440-2d9aa33d6fe3" + } + } +} +` + _ = json.Unmarshal([]byte(taintNode), &l) + assert.True(t, isMasterNodeTaints(l.Spec.Taints)) +} diff --git a/core/pkg/resourcehandler/k8sresourcesutils.go b/core/pkg/resourcehandler/k8sresourcesutils.go index baaa187e..91839727 100644 --- a/core/pkg/resourcehandler/k8sresourcesutils.go +++ b/core/pkg/resourcehandler/k8sresourcesutils.go @@ -4,7 +4,6 @@ import ( "strings" "github.com/armosec/kubescape/v2/core/cautils" - "github.com/armosec/kubescape/v2/core/pkg/hostsensorutils" "github.com/armosec/opa-utils/reporthandling" "k8s.io/utils/strings/slices" @@ -12,12 +11,43 @@ import ( ) var ( - ClusterDescribe = "ClusterDescribe" + ClusterDescribe = "ClusterDescribe" + KubeletConfiguration = "KubeletConfiguration" + OsReleaseFile = "OsReleaseFile" + KernelVersion = "KernelVersion" + LinuxSecurityHardeningStatus = "LinuxSecurityHardeningStatus" + OpenPortsList = "OpenPortsList" + LinuxKernelVariables = "LinuxKernelVariables" + KubeletCommandLine = "KubeletCommandLine" + ImageVulnerabilities = "ImageVulnerabilities" + MapResourceToApiGroup = map[string]string{ + KubeletConfiguration: "hostdata.kubescape.cloud/v1beta0", + OsReleaseFile: "hostdata.kubescape.cloud/v1beta0", + KubeletCommandLine: "hostdata.kubescape.cloud/v1beta0", + KernelVersion: "hostdata.kubescape.cloud/v1beta0", + LinuxSecurityHardeningStatus: "hostdata.kubescape.cloud/v1beta0", + OpenPortsList: "hostdata.kubescape.cloud/v1beta0", + LinuxKernelVariables: "hostdata.kubescape.cloud/v1beta0", + } + MapResourceToApiGroupVuln = map[string][]string{ + ImageVulnerabilities: {"armo.vuln.images/v1", "image.vulnscan.com/v1"}} MapResourceToApiGroupCloud = map[string][]string{ ClusterDescribe: {"container.googleapis.com/v1", "eks.amazonaws.com/v1", "management.azure.com/v1"}} ) +func isEmptyImgVulns(armoResourcesMap cautils.ArmoResources) bool { + imgVulnResources := cautils.MapImageVulnResources(&armoResourcesMap) + for _, resource := range imgVulnResources { + if val, ok := armoResourcesMap[resource]; ok { + if len(val) > 0 { + return false + } + } + } + return true +} + func setK8sResourceMap(frameworks []reporthandling.Framework) *cautils.K8SResources { k8sResources := make(cautils.K8SResources) complexMap := setComplexK8sResourceMap(frameworks) @@ -80,10 +110,16 @@ func setComplexArmoResourceMap(frameworks []reporthandling.Framework, resourceTo } func mapArmoResourceToApiGroup(resource string) []string { - if val, ok := hostsensorutils.MapResourceToApiGroup[resource]; ok { + if val, ok := MapResourceToApiGroup[resource]; ok { return []string{val} } - return MapResourceToApiGroupCloud[resource] + if val, ok := MapResourceToApiGroupCloud[resource]; ok { + return val + } + if val, ok := MapResourceToApiGroupVuln[resource]; ok { + return val + } + return []string{} } func insertControls(resource string, resourceToControl map[string][]string, control reporthandling.Control) { diff --git a/core/pkg/resourcehandler/k8sresourcesutils_test.go b/core/pkg/resourcehandler/k8sresourcesutils_test.go index 79ea71a3..367b787c 100644 --- a/core/pkg/resourcehandler/k8sresourcesutils_test.go +++ b/core/pkg/resourcehandler/k8sresourcesutils_test.go @@ -2,7 +2,9 @@ package resourcehandler import ( "github.com/armosec/k8s-interface/k8sinterface" + "github.com/armosec/kubescape/v2/core/cautils" "github.com/armosec/opa-utils/reporthandling" + "github.com/stretchr/testify/assert" "testing" ) @@ -24,6 +26,18 @@ func TestSetResourceMap(t *testing.T) { } } +func TestSsEmptyImgVulns(t *testing.T) { + armoResourcesMap := make(cautils.ArmoResources, 0) + armoResourcesMap["container.googleapis.com/v1"] = []string{"fsdfds"} + assert.Equal(t, true, isEmptyImgVulns(armoResourcesMap)) + + armoResourcesMap["armo.vuln.images/v1/ImageVulnerabilities"] = []string{"dada"} + assert.Equal(t, false, isEmptyImgVulns(armoResourcesMap)) + + armoResourcesMap["armo.vuln.images/v1/ImageVulnerabilities"] = []string{} + armoResourcesMap["bla"] = []string{"blu"} + assert.Equal(t, true, isEmptyImgVulns(armoResourcesMap)) +} func TestInsertK8sResources(t *testing.T) { // insertK8sResources diff --git a/go.mod b/go.mod index fbfa6a12..2707d3ad 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/armosec/armoapi-go v0.0.73 github.com/armosec/go-git-url v0.0.4 - github.com/armosec/k8s-interface v0.0.74 + github.com/armosec/k8s-interface v0.0.75 github.com/armosec/opa-utils v0.0.137 github.com/armosec/rbac-utils v0.0.14 github.com/armosec/utils-go v0.0.5 diff --git a/go.sum b/go.sum index a5869a36..260f1aa1 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,8 @@ github.com/armosec/go-git-url v0.0.4/go.mod h1:PJqdEyJyFxTQvawBcyOM0Ies6+uezire5 github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= github.com/armosec/k8s-interface v0.0.70/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= -github.com/armosec/k8s-interface v0.0.74 h1:qZ1bkQv9JLfpwzxNcTytpYQpHKTKZ5rIhMze8SU1cPI= -github.com/armosec/k8s-interface v0.0.74/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= +github.com/armosec/k8s-interface v0.0.75 h1:pfheXWGcE6vUlo4TOkwXQ8iGo8Dw/UCXefD3Bx4l0Qs= +github.com/armosec/k8s-interface v0.0.75/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= github.com/armosec/opa-utils v0.0.137 h1:KAkxWYnnTef8ofixJ198Zs4Xs7MOh32+yMUyFY7I8DA= github.com/armosec/opa-utils v0.0.137/go.mod h1:mCFQzz4E227f7V2jQVQ9XCivkNNK3UWCTaZ0HE5rBWk= diff --git a/httphandler/go.mod b/httphandler/go.mod index 3ca38ada..3e6240ff 100644 --- a/httphandler/go.mod +++ b/httphandler/go.mod @@ -30,7 +30,7 @@ require ( github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/armosec/armoapi-go v0.0.73 // indirect github.com/armosec/go-git-url v0.0.4 // indirect - github.com/armosec/k8s-interface v0.0.70 // indirect + github.com/armosec/k8s-interface v0.0.75 // indirect github.com/armosec/rbac-utils v0.0.14 // indirect github.com/armosec/utils-k8s-go v0.0.6 // indirect github.com/aws/aws-sdk-go v1.41.11 // indirect diff --git a/httphandler/go.sum b/httphandler/go.sum index 2d88666a..9ce5fc4f 100644 --- a/httphandler/go.sum +++ b/httphandler/go.sum @@ -120,8 +120,9 @@ github.com/armosec/go-git-url v0.0.4 h1:emG9Yfl53rHpuX41fXLD92ehzhRoNSSnGT6Pr7og github.com/armosec/go-git-url v0.0.4/go.mod h1:PJqdEyJyFxTQvawBcyOM0Ies6+uezire5gpwfr1XX5M= github.com/armosec/k8s-interface v0.0.8/go.mod h1:xxS+V5QT3gVQTwZyAMMDrYLWGrfKOpiJ7Jfhfa0w9sM= github.com/armosec/k8s-interface v0.0.37/go.mod h1:vHxGWqD/uh6+GQb9Sqv7OGMs+Rvc2dsFVc0XtgRh1ZU= -github.com/armosec/k8s-interface v0.0.70 h1:NU3UIaNl7H3hsRecwggiaQbZXTwXtOKg3GOBjq6/XJw= github.com/armosec/k8s-interface v0.0.70/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= +github.com/armosec/k8s-interface v0.0.75 h1:pfheXWGcE6vUlo4TOkwXQ8iGo8Dw/UCXefD3Bx4l0Qs= +github.com/armosec/k8s-interface v0.0.75/go.mod h1:8NX4xWXh8mwW7QyZdZea1czNdM2azCK9BbUNmiZYXW0= github.com/armosec/opa-utils v0.0.64/go.mod h1:6tQP8UDq2EvEfSqh8vrUdr/9QVSCG4sJfju1SXQOn4c= github.com/armosec/opa-utils v0.0.137 h1:KAkxWYnnTef8ofixJ198Zs4Xs7MOh32+yMUyFY7I8DA= github.com/armosec/opa-utils v0.0.137/go.mod h1:mCFQzz4E227f7V2jQVQ9XCivkNNK3UWCTaZ0HE5rBWk=