Files
kubescape/policyhandler/k8sresources.go
2021-10-14 17:12:10 +03:00

108 lines
3.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package policyhandler
import (
"fmt"
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/armoapi-go/armotypes"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
k8slabels "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
)
const SelectAllResources = "*"
func (policyHandler *PolicyHandler) getK8sResources(frameworks []reporthandling.Framework, designator *armotypes.PortalDesignator, excludedNamespaces string) (*cautils.K8SResources, error) {
// get k8s resources
cautils.ProgressTextDisplay("Accessing Kubernetes objects")
// build resources map
k8sResourcesMap := setResourceMap(frameworks)
// get namespace and labels from designator (ignore cluster labels)
_, namespace, labels := armotypes.DigestPortalDesignator(designator)
// pull k8s recourses
if err := policyHandler.pullResources(k8sResourcesMap, namespace, labels, excludedNamespaces); err != nil {
return k8sResourcesMap, err
}
cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects, lets start!!!")
return k8sResourcesMap, nil
}
func (policyHandler *PolicyHandler) pullResources(k8sResources *cautils.K8SResources, namespace string, labels map[string]string, excludedNamespaces string) error {
var errs error
for groupResource := range *k8sResources {
apiGroup, apiVersion, resource := k8sinterface.StringToResourceGroup(groupResource)
gvr := schema.GroupVersionResource{Group: apiGroup, Version: apiVersion, Resource: resource}
result, err := policyHandler.pullSingleResource(&gvr, namespace, labels, excludedNamespaces)
if err != nil {
// handle error
if errs == nil {
errs = err
} else {
errs = fmt.Errorf("%s\n%s", errs, err.Error())
}
} else {
// store result as []map[string]interface{}
(*k8sResources)[groupResource] = k8sinterface.ConvertUnstructuredSliceToMap(k8sinterface.FilterOutOwneredResources(result))
}
}
return errs
}
func (policyHandler *PolicyHandler) pullSingleResource(resource *schema.GroupVersionResource, namespace string, labels map[string]string, excludedNamespaces string) ([]unstructured.Unstructured, error) {
// set labels
listOptions := metav1.ListOptions{}
if excludedNamespaces != "" {
setFieldSelector(&listOptions, resource, excludedNamespaces)
}
if len(labels) > 0 {
set := k8slabels.Set(labels)
listOptions.LabelSelector = set.AsSelector().String()
}
// set dynamic object
var clientResource dynamic.ResourceInterface
if namespace != "" && k8sinterface.IsNamespaceScope(resource.Group, resource.Resource) {
clientResource = policyHandler.k8s.DynamicClient.Resource(*resource).Namespace(namespace)
} else {
clientResource = policyHandler.k8s.DynamicClient.Resource(*resource)
}
// list resources
result, err := clientResource.List(policyHandler.k8s.Context, listOptions)
if err != nil {
return nil, fmt.Errorf("failed to get resource: %v, namespace: %s, labelSelector: %v, reason: %s", resource, namespace, listOptions.LabelSelector, err.Error())
}
return result.Items, nil
}
func setFieldSelector(listOptions *metav1.ListOptions, resource *schema.GroupVersionResource, excludedNamespaces string) {
fieldSelector := "metadata."
if resource.Resource == "namespaces" {
fieldSelector += "name"
} else if k8sinterface.IsNamespaceScope(resource.Group, resource.Resource) {
fieldSelector += "namespace"
} else {
return
}
excludedNamespacesSlice := strings.Split(excludedNamespaces, ",")
for _, excludedNamespace := range excludedNamespacesSlice {
listOptions.FieldSelector += fmt.Sprintf("%s!=%s,", fieldSelector, excludedNamespace)
}
}