Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added security posture and visibilty column in karmor probe #301

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 91 additions & 23 deletions probe/probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -436,34 +442,34 @@ 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 {
_, err := boldWhite.Printf("Node %d : \n", i+1)
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",
Expand Down Expand Up @@ -508,31 +514,46 @@ 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)})
data = append(data, []string{" ", "Container Runtime:", green(kd.ContainerRuntime)})
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
Expand Down Expand Up @@ -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
Expand All @@ -582,34 +609,75 @@ 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{})
if err != nil {
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})

}
}
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down