diff --git a/KubeArmor/core/containerdHandler.go b/KubeArmor/core/containerdHandler.go index c0026cee5c..f630f4ba08 100644 --- a/KubeArmor/core/containerdHandler.go +++ b/KubeArmor/core/containerdHandler.go @@ -133,7 +133,7 @@ func (ch *ContainerdHandler) Close() { // ==================== // // GetContainerInfo Function -func (ch *ContainerdHandler) GetContainerInfo(ctx context.Context, containerID string) (tp.Container, error) { +func (ch *ContainerdHandler) GetContainerInfo(ctx context.Context, containerID string, OwnerInfo map[string]tp.PodOwner) (tp.Container, error) { req := pb.GetContainerRequest{ID: containerID} res, err := ch.client.Get(ctx, &req) if err != nil { @@ -163,6 +163,12 @@ func (ch *ContainerdHandler) GetContainerInfo(ctx context.Context, containerID s container.NamespaceName = "container_namespace" } + if len(OwnerInfo) > 0 { + if podOwnerInfo, ok := OwnerInfo[container.EndPointName]; ok { + container.Owner = podOwnerInfo + } + } + iface, err := typeurl.UnmarshalAny(res.Container.Spec) if err != nil { return tp.Container{}, err @@ -286,7 +292,7 @@ func (dm *KubeArmorDaemon) UpdateContainerdContainer(ctx context.Context, contai if action == "start" { // get container information from containerd client - container, err := Containerd.GetContainerInfo(ctx, containerID) + container, err := Containerd.GetContainerInfo(ctx, containerID, dm.OwnerInfo) if err != nil { return false } diff --git a/KubeArmor/core/crioHandler.go b/KubeArmor/core/crioHandler.go index c9f83b47c9..466b2f3fa2 100644 --- a/KubeArmor/core/crioHandler.go +++ b/KubeArmor/core/crioHandler.go @@ -77,7 +77,7 @@ func (ch *CrioHandler) Close() { // ==================== // // GetContainerInfo Function gets info of a particular container -func (ch *CrioHandler) GetContainerInfo(ctx context.Context, containerID string) (tp.Container, error) { +func (ch *CrioHandler) GetContainerInfo(ctx context.Context, containerID string, OwnerInfo map[string]tp.PodOwner) (tp.Container, error) { // request to get status of specified container // verbose has to be true to retrieve additional CRI specific info req := &pb.ContainerStatusRequest{ @@ -110,6 +110,12 @@ func (ch *CrioHandler) GetContainerInfo(ctx context.Context, containerID string) container.EndPointName = val } + if len(OwnerInfo) > 0 { + if podOwnerInfo, ok := OwnerInfo[container.EndPointName]; ok { + container.Owner = podOwnerInfo + } + } + // extracting the runtime specific "info" var containerInfo CrioContainerInfo err = json.Unmarshal([]byte(res.Info["info"]), &containerInfo) @@ -201,7 +207,7 @@ func (dm *KubeArmorDaemon) UpdateCrioContainer(ctx context.Context, containerID, if action == "start" { // get container info from client - container, err := Crio.GetContainerInfo(ctx, containerID) + container, err := Crio.GetContainerInfo(ctx, containerID, dm.OwnerInfo) if err != nil { return false } diff --git a/KubeArmor/core/dockerHandler.go b/KubeArmor/core/dockerHandler.go index 5f15ba7991..ebfc377fdd 100644 --- a/KubeArmor/core/dockerHandler.go +++ b/KubeArmor/core/dockerHandler.go @@ -91,7 +91,7 @@ func (dh *DockerHandler) Close() { // ==================== // // GetContainerInfo Function -func (dh *DockerHandler) GetContainerInfo(containerID string) (tp.Container, error) { +func (dh *DockerHandler) GetContainerInfo(containerID string, OwnerInfo map[string]tp.PodOwner) (tp.Container, error) { if dh.DockerClient == nil { return tp.Container{}, errors.New("no docker client") } @@ -125,6 +125,12 @@ func (dh *DockerHandler) GetContainerInfo(containerID string) (tp.Container, err container.NamespaceName = "container_namespace" } + if len(OwnerInfo) > 0 { + if podOwnerInfo, ok := OwnerInfo[container.EndPointName]; ok { + container.Owner = podOwnerInfo + } + } + container.AppArmorProfile = inspect.AppArmorProfile if inspect.HostConfig.Privileged || (inspect.HostConfig.CapAdd != nil && len(inspect.HostConfig.CapAdd) > 0) { @@ -216,7 +222,7 @@ func (dh *DockerHandler) GetEventChannel() <-chan events.Message { func (dm *KubeArmorDaemon) SetContainerVisibility(containerID string) { // get container information from docker client - container, err := Docker.GetContainerInfo(containerID) + container, err := Docker.GetContainerInfo(containerID, dm.OwnerInfo) if err != nil { return } @@ -254,7 +260,7 @@ func (dm *KubeArmorDaemon) GetAlreadyDeployedDockerContainers() { if containerList, err := Docker.DockerClient.ContainerList(context.Background(), types.ContainerListOptions{}); err == nil { for _, dcontainer := range containerList { // get container information from docker client - container, err := Docker.GetContainerInfo(dcontainer.ID) + container, err := Docker.GetContainerInfo(dcontainer.ID, dm.OwnerInfo) if err != nil { continue } @@ -363,7 +369,7 @@ func (dm *KubeArmorDaemon) UpdateDockerContainer(containerID, action string) { var err error // get container information from docker client - container, err = Docker.GetContainerInfo(containerID) + container, err = Docker.GetContainerInfo(containerID, dm.OwnerInfo) if err != nil { return } diff --git a/KubeArmor/core/kubeArmor.go b/KubeArmor/core/kubeArmor.go index 3635e1d3de..0dcffff397 100644 --- a/KubeArmor/core/kubeArmor.go +++ b/KubeArmor/core/kubeArmor.go @@ -63,6 +63,9 @@ type KubeArmorDaemon struct { EndPoints []tp.EndPoint EndPointsLock *sync.RWMutex + // Owner Info + OwnerInfo map[string]tp.PodOwner + // Security policies SecurityPolicies []tp.SecurityPolicy SecurityPoliciesLock *sync.RWMutex @@ -142,6 +145,8 @@ func NewKubeArmorDaemon() *KubeArmorDaemon { dm.MonitorLock = new(sync.RWMutex) + dm.OwnerInfo = map[string]tp.PodOwner{} + return dm } diff --git a/KubeArmor/core/kubeUpdate.go b/KubeArmor/core/kubeUpdate.go index 822c70210b..2803bb894a 100644 --- a/KubeArmor/core/kubeUpdate.go +++ b/KubeArmor/core/kubeUpdate.go @@ -187,9 +187,6 @@ func (dm *KubeArmorDaemon) UpdateEndPointWithPod(action string, pod tp.K8sPod) { newPoint.NamespaceName = pod.Metadata["namespaceName"] newPoint.EndPointName = pod.Metadata["podName"] - newPoint.Owner.Ref = pod.Metadata["owner.controller"] - newPoint.Owner.Name = pod.Metadata["owner.controllerName"] - newPoint.Owner.Namespace = pod.Metadata["owner.namespace"] newPoint.Labels = map[string]string{} newPoint.Identities = []string{"namespaceName=" + pod.Metadata["namespaceName"]} @@ -242,11 +239,14 @@ func (dm *KubeArmorDaemon) UpdateEndPointWithPod(action string, pod tp.K8sPod) { container := dm.Containers[containerID] container.NamespaceName = newPoint.NamespaceName - container.Owner.Ref = newPoint.Owner.Ref - container.Owner.Name = newPoint.Owner.Name - container.Owner.Namespace = newPoint.Owner.Namespace container.EndPointName = newPoint.EndPointName + if (container.Owner == tp.PodOwner{}) && (len(dm.OwnerInfo) > 0) { + if podOwnerInfo, ok := dm.OwnerInfo[container.EndPointName]; ok && (podOwnerInfo != tp.PodOwner{}) { + container.Owner = podOwnerInfo + } + } + labels := []string{} for k, v := range newPoint.Labels { labels = append(labels, k+"="+v) @@ -412,10 +412,12 @@ func (dm *KubeArmorDaemon) UpdateEndPointWithPod(action string, pod tp.K8sPod) { container := dm.Containers[containerID] container.NamespaceName = newEndPoint.NamespaceName - container.Owner.Ref = newEndPoint.Owner.Ref - container.Owner.Name = newEndPoint.Owner.Name - container.Owner.Namespace = newEndPoint.Owner.Namespace container.EndPointName = newEndPoint.EndPointName + if (container.Owner == tp.PodOwner{}) && (len(dm.OwnerInfo) > 0) { + if podOwnerInfo, ok := dm.OwnerInfo[container.EndPointName]; ok && (podOwnerInfo != tp.PodOwner{}) { + container.Owner = podOwnerInfo + } + } labels := []string{} for k, v := range newEndPoint.Labels { @@ -550,6 +552,9 @@ func (dm *KubeArmorDaemon) HandleUnknownNamespaceNsMap(container *tp.Container) // WatchK8sPods Function func (dm *KubeArmorDaemon) WatchK8sPods() { + var controllerName, controller, namespace string + var err error + for { if resp := K8s.WatchK8sPods(); resp != nil { defer func() { @@ -583,16 +588,29 @@ func (dm *KubeArmorDaemon) WatchK8sPods() { pod.Metadata["namespaceName"] = event.Object.ObjectMeta.Namespace pod.Metadata["podName"] = event.Object.ObjectMeta.Name - controllerName, controller, namespace, err := getTopLevelOwner(event.Object.ObjectMeta, event.Object.Namespace, event.Object.Kind) - if err != nil { - dm.Logger.Warnf("Failed to get ownerRef (%s, %s)", event.Object.ObjectMeta.Name, err.Error()) + if event.Type == "ADDED" { + controllerName, controller, namespace, err = getTopLevelOwner(event.Object.ObjectMeta, event.Object.Namespace, event.Object.Kind) + if err != nil { + dm.Logger.Warnf("Failed to get ownerRef (%s, %s)", event.Object.ObjectMeta.Name, err.Error()) + } + } + _, err := K8s.K8sClient.CoreV1().Pods(namespace).Get(context.Background(), event.Object.ObjectMeta.Name, metav1.GetOptions{}) + if err == nil && (event.Type == "MODIFIED" || event.Type != "DELETED") { + controllerName, controller, namespace, err = getTopLevelOwner(event.Object.ObjectMeta, event.Object.Namespace, event.Object.Kind) + if err != nil { + dm.Logger.Warnf("Failed to get ownerRef (%s, %s)", event.Object.ObjectMeta.Name, err.Error()) + } + } + owner := tp.PodOwner{ + Name: controllerName, + Ref: controller, + Namespace: namespace, } + dm.OwnerInfo[pod.Metadata["podName"]] = owner + podOwnerName = controllerName - pod.Metadata["owner.controllerName"] = controllerName - pod.Metadata["owner.controller"] = controller - pod.Metadata["owner.namespace"] = namespace //get the owner , then check if that owner has owner if...do it recusivelt until you get the no owner @@ -704,15 +722,15 @@ func (dm *KubeArmorDaemon) WatchK8sPods() { appArmorAnnotations := map[string]string{} updateAppArmor := false - if _, ok := pod.Metadata["owner.controllerName"]; ok { - if pod.Metadata["owner.controller"] == "StatefulSet" { + if dm.OwnerInfo[pod.Metadata["podName"]].Name != "" { + if dm.OwnerInfo[pod.Metadata["podName"]].Ref == "StatefulSet" { statefulset, err := K8s.K8sClient.AppsV1().StatefulSets(pod.Metadata["namespaceName"]).Get(context.Background(), podOwnerName, metav1.GetOptions{}) if err == nil { for _, c := range statefulset.Spec.Template.Spec.Containers { containers = append(containers, c.Name) } } - } else if pod.Metadata["owner.controller"] == "ReplicaSet" { + } else if dm.OwnerInfo[pod.Metadata["podName"]].Ref == "ReplicaSet" { replica, err := K8s.K8sClient.AppsV1().ReplicaSets(pod.Metadata["namespaceName"]).Get(context.Background(), podOwnerName, metav1.GetOptions{}) if err == nil { for _, c := range replica.Spec.Template.Spec.Containers { @@ -720,21 +738,21 @@ func (dm *KubeArmorDaemon) WatchK8sPods() { } } - } else if pod.Metadata["owner.controller"] == "DaemonSet" { + } else if dm.OwnerInfo[pod.Metadata["podName"]].Ref == "DaemonSet" { daemon, err := K8s.K8sClient.AppsV1().DaemonSets(pod.Metadata["namespaceName"]).Get(context.Background(), podOwnerName, metav1.GetOptions{}) if err == nil { for _, c := range daemon.Spec.Template.Spec.Containers { containers = append(containers, c.Name) } } - } else if pod.Metadata["owner.controller"] == "Deployment" { + } else if dm.OwnerInfo[pod.Metadata["podName"]].Ref == "Deployment" { deploy, err := K8s.K8sClient.AppsV1().Deployments(pod.Metadata["namespaceName"]).Get(context.Background(), podOwnerName, metav1.GetOptions{}) if err == nil { for _, c := range deploy.Spec.Template.Spec.Containers { containers = append(containers, c.Name) } } - } else if pod.Metadata["owner.controller"] == "Pod" { + } else if dm.OwnerInfo[pod.Metadata["podName"]].Ref == "Pod" { pod, err := K8s.K8sClient.CoreV1().Pods(pod.Metadata["namespaceName"]).Get(context.Background(), podOwnerName, metav1.GetOptions{}) if err == nil { for _, c := range pod.Spec.Containers { @@ -784,10 +802,11 @@ func (dm *KubeArmorDaemon) WatchK8sPods() { // update apparmor profiles dm.RuntimeEnforcer.UpdateAppArmorProfiles(pod.Metadata["podName"], "ADDED", appArmorAnnotations, pod.PrivilegedAppArmorProfiles) - if updateAppArmor && pod.Annotations["kubearmor-policy"] == "enabled" && pod.Metadata["owner.controller"] != "Pod" { - if deploymentName, ok := pod.Metadata["owner.controllerName"]; ok { + if updateAppArmor && pod.Annotations["kubearmor-policy"] == "enabled" && dm.OwnerInfo[pod.Metadata["podName"]].Ref != "Pod" { + if dm.OwnerInfo[pod.Metadata["podName"]].Name != "" { + deploymentName := dm.OwnerInfo[pod.Metadata["podName"]].Name // patch the deployment with apparmor annotations - if err := K8s.PatchResourceWithAppArmorAnnotations(pod.Metadata["namespaceName"], deploymentName, appArmorAnnotations, pod.Metadata["owner.controller"]); err != nil { + if err := K8s.PatchResourceWithAppArmorAnnotations(pod.Metadata["namespaceName"], deploymentName, appArmorAnnotations, dm.OwnerInfo[pod.Metadata["podName"]].Ref); err != nil { dm.Logger.Errf("Failed to update AppArmor Annotations (%s/%s/%s, %s)", pod.Metadata["namespaceName"], deploymentName, pod.Metadata["podName"], err.Error()) } else { dm.Logger.Printf("Patched AppArmor Annotations (%s/%s/%s)", pod.Metadata["namespaceName"], deploymentName, pod.Metadata["podName"]) @@ -804,10 +823,11 @@ func (dm *KubeArmorDaemon) WatchK8sPods() { prevPolicyEnabled = val } - if updateAppArmor && prevPolicyEnabled != "enabled" && pod.Annotations["kubearmor-policy"] == "enabled" && pod.Metadata["owner.controller"] != "Pod" { - if deploymentName, ok := pod.Metadata["owner.controllerName"]; ok { + if updateAppArmor && prevPolicyEnabled != "enabled" && pod.Annotations["kubearmor-policy"] == "enabled" && dm.OwnerInfo[pod.Metadata["podName"]].Ref != "Pod" { + if dm.OwnerInfo[pod.Metadata["podName"]].Name != "" { + deploymentName := dm.OwnerInfo[pod.Metadata["podName"]].Name // patch the deployment with apparmor annotations - if err := K8s.PatchResourceWithAppArmorAnnotations(pod.Metadata["namespaceName"], deploymentName, appArmorAnnotations, pod.Metadata["owner.controller"]); err != nil { + if err := K8s.PatchResourceWithAppArmorAnnotations(pod.Metadata["namespaceName"], deploymentName, appArmorAnnotations, dm.OwnerInfo[pod.Metadata["podName"]].Ref); err != nil { dm.Logger.Errf("Failed to update AppArmor Annotations (%s/%s/%s, %s)", pod.Metadata["namespaceName"], deploymentName, pod.Metadata["podName"], err.Error()) } else { dm.Logger.Printf("Patched AppArmor Annotations (%s/%s/%s)", pod.Metadata["namespaceName"], deploymentName, pod.Metadata["podName"]) @@ -858,6 +878,7 @@ func (dm *KubeArmorDaemon) WatchK8sPods() { for idx, k8spod := range dm.K8sPods { if k8spod.Metadata["namespaceName"] == pod.Metadata["namespaceName"] && k8spod.Metadata["podName"] == pod.Metadata["podName"] { dm.K8sPods = append(dm.K8sPods[:idx], dm.K8sPods[idx+1:]...) + delete(dm.OwnerInfo, pod.Metadata["podName"]) break } } diff --git a/KubeArmor/types/types.go b/KubeArmor/types/types.go index d881654e9b..33deb76a05 100644 --- a/KubeArmor/types/types.go +++ b/KubeArmor/types/types.go @@ -76,9 +76,8 @@ type Namespace struct { type EndPoint struct { NamespaceName string `json:"namespaceName"` - EndPointName string `json:"endPointName"` - Owner PodOwner `json:"owner,omitempty"` - ContainerName string `json:"containerName"` + EndPointName string `json:"endPointName"` + ContainerName string `json:"containerName"` Labels map[string]string `json:"labels"` Identities []string `json:"identities"`