integrate host sensor into k8s IMetadata resource map

This commit is contained in:
Bezalel Brandwine
2021-12-05 15:08:05 +02:00
parent cbb2a3e46f
commit 9080603bce
8 changed files with 95 additions and 33 deletions
+22 -2
View File
@@ -42,7 +42,6 @@ func initHostSensor(scanInfo *cautils.ScanInfo, k8s *k8sinterface.KubernetesApi)
glog.Errorf("failed to create host sensor: %v", err)
return &hostsensorutils.HostSensorHandlerMock{}
}
scanInfo.ExcludedNamespaces = fmt.Sprintf("%s,%s", scanInfo.ExcludedNamespaces, hostSensorHandler.DaemonSet.Namespace)
return hostSensorHandler
} else {
fmt.Printf("Skipping nodes scanning\n")
@@ -55,6 +54,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
var hostSensorHandler hostsensorutils.IHostSensor
var tenantConfig cautils.ITenantConfig
hostSensorHandler = &hostsensorutils.HostSensorHandlerMock{}
// scanning environment
scanningTarget := scanInfo.GetScanningEnvironment()
switch scanningTarget {
@@ -108,13 +108,33 @@ func ScanCliSetup(scanInfo *cautils.ScanInfo) error {
interfaces.report.SetClusterName(interfaces.tenantConfig.GetClusterName())
interfaces.report.SetCustomerGUID(interfaces.tenantConfig.GetCustomerGUID())
if err := interfaces.hostSensorHandler.Init(); err != nil {
errMsg := "failed to init host sensor"
if scanInfo.VerboseMode {
errMsg = fmt.Sprintf("%s: %v", errMsg, err)
}
cautils.ErrorDisplay(errMsg)
} else if len(scanInfo.IncludeNamespaces) == 0 && interfaces.hostSensorHandler.GetNamespace() != "" {
scanInfo.ExcludedNamespaces = fmt.Sprintf("%s,%s", scanInfo.ExcludedNamespaces, interfaces.hostSensorHandler)
}
defer func() {
if err := interfaces.hostSensorHandler.TearDown(); err != nil {
errMsg := "failed to tear down host sensor"
if scanInfo.VerboseMode {
errMsg = fmt.Sprintf("%s: %v", errMsg, err)
}
cautils.ErrorDisplay(errMsg)
}
}()
// set policy getter only after setting the customerGUID
setPolicyGetter(scanInfo, interfaces.tenantConfig.GetCustomerGUID())
// cli handler setup
go func() {
// policy handler setup
policyHandler := policyhandler.NewPolicyHandler(&processNotification, interfaces.resourceHandler)
policyHandler := policyhandler.NewPolicyHandler(&processNotification, interfaces.resourceHandler, interfaces.hostSensorHandler)
if err := Scan(policyHandler, scanInfo); err != nil {
fmt.Println(err)
+3 -3
View File
@@ -8,7 +8,7 @@ import (
)
type HostSensorDataEnvelope struct {
schema.GroupVersionKind
schema.GroupVersionResource
NodeName string `json:"nodeName"`
Data json.RawMessage `json:"data"`
}
@@ -22,7 +22,7 @@ func (hsde *HostSensorDataEnvelope) SetName(val string) {
}
func (hsde *HostSensorDataEnvelope) SetKind(val string) {
hsde.Kind = val
hsde.Resource = val
}
@@ -43,7 +43,7 @@ func (hsde *HostSensorDataEnvelope) GetName() string {
}
func (hsde *HostSensorDataEnvelope) GetKind() string {
return hsde.Kind
return hsde.Resource
}
func (hsde *HostSensorDataEnvelope) GetApiVersion() string {
+24 -19
View File
@@ -8,6 +8,7 @@ import (
"time"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/kubescape/cautils"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -18,22 +19,15 @@ import (
)
type HostSensorHandler struct {
HostSensorNamespace string
HostSensorPort int32
HostSensorDaemonSetName string
HostSensorPodNames map[string]string //map from pod names to node names
IsReady <-chan bool //readonly chan
k8sObj *k8sinterface.KubernetesApi
DaemonSet *appsv1.DaemonSet
podListLock sync.RWMutex
HostSensorPort int32
HostSensorPodNames map[string]string //map from pod names to node names
IsReady <-chan bool //readonly chan
k8sObj *k8sinterface.KubernetesApi
DaemonSet *appsv1.DaemonSet
podListLock sync.RWMutex
}
func NewHostSensorHandler(k8sObj *k8sinterface.KubernetesApi) (*HostSensorHandler, error) {
// deploy the YAML
// store namespace + port
// store pod names
// make sure all pods are running, after X seconds treat has running anyway, and log an error on the pods not running yet
// return the object
if k8sObj == nil {
return nil, fmt.Errorf("nil k8s interface received")
@@ -54,6 +48,13 @@ func NewHostSensorHandler(k8sObj *k8sinterface.KubernetesApi) (*HostSensorHandle
}
func (hsh *HostSensorHandler) Init() error {
// deploy the YAML
// store namespace + port
// store pod names
// make sure all pods are running, after X seconds treat has running anyway, and log an error on the pods not running yet
cautils.ProgressTextDisplay("Installing host sensor")
cautils.StartSpinner()
defer cautils.StopSpinner()
if err := hsh.applyYAML(); err != nil {
return fmt.Errorf("in HostSensorHandler init failed to apply YAML: %v", err)
}
@@ -77,13 +78,14 @@ func (hsh *HostSensorHandler) applyYAML() error {
if err := yaml.Unmarshal(singleYAMLBytes, namespaceAC); err != nil {
return fmt.Errorf("failed to Unmarshal YAML of namespace: %v", err)
}
namespaceName := ""
if ns, err := hsh.k8sObj.KubernetesClient.CoreV1().Namespaces().Apply(hsh.k8sObj.Context, namespaceAC, metav1.ApplyOptions{
FieldManager: "kubescape",
}); err != nil {
return fmt.Errorf("failed to apply YAML of namespace: %v", err)
} else {
hsh.HostSensorNamespace = ns.Name
namespaceName = ns.Name
}
// apply deamonset
deamonAC := &appsapplyv1.DaemonSetApplyConfiguration{}
@@ -96,13 +98,12 @@ func (hsh *HostSensorHandler) applyYAML() error {
if err := yaml.Unmarshal(singleYAMLBytes, deamonAC); err != nil {
return fmt.Errorf("failed to Unmarshal YAML of deamonset: %v", err)
}
deamonAC.Namespace = &hsh.HostSensorNamespace
if ds, err := hsh.k8sObj.KubernetesClient.AppsV1().DaemonSets(hsh.HostSensorNamespace).Apply(hsh.k8sObj.Context, deamonAC, metav1.ApplyOptions{
deamonAC.Namespace = &namespaceName
if ds, err := hsh.k8sObj.KubernetesClient.AppsV1().DaemonSets(namespaceName).Apply(hsh.k8sObj.Context, deamonAC, metav1.ApplyOptions{
FieldManager: "kubescape",
}); err != nil {
return fmt.Errorf("failed to apply YAML of deamonset: %v", err)
} else {
hsh.HostSensorDaemonSetName = ds.Name
hsh.HostSensorPort = ds.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort
hsh.DaemonSet = ds
}
@@ -171,10 +172,10 @@ func (hsh *HostSensorHandler) updatePodInListAtomic(eventType watch.EventType, p
func (hsh *HostSensorHandler) TearDown() error {
// remove the namespace
gracePeriod := int64(15)
if err := hsh.k8sObj.KubernetesClient.AppsV1().DaemonSets(hsh.HostSensorNamespace).Delete(hsh.k8sObj.Context, hsh.HostSensorDaemonSetName, metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod}); err != nil {
if err := hsh.k8sObj.KubernetesClient.AppsV1().DaemonSets(hsh.GetNamespace()).Delete(hsh.k8sObj.Context, hsh.DaemonSet.Name, metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod}); err != nil {
return fmt.Errorf("failed to delete host-sensor daemonset: %v", err)
}
if err := hsh.k8sObj.KubernetesClient.CoreV1().Namespaces().Delete(hsh.k8sObj.Context, hsh.HostSensorNamespace,
if err := hsh.k8sObj.KubernetesClient.CoreV1().Namespaces().Delete(hsh.k8sObj.Context, hsh.GetNamespace(),
metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod}); err != nil {
return fmt.Errorf("failed to delete host-sensor namespace: %v", err)
}
@@ -182,3 +183,7 @@ func (hsh *HostSensorHandler) TearDown() error {
return nil
}
func (hsh *HostSensorHandler) GetNamespace() string {
return hsh.DaemonSet.Namespace
}
+10 -3
View File
@@ -5,7 +5,8 @@ import (
"fmt"
"sync"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/armosec/kubescape/cautils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)
@@ -93,20 +94,26 @@ func (hsh *HostSensorHandler) GetKubeletConfigurations() ([]HostSensorDataEnvelo
continue
}
res[resIdx].Data = jsonBytes
kindDet := schema.GroupVersionKind{}
kindDet := metav1.TypeMeta{}
if err = json.Unmarshal(jsonBytes, &kindDet); err != nil {
fmt.Printf("In GetKubeletConfigurations failed to Unmarshal GroupVersionKind: %v;\n%v", err, jsonBytes)
continue
}
res[resIdx].GroupVersionKind = kindDet
res[resIdx].GroupVersionResource.Resource = kindDet.Kind
res[resIdx].GroupVersionResource.Group = kindDet.GroupVersionKind().Group
res[resIdx].GroupVersionResource.Version = kindDet.GroupVersionKind().Version
}
return res, err
}
func (hsh *HostSensorHandler) CollectResources() ([]HostSensorDataEnvelope, error) {
cautils.ProgressTextDisplay("Accessing host sensor")
cautils.StartSpinner()
defer cautils.StopSpinner()
kcData, err := hsh.GetKubeletConfigurations()
if err != nil {
return kcData, err
}
cautils.SuccessTextDisplay("Read host information from host sensor")
return kcData, nil
}
+1
View File
@@ -4,4 +4,5 @@ type IHostSensor interface {
Init() error
TearDown() error
CollectResources() ([]HostSensorDataEnvelope, error)
GetNamespace() string
}
+4
View File
@@ -14,3 +14,7 @@ func (hshm *HostSensorHandlerMock) TearDown() error {
func (hshm *HostSensorHandlerMock) CollectResources() ([]HostSensorDataEnvelope, error) {
return []HostSensorDataEnvelope{}, nil
}
func (hshm *HostSensorHandlerMock) GetNamespace() string {
return ""
}
+30 -5
View File
@@ -3,24 +3,29 @@ package policyhandler
import (
"fmt"
"github.com/armosec/k8s-interface/k8sinterface"
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/hostsensorutils"
"github.com/armosec/kubescape/resourcehandler"
"github.com/armosec/opa-utils/reporthandling"
)
// PolicyHandler -
type PolicyHandler struct {
resourceHandler resourcehandler.IResourceHandler
resourceHandler resourcehandler.IResourceHandler
hostSensorHandler hostsensorutils.IHostSensor
// we are listening on this chan in opaprocessor/processorhandler.go/ProcessRulesListenner func
processPolicy *chan *cautils.OPASessionObj
getters *cautils.Getters
}
// CreatePolicyHandler Create ws-handler obj
func NewPolicyHandler(processPolicy *chan *cautils.OPASessionObj, resourceHandler resourcehandler.IResourceHandler) *PolicyHandler {
func NewPolicyHandler(processPolicy *chan *cautils.OPASessionObj, resourceHandler resourcehandler.IResourceHandler, hostSensorHandler hostsensorutils.IHostSensor) *PolicyHandler {
return &PolicyHandler{
resourceHandler: resourceHandler,
processPolicy: processPolicy,
resourceHandler: resourceHandler,
processPolicy: processPolicy,
hostSensorHandler: hostSensorHandler,
}
}
@@ -52,5 +57,25 @@ func (policyHandler *PolicyHandler) HandleNotificationRequest(notification *repo
func (policyHandler *PolicyHandler) getResources(notification *reporthandling.PolicyNotification, opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) (*cautils.K8SResources, error) {
opaSessionObj.PostureReport.ClusterAPIServerInfo = policyHandler.resourceHandler.GetClusterAPIServerInfo()
return policyHandler.resourceHandler.GetResources(opaSessionObj.Frameworks, &notification.Designators)
resourcesMap, err := policyHandler.resourceHandler.GetResources(opaSessionObj.Frameworks, &notification.Designators)
if err != nil {
return resourcesMap, err
}
hostResources, err := policyHandler.hostSensorHandler.CollectResources()
if err != nil {
return resourcesMap, err
}
for rscIdx := range hostResources {
groupResources := k8sinterface.ResourceGroupToString(hostResources[rscIdx].Group, hostResources[rscIdx].GetApiVersion(), hostResources[rscIdx].GetKind())
for _, groupResource := range groupResources {
grpReasorceList, ok := (*resourcesMap)[groupResource]
if !ok {
grpReasorceList = make([]workloadinterface.IMetadata, 0)
}
grpReasorceList = append(grpReasorceList, &hostResources[rscIdx])
(*resourcesMap)[groupResource] = grpReasorceList
}
}
cautils.SuccessTextDisplay("Lets start!!!")
return resourcesMap, nil
}
+1 -1
View File
@@ -47,7 +47,7 @@ func (k8sHandler *K8sResourceHandler) GetResources(frameworks []reporthandling.F
return k8sResourcesMap, err
}
cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects, lets start!!!")
cautils.SuccessTextDisplay("Accessed successfully to Kubernetes objects")
return k8sResourcesMap, nil
}