From 2136fdd6ffae1b1a442d8843c4542044a6f6a840 Mon Sep 17 00:00:00 2001 From: Aryan-sharma11 Date: Thu, 30 Mar 2023 18:01:48 +0530 Subject: [PATCH] Added security posture and visibilty column in karmor probe Signed-off-by: Aryan-sharma11 --- probe/probe.go | 114 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 23 deletions(-) diff --git a/probe/probe.go b/probe/probe.go index c2d15a58..ece8c411 100644 --- a/probe/probe.go +++ b/probe/probe.go @@ -49,6 +49,12 @@ type Options struct { Full bool } +// To store container default posture and visibility data +type PostureAndVisibility struct { + DefaultPosture string + Visibility string +} + // K8sInstaller for karmor install func probeDaemonInstaller(c *k8s.Client, o Options, krnhdr bool) error { daemonset := deployment.GenerateDaemonSet(o.Namespace, krnhdr) @@ -90,11 +96,11 @@ func PrintProbeResult(c *k8s.Client, o Options) error { if isKubeArmorRunning(c, o) { getKubeArmorDeployments(c, o) getKubeArmorContainers(c, o) - err := probeRunningKubeArmorNodes(c, o) + postureData, err := probeRunningKubeArmorNodes(c, o) if err != nil { log.Println("error occured when probing kubearmor nodes", err) } - err = getAnnotatedPods(c) + err = getAnnotatedPods(c, postureData) if err != nil { log.Println("error occured when getting annotated pods", err) } @@ -436,15 +442,15 @@ func getKubeArmorContainers(c *k8s.Client, o Options) { } -func probeRunningKubeArmorNodes(c *k8s.Client, o Options) error { +func probeRunningKubeArmorNodes(c *k8s.Client, o Options) (map[string]string, error) { // // KubeArmor Nodes + postureData := make(map[string]string) nodes, err := c.K8sClientset.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) if err != nil { log.Println("error getting nodes", err) - return err + return nil, err } - if len(nodes.Items) > 0 { for i, item := range nodes.Items { @@ -452,18 +458,18 @@ func probeRunningKubeArmorNodes(c *k8s.Client, o Options) error { if err != nil { color.Red(" Error while printing") } - err = readDataFromKubeArmor(c, o, item.Name) + err = readDataFromKubeArmor(c, o, item.Name, postureData) if err != nil { - return err + return nil, err } } } else { fmt.Println("No kubernetes environment found") } - return nil + return postureData, nil } -func readDataFromKubeArmor(c *k8s.Client, o Options, nodeName string) error { +func readDataFromKubeArmor(c *k8s.Client, o Options, nodeName string, postureData map[string]string) error { srcPath := "/tmp/karmorProbeData.cfg" pods, err := c.K8sClientset.CoreV1().Pods(o.Namespace).List(context.Background(), metav1.ListOptions{ LabelSelector: "kubearmor-app=kubearmor", @@ -508,23 +514,38 @@ func readDataFromKubeArmor(c *k8s.Client, o Options, nodeName string) error { log.Println("an error occured when reading file", err) return err } - err = printKubeArmorProbeOutput(buf) + + kd, err := parseJsonData(buf) + if err != nil { + return err + } + + err = printKubeArmorProbeOutput(kd) if err != nil { log.Println("an error occured when printing output", err) return err } + + postureData["filePosture"] = kd.ContainerDefaultPosture.FileAction + postureData["capabilitiesPosture"] = kd.ContainerDefaultPosture.CapabilitiesAction + postureData["networkPosture"] = kd.ContainerDefaultPosture.NetworkAction + return nil } +func parseJsonData(buf []byte) (*KubeArmorProbeData, error) { + // Parsing JSON encoded data -func printKubeArmorProbeOutput(buf []byte) error { var kd *KubeArmorProbeData var json = jsoniter.ConfigCompatibleWithStandardLibrary - var data [][]string err := json.Unmarshal(buf, &kd) if err != nil { log.Println("an error occured when parsing file", err) - return err + return kd, err } + return kd, err +} +func printKubeArmorProbeOutput(kd *KubeArmorProbeData) error { + var data [][]string data = append(data, []string{" ", "OS Image:", green(kd.OSImage)}) data = append(data, []string{" ", "Kernel Version:", green(kd.KernelVersion)}) data = append(data, []string{" ", "Kubelet Version:", green(kd.KubeletVersion)}) @@ -532,7 +553,7 @@ func printKubeArmorProbeOutput(buf []byte) error { data = append(data, []string{" ", "Active LSM:", green(kd.ActiveLSM)}) data = append(data, []string{" ", "Host Security:", green(strconv.FormatBool(kd.HostSecurity))}) data = append(data, []string{" ", "Container Security:", green(strconv.FormatBool(kd.ContainerSecurity))}) - data = append(data, []string{" ", "Container Default Posture:", green(kd.ContainerDefaultPosture.FileAction) + itwhite("(File)"), green(kd.ContainerDefaultPosture.FileAction) + itwhite("(Capabilities)"), green(kd.ContainerDefaultPosture.NetworkAction) + itwhite("(Network)")}) + data = append(data, []string{" ", "Container Default Posture:", green(kd.ContainerDefaultPosture.FileAction) + itwhite("(File)"), green(kd.ContainerDefaultPosture.CapabilitiesAction) + itwhite("(Capabilities)"), green(kd.ContainerDefaultPosture.NetworkAction) + itwhite("(Network)")}) data = append(data, []string{" ", "Host Default Posture:", green(kd.HostDefaultPosture.FileAction) + itwhite("(File)"), green(kd.HostDefaultPosture.CapabilitiesAction) + itwhite("(Capabilities)"), green(kd.HostDefaultPosture.NetworkAction) + itwhite("(Network)")}) renderOutputInTableWithNoBorders(data) return nil @@ -565,7 +586,13 @@ func probeSystemdMode() error { if err != nil { color.Red(" Error") } - err = printKubeArmorProbeOutput(buf) + + kd, err := parseJsonData(buf) + if err != nil { + return err + } + + err = printKubeArmorProbeOutput(kd) if err != nil { log.Println("an error occured when printing output", err) return err @@ -582,7 +609,40 @@ func getAnnotatedPodLabels(m map[string]string) mapset.Set[string] { return b } -func getAnnotatedPods(c *k8s.Client) error { +func getNsSecurityPostureAndVisibility(c *k8s.Client, postureData map[string]string) (map[string]*PostureAndVisibility, error) { + // Namespace/host security posture and visibility setting + + mp := make(map[string]*PostureAndVisibility) + namespaces, err := c.K8sClientset.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{}) + + if err != nil { + return mp, err + } + + for _, ns := range namespaces.Items { + + filePosture := postureData["filePosture"] + capabilityPosture := postureData["capabilitiesPosture"] + networkPosture := postureData["networkPosture"] + + if len(ns.Annotations["kubearmor-file-posture"]) > 0 { + filePosture = ns.Annotations["kubearmor-file-posture"] + } + + if len(ns.Annotations["kubearmor-capabilities-posture"]) > 0 { + capabilityPosture = ns.Annotations["kubearmor-capabilities-posture"] + } + + if len(ns.Annotations["kubearmor-network-posture"]) > 0 { + networkPosture = ns.Annotations["kubearmor-network-posture"] + } + mp[ns.Name] = &PostureAndVisibility{DefaultPosture: "file(" + filePosture + "), capabilities(" + capabilityPosture + "), network(" + networkPosture + ")", Visibility: ns.Annotations["kubearmor-visibility"]} + } + + return mp, err +} + +func getAnnotatedPods(c *k8s.Client, postureData map[string]string) error { // Annotated Pods Description var data [][]string pods, err := c.K8sClientset.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{}) @@ -590,26 +650,34 @@ func getAnnotatedPods(c *k8s.Client) error { return err } + mp, err := getNsSecurityPostureAndVisibility(c, postureData) + if err != nil { + return err + } + policyMap, err := getPoliciesOnAnnotatedPods(c) if err != nil { color.Red(" Error getting policies on annotated pods") } for _, p := range pods.Items { + if p.Annotations["kubearmor-policy"] == "enabled" { armoredPod, err := c.K8sClientset.CoreV1().Pods(p.Namespace).Get(context.Background(), p.Name, metav1.GetOptions{}) if err != nil { return err } - data = append(data, []string{armoredPod.Namespace, armoredPod.Name, ""}) + data = append(data, []string{armoredPod.Namespace, mp[armoredPod.Namespace].DefaultPosture, mp[armoredPod.Namespace].Visibility, armoredPod.Name, ""}) labels := getAnnotatedPodLabels(armoredPod.Labels) + for policyKey, policyValue := range policyMap { s2 := sliceToSet(policyValue) if s2.IsSubset(labels) { if checkIfDataAlreadyContainsPodName(data, armoredPod.Name, policyKey) { continue } else { - data = append(data, []string{armoredPod.Namespace, armoredPod.Name, policyKey}) + data = append(data, []string{armoredPod.Namespace, mp[armoredPod.Namespace].DefaultPosture, mp[armoredPod.Namespace].Visibility, armoredPod.Name, policyKey}) + } } } @@ -626,13 +694,13 @@ func getAnnotatedPods(c *k8s.Client) error { }) table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"NAMESPACE", "NAME", "POLICY"}) + table.SetHeader([]string{"NAMESPACE", "DEFAULT POSTURE", "VISIBILITY", "NAME", "POLICY"}) for _, v := range data { table.Append(v) } table.SetRowLine(true) - table.SetAutoMergeCellsByColumnIndex([]int{0, 1}) + table.SetAutoMergeCellsByColumnIndex([]int{0, 1, 2}) table.Render() return nil } @@ -676,10 +744,10 @@ func checkIfDataAlreadyContainsPodName(input [][]string, name string, policy str for _, slice := range input { //if slice contains podname, then append the policy to the existing policies if slices.Contains(slice, name) { - if slice[2] == "" { - slice[2] = policy + if slice[4] == "" { + slice[4] = policy } else { - slice[2] = slice[2] + "\n" + policy + slice[4] = slice[4] + "\n" + policy } return true }