diff --git a/KubeArmor/config/config.go b/KubeArmor/config/config.go index 22ccb3b50..2eb861c96 100644 --- a/KubeArmor/config/config.go +++ b/KubeArmor/config/config.go @@ -54,7 +54,9 @@ type KubearmorConfig struct { DefaultPostureLogs bool // Enable/Disable Default Posture logs for AppArmor LSM InitTimeout string // Timeout for main thread init stages - StateAgent bool // enable KubeArmor state agent + UseOCIHooks bool // Use OCI hooks for container visibility instead of CRI socket + StateAgent bool // enable KubeArmor state agent + RestorePath string // Path to restore policies from AlertThrottling bool // Enable/Disable Alert Throttling MaxAlertPerSec int // Maximum alerts allowed per second @@ -96,6 +98,8 @@ const ( ConfigCoverageTest string = "coverageTest" ConfigK8sEnv string = "k8s" ConfigDebug string = "debug" + UseOCIHooks string = "useOCIHooks" + RestorePath string = "restorePath" ConfigUntrackedNs string = "untrackedNs" LsmOrder string = "lsm" BPFFsPath string = "bpfFsPath" @@ -156,6 +160,10 @@ func readCmdLineParams() { stateAgent := flag.Bool(ConfigStateAgent, false, "enabling KubeArmor State Agent client") + useOCIHooks := flag.Bool(UseOCIHooks, false, "Use OCI hooks to get new containers instead of using container runtime socket") + + restorePath := flag.String(RestorePath, PolicyDir, "Path to restore policies from") + alertThrottling := flag.Bool(ConfigAlertThrottling, true, "enabling Alert Throttling") maxAlertPerSec := flag.Int(ConfigMaxAlertPerSec, 10, "Maximum alerts allowed per second") @@ -220,6 +228,10 @@ func readCmdLineParams() { viper.SetDefault(ConfigStateAgent, *stateAgent) + viper.SetDefault(UseOCIHooks, *useOCIHooks) + + viper.SetDefault(RestorePath, *restorePath) + viper.SetDefault(ConfigAlertThrottling, *alertThrottling) viper.SetDefault(ConfigMaxAlertPerSec, *maxAlertPerSec) @@ -324,6 +336,10 @@ func LoadConfig() error { GlobalCfg.StateAgent = viper.GetBool(ConfigStateAgent) + GlobalCfg.UseOCIHooks = viper.GetBool(UseOCIHooks) + + GlobalCfg.RestorePath = viper.GetString(RestorePath) + GlobalCfg.AlertThrottling = viper.GetBool(ConfigAlertThrottling) GlobalCfg.MaxAlertPerSec = viper.GetInt(ConfigMaxAlertPerSec) GlobalCfg.ThrottleSec = viper.GetInt(ConfigThrottleSec) diff --git a/KubeArmor/core/containerdHandler.go b/KubeArmor/core/containerdHandler.go index 66ca50db4..9201b8490 100644 --- a/KubeArmor/core/containerdHandler.go +++ b/KubeArmor/core/containerdHandler.go @@ -335,61 +335,11 @@ func (dm *KubeArmorDaemon) UpdateContainerdContainer(ctx context.Context, contai } } - switch endPointEvent { - case "ADDED": - endPoint.EndPointName = container.ContainerName - endPoint.ContainerName = container.ContainerName - endPoint.NamespaceName = container.NamespaceName - - endPoint.Containers = []string{container.ContainerID} - - endPoint.Labels = containerLabels - endPoint.Identities = containerIdentities - - endPoint.PolicyEnabled = tp.KubeArmorPolicyEnabled - endPoint.ProcessVisibilityEnabled = true - endPoint.FileVisibilityEnabled = true - endPoint.NetworkVisibilityEnabled = true - endPoint.CapabilitiesVisibilityEnabled = true - - endPoint.AppArmorProfiles = []string{"kubearmor_" + container.ContainerName} - - globalDefaultPosture := tp.DefaultPosture{ - FileAction: cfg.GlobalCfg.DefaultFilePosture, - NetworkAction: cfg.GlobalCfg.DefaultNetworkPosture, - CapabilitiesAction: cfg.GlobalCfg.DefaultCapabilitiesPosture, - } - endPoint.DefaultPosture = globalDefaultPosture - - dm.SecurityPoliciesLock.RLock() - for _, secPol := range dm.SecurityPolicies { - if kl.MatchIdentities(secPol.Spec.Selector.Identities, endPoint.Identities) { - endPoint.SecurityPolicies = append(endPoint.SecurityPolicies, secPol) - } - } - dm.SecurityPoliciesLock.RUnlock() - - dm.EndPoints = append(dm.EndPoints, endPoint) - case "UPDATED": - // in case of AppArmor enforcement when endPoint has to be created first - endPoint.Containers = append(endPoint.Containers, container.ContainerID) - - // if this container has any additional identities, add them - endPoint.Identities = append(endPoint.Identities, containerIdentities...) - endPoint.Identities = slices.Compact(endPoint.Identities) - - // add other policies - endPoint.SecurityPolicies = []tp.SecurityPolicy{} - dm.SecurityPoliciesLock.RLock() - for _, secPol := range dm.SecurityPolicies { - if kl.MatchIdentities(secPol.Spec.Selector.Identities, endPoint.Identities) { - endPoint.SecurityPolicies = append(endPoint.SecurityPolicies, secPol) - } - } - dm.SecurityPoliciesLock.RUnlock() - + dm.CreateEndpoint(&endPoint, container, containerLabels, containerIdentities, endPointEvent) + if endPointEvent == "UPDATED" { dm.EndPoints[endPointIdx] = endPoint } + dm.EndPointsLock.Unlock() } @@ -457,23 +407,7 @@ func (dm *KubeArmorDaemon) UpdateContainerdContainer(ctx context.Context, contai } if dm.SystemMonitor != nil && cfg.GlobalCfg.Policy { - // for throttling - dm.SystemMonitor.Logger.ContainerNsKey[containerID] = common.OuterKey{ - MntNs: container.MntNS, - PidNs: container.PidNS, - } - - // update NsMap - dm.SystemMonitor.AddContainerIDToNsMap(containerID, container.NamespaceName, container.PidNS, container.MntNS) - dm.RuntimeEnforcer.RegisterContainer(containerID, container.PidNS, container.MntNS) - - if len(endPoint.SecurityPolicies) > 0 { // struct can be empty or no policies registered for the endPoint yet - dm.Logger.UpdateSecurityPolicies("ADDED", endPoint) - if dm.RuntimeEnforcer != nil && endPoint.PolicyEnabled == tp.KubeArmorPolicyEnabled { - // enforce security policies - dm.RuntimeEnforcer.UpdateSecurityPolicies(endPoint) - } - } + dm.PopulateMaps(endPoint, container) } if cfg.GlobalCfg.StateAgent { diff --git a/KubeArmor/core/dockerHandler.go b/KubeArmor/core/dockerHandler.go index 35f3caab3..d433a376a 100644 --- a/KubeArmor/core/dockerHandler.go +++ b/KubeArmor/core/dockerHandler.go @@ -496,61 +496,11 @@ func (dm *KubeArmorDaemon) UpdateDockerContainer(containerID, action string) { } } - switch endPointEvent { - case "ADDED": - endPoint.EndPointName = container.ContainerName - endPoint.ContainerName = container.ContainerName - endPoint.NamespaceName = container.NamespaceName - - endPoint.Containers = []string{container.ContainerID} - - endPoint.Labels = containerLabels - endPoint.Identities = containerIdentities - - endPoint.PolicyEnabled = tp.KubeArmorPolicyEnabled - endPoint.ProcessVisibilityEnabled = true - endPoint.FileVisibilityEnabled = true - endPoint.NetworkVisibilityEnabled = true - endPoint.CapabilitiesVisibilityEnabled = true - - endPoint.AppArmorProfiles = []string{"kubearmor_" + container.ContainerName} - - globalDefaultPosture := tp.DefaultPosture{ - FileAction: cfg.GlobalCfg.DefaultFilePosture, - NetworkAction: cfg.GlobalCfg.DefaultNetworkPosture, - CapabilitiesAction: cfg.GlobalCfg.DefaultCapabilitiesPosture, - } - endPoint.DefaultPosture = globalDefaultPosture - - dm.SecurityPoliciesLock.RLock() - for _, secPol := range dm.SecurityPolicies { - if kl.MatchIdentities(secPol.Spec.Selector.Identities, endPoint.Identities) { - endPoint.SecurityPolicies = append(endPoint.SecurityPolicies, secPol) - } - } - dm.SecurityPoliciesLock.RUnlock() - - dm.EndPoints = append(dm.EndPoints, endPoint) - case "UPDATED": - // in case of AppArmor enforcement when endpoint has to be created first - endPoint.Containers = append(endPoint.Containers, container.ContainerID) - - // if this container has any additional identities, add them - endPoint.Identities = append(endPoint.Identities, containerIdentities...) - endPoint.Identities = slices.Compact(endPoint.Identities) - - // add other policies - endPoint.SecurityPolicies = []tp.SecurityPolicy{} - dm.SecurityPoliciesLock.RLock() - for _, secPol := range dm.SecurityPolicies { - if kl.MatchIdentities(secPol.Spec.Selector.Identities, endPoint.Identities) { - endPoint.SecurityPolicies = append(endPoint.SecurityPolicies, secPol) - } - } - dm.SecurityPoliciesLock.RUnlock() - + dm.CreateEndpoint(&endPoint, container, containerLabels, containerIdentities, endPointEvent) + if endPointEvent == "UPDATED" { dm.EndPoints[endPointIdx] = endPoint } + dm.EndPointsLock.Unlock() } @@ -607,23 +557,7 @@ func (dm *KubeArmorDaemon) UpdateDockerContainer(containerID, action string) { } if dm.SystemMonitor != nil && cfg.GlobalCfg.Policy { - // for throttling - dm.SystemMonitor.Logger.ContainerNsKey[containerID] = common.OuterKey{ - MntNs: container.MntNS, - PidNs: container.PidNS, - } - - // update NsMap - dm.SystemMonitor.AddContainerIDToNsMap(containerID, container.NamespaceName, container.PidNS, container.MntNS) - dm.RuntimeEnforcer.RegisterContainer(containerID, container.PidNS, container.MntNS) - - if len(endPoint.SecurityPolicies) > 0 { // struct can be empty or no policies registered for the endpoint yet - dm.Logger.UpdateSecurityPolicies("ADDED", endPoint) - if dm.RuntimeEnforcer != nil && endPoint.PolicyEnabled == tp.KubeArmorPolicyEnabled { - // enforce security policies - dm.RuntimeEnforcer.UpdateSecurityPolicies(endPoint) - } - } + dm.PopulateMaps(endPoint, container) } if cfg.GlobalCfg.StateAgent { diff --git a/KubeArmor/core/hookHandler.go b/KubeArmor/core/hookHandler.go new file mode 100644 index 000000000..401f9a9ee --- /dev/null +++ b/KubeArmor/core/hookHandler.go @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Authors of KubeArmor + +package core + +import ( + "encoding/json" + "io" + "log" + "os" + "strings" + + "github.com/fsnotify/fsnotify" + kl "github.com/kubearmor/KubeArmor/KubeArmor/common" + cfg "github.com/kubearmor/KubeArmor/KubeArmor/config" + "github.com/kubearmor/KubeArmor/KubeArmor/state" + tp "github.com/kubearmor/KubeArmor/KubeArmor/types" +) + +func (dm *KubeArmorDaemon) HandleFile(file string) { + f, err := os.Open(file) + if err != nil { + log.Fatalln("Error opening file:", err) + } + + decoder := json.NewDecoder(f) + for { + var containerData tp.Container + + err = decoder.Decode(&containerData) + if err != nil { + dm.Logger.Warnf("Reached EOF") + } + dm.handleContainerCreate(containerData) + if err == io.EOF { + // End of file reached + break + } + } + + defer f.Close() + + w, err := fsnotify.NewWatcher() + if err != nil { + log.Fatal("Error creating new watcher:", err) + } + defer w.Close() + + err = w.Add(file) + if err != nil { + log.Fatal("Error adding file to watcher:", err) + } + + for { + select { + case err, ok := <-w.Errors: + if !ok { + dm.Logger.Warnf("Returning 1") + return + } + log.Println("Watcher error:", err) + + case e, ok := <-w.Events: + if !ok { + dm.Logger.Warnf("Returning 2") + return + } + + if e.Op&fsnotify.Write == fsnotify.Write { + f, err := os.Open(file) + if err != nil { + log.Println("Error opening file:", err) + continue + } + defer f.Close() + + decoder := json.NewDecoder(f) + for { + var containerData tp.Container + + err = decoder.Decode(&containerData) + if err != nil { + dm.Logger.Warnf("Reached EOF") + } + dm.handleContainerCreate(containerData) + if err == io.EOF { + // End of file reached + break + } + } + } + } + } +} + +func (dm *KubeArmorDaemon) handleContainerCreate(container tp.Container) { + endPoint := tp.EndPoint{} + + dm.ContainersLock.Lock() + defer dm.ContainersLock.Unlock() + if _, ok := dm.Containers[container.ContainerID]; !ok { + dm.Containers[container.ContainerID] = container + + // create/update endpoint in non-k8s mode + if !dm.K8sEnabled { + // for policy matching + container.NamespaceName = "container_namespace" + labels := []string{} + labels = append(labels, "namespaceName="+container.NamespaceName) + labels = append(labels, "kubearmor.io/container.name="+container.ContainerName) + container.Labels = strings.Join(labels, ",") + + containerLabels, containerIdentities := kl.GetLabelsFromString(container.Labels) + dm.EndPointsLock.Lock() + dm.CreateEndpoint(&endPoint, container, containerLabels, containerIdentities, "ADDED") + dm.EndPointsLock.Unlock() + } + } else if dm.Containers[container.ContainerID].PidNS == 0 && dm.Containers[container.ContainerID].MntNS == 0 { + c := dm.Containers[container.ContainerID] + c.MntNS = container.MntNS + c.PidNS = container.PidNS + c.AppArmorProfile = container.AppArmorProfile + dm.Containers[c.ContainerID] = c + + dm.EndPointsLock.Lock() + for idx, endpoint := range dm.EndPoints { + if endpoint.NamespaceName == container.NamespaceName && endpoint.EndPointName == container.EndPointName && kl.ContainsElement(endPoint.Containers, container.ContainerID) { + + // update apparmor profiles + if !kl.ContainsElement(endpoint.AppArmorProfiles, container.AppArmorProfile) { + dm.EndPoints[idx].AppArmorProfiles = append(dm.EndPoints[idx].AppArmorProfiles, container.AppArmorProfile) + } + + if container.Privileged && dm.EndPoints[idx].PrivilegedContainers != nil { + dm.EndPoints[idx].PrivilegedContainers[container.ContainerName] = struct{}{} + } + + endPoint = dm.EndPoints[idx] + + break + } + } + dm.EndPointsLock.Unlock() + } + + if len(dm.OwnerInfo) > 0 { + container.Owner = dm.OwnerInfo[container.EndPointName] + } + + if dm.SystemMonitor != nil && cfg.GlobalCfg.Policy { + dm.PopulateMaps(endPoint, container) + } + + if cfg.GlobalCfg.StateAgent { + container.Status = "running" + go dm.StateAgent.PushContainerEvent(container, state.EventAdded) + } + + dm.Logger.Printf("Detected a container (added/%.12s/pidns=%d/mntns=%d)", container.ContainerID, container.PidNS, container.MntNS) +} diff --git a/KubeArmor/core/kubeArmor.go b/KubeArmor/core/kubeArmor.go index 9951150ba..fcfc5b3c4 100644 --- a/KubeArmor/core/kubeArmor.go +++ b/KubeArmor/core/kubeArmor.go @@ -569,8 +569,10 @@ func KubeArmor() { dm.SetContainerNSVisibility() - // Check if cri socket set, if not then auto detect - if cfg.GlobalCfg.CRISocket == "" { + if cfg.GlobalCfg.UseOCIHooks { + go dm.HandleFile("/opt/output.json") + } else if cfg.GlobalCfg.CRISocket == "" { + // Check if cri socket set, if not then auto detect if kl.GetCRISocket("") == "" { dm.Logger.Warnf("Error while looking for CRI socket file") enableContainerPolicy = false @@ -592,16 +594,20 @@ func KubeArmor() { // monitor crio events go dm.MonitorCrioEvents() } else { - dm.Logger.Warnf("Failed to monitor containers: %s is not a supported CRI socket.", cfg.GlobalCfg.CRISocket) - enableContainerPolicy = false + if !cfg.GlobalCfg.UseOCIHooks { + dm.Logger.Warnf("Failed to monitor containers: %s is not a supported CRI socket.", cfg.GlobalCfg.CRISocket) + enableContainerPolicy = false + } } dm.Logger.Printf("Using %s for monitoring containers", cfg.GlobalCfg.CRISocket) } if dm.K8sEnabled && cfg.GlobalCfg.Policy { - // check if the CRI socket set while executing kubearmor exists - if cfg.GlobalCfg.CRISocket != "" { + if cfg.GlobalCfg.UseOCIHooks { + go dm.HandleFile("/opt/output.json") + } else if cfg.GlobalCfg.CRISocket != "" { // check if the CRI socket set while executing kubearmor exists + // check if the CRI socket set while executing kubearmor exists trimmedSocket := strings.TrimPrefix(cfg.GlobalCfg.CRISocket, "unix://") if _, err := os.Stat(trimmedSocket); err != nil { dm.Logger.Warnf("Error while looking for CRI socket file: %s", err.Error()) diff --git a/KubeArmor/core/provider.go b/KubeArmor/core/provider.go new file mode 100644 index 000000000..347b78813 --- /dev/null +++ b/KubeArmor/core/provider.go @@ -0,0 +1,86 @@ +package core + +import ( + "slices" + + "github.com/kubearmor/KubeArmor/KubeArmor/common" + kl "github.com/kubearmor/KubeArmor/KubeArmor/common" + cfg "github.com/kubearmor/KubeArmor/KubeArmor/config" + tp "github.com/kubearmor/KubeArmor/KubeArmor/types" +) + +func (dm *KubeArmorDaemon) CreateEndpoint(endPoint *tp.EndPoint, container tp.Container, containerLabels map[string]string, containerIdentities []string, endPointEvent string) { + switch endPointEvent { + case "ADDED": + endPoint.EndPointName = container.ContainerName + endPoint.ContainerName = container.ContainerName + endPoint.NamespaceName = container.NamespaceName + + endPoint.Containers = []string{container.ContainerID} + + endPoint.Labels = containerLabels + endPoint.Identities = containerIdentities + + endPoint.PolicyEnabled = tp.KubeArmorPolicyEnabled + endPoint.ProcessVisibilityEnabled = true + endPoint.FileVisibilityEnabled = true + endPoint.NetworkVisibilityEnabled = true + endPoint.CapabilitiesVisibilityEnabled = true + + endPoint.AppArmorProfiles = []string{"kubearmor_" + container.ContainerName} + + globalDefaultPosture := tp.DefaultPosture{ + FileAction: cfg.GlobalCfg.DefaultFilePosture, + NetworkAction: cfg.GlobalCfg.DefaultNetworkPosture, + CapabilitiesAction: cfg.GlobalCfg.DefaultCapabilitiesPosture, + } + endPoint.DefaultPosture = globalDefaultPosture + + dm.SecurityPoliciesLock.RLock() + for _, secPol := range dm.SecurityPolicies { + if kl.MatchIdentities(secPol.Spec.Selector.Identities, endPoint.Identities) { + endPoint.SecurityPolicies = append(endPoint.SecurityPolicies, secPol) + } + } + dm.SecurityPoliciesLock.RUnlock() + + dm.EndPoints = append(dm.EndPoints, *endPoint) + case "UPDATED": + // in case of AppArmor enforcement when endPoint has to be created first + endPoint.Containers = append(endPoint.Containers, container.ContainerID) + + // if this container has any additional identities, add them + endPoint.Identities = append(endPoint.Identities, containerIdentities...) + endPoint.Identities = slices.Compact(endPoint.Identities) + + // add other policies + endPoint.SecurityPolicies = []tp.SecurityPolicy{} + dm.SecurityPoliciesLock.RLock() + for _, secPol := range dm.SecurityPolicies { + if kl.MatchIdentities(secPol.Spec.Selector.Identities, endPoint.Identities) { + endPoint.SecurityPolicies = append(endPoint.SecurityPolicies, secPol) + } + } + dm.SecurityPoliciesLock.RUnlock() + } +} + +func (dm *KubeArmorDaemon) PopulateMaps(endPoint tp.EndPoint, container tp.Container) { + // for throttling + dm.SystemMonitor.Logger.ContainerNsKey[container.ContainerID] = common.OuterKey{ + MntNs: container.MntNS, + PidNs: container.PidNS, + } + + // update NsMap + dm.SystemMonitor.AddContainerIDToNsMap(container.ContainerID, container.NamespaceName, container.PidNS, container.MntNS) + dm.RuntimeEnforcer.RegisterContainer(container.ContainerID, container.PidNS, container.MntNS) + + if len(endPoint.SecurityPolicies) > 0 { // struct can be empty or no policies registered for the endPoint yet + dm.Logger.UpdateSecurityPolicies("ADDED", endPoint) + if dm.RuntimeEnforcer != nil && endPoint.PolicyEnabled == tp.KubeArmorPolicyEnabled { + // enforce security policies + dm.RuntimeEnforcer.UpdateSecurityPolicies(endPoint) + } + } +} diff --git a/KubeArmor/core/unorchestratedUpdates.go b/KubeArmor/core/unorchestratedUpdates.go index 209d3dfd7..958d03a7f 100644 --- a/KubeArmor/core/unorchestratedUpdates.go +++ b/KubeArmor/core/unorchestratedUpdates.go @@ -4,7 +4,6 @@ package core import ( - "encoding/json" "os" "regexp" "sort" @@ -15,6 +14,7 @@ import ( kg "github.com/kubearmor/KubeArmor/KubeArmor/log" tp "github.com/kubearmor/KubeArmor/KubeArmor/types" pb "github.com/kubearmor/KubeArmor/protobuf" + yl "sigs.k8s.io/yaml" ) // SetContainerVisibility function enables visibility flag arguments for un-orchestrated container and updates the visibility map @@ -684,9 +684,10 @@ func (dm *KubeArmorDaemon) ParseAndUpdateContainerSecurityPolicy(event tp.K8sKub // backupKubeArmorHostPolicy Function func (dm *KubeArmorDaemon) backupKubeArmorHostPolicy(policy tp.HostSecurityPolicy) { // Check for "/opt/kubearmor/policies" path. If dir not found, create the same - if _, err := os.Stat(cfg.PolicyDir); err != nil { - if err = os.MkdirAll(cfg.PolicyDir, 0700); err != nil { - kg.Warnf("Dir creation failed for [%v]", cfg.PolicyDir) + if _, err := os.Stat(cfg.GlobalCfg.RestorePath); err != nil { + if err = os.MkdirAll(cfg.GlobalCfg.RestorePath, 0700); err != nil { + kg.Warnf("Dir creation failed for [%v], setting restore path to %s", cfg.GlobalCfg.RestorePath, cfg.PolicyDir) + cfg.GlobalCfg.RestorePath = cfg.PolicyDir return } } @@ -694,8 +695,8 @@ func (dm *KubeArmorDaemon) backupKubeArmorHostPolicy(policy tp.HostSecurityPolic var file *os.File var err error - if file, err = os.Create(cfg.PolicyDir + policy.Metadata["policyName"] + ".yaml"); err == nil { - if policyBytes, err := json.Marshal(policy); err == nil { + if file, err = os.Create(cfg.GlobalCfg.RestorePath + policy.Metadata["policyName"] + ".yaml"); err == nil { + if policyBytes, err := yl.Marshal(policy); err == nil { if _, err = file.Write(policyBytes); err == nil { if err := file.Close(); err != nil { dm.Logger.Errf(err.Error()) @@ -708,9 +709,10 @@ func (dm *KubeArmorDaemon) backupKubeArmorHostPolicy(policy tp.HostSecurityPolic // Back up KubeArmor container policies in /opt/kubearmor/policies func (dm *KubeArmorDaemon) backupKubeArmorContainerPolicy(policy tp.SecurityPolicy) { // Check for "/opt/kubearmor/policies" path. If dir not found, create the same - if _, err := os.Stat(cfg.PolicyDir); err != nil { - if err = os.MkdirAll(cfg.PolicyDir, 0700); err != nil { - kg.Warnf("Dir creation failed for [%v]", cfg.PolicyDir) + if _, err := os.Stat(cfg.GlobalCfg.RestorePath); err != nil { + if err = os.MkdirAll(cfg.GlobalCfg.RestorePath, 0700); err != nil { + kg.Warnf("Dir creation failed for [%v], setting restore path to %s", cfg.GlobalCfg.RestorePath, cfg.PolicyDir) + cfg.GlobalCfg.RestorePath = cfg.PolicyDir return } } @@ -718,8 +720,8 @@ func (dm *KubeArmorDaemon) backupKubeArmorContainerPolicy(policy tp.SecurityPoli var file *os.File var err error - if file, err = os.Create(cfg.PolicyDir + policy.Metadata["policyName"] + ".yaml"); err == nil { - if policyBytes, err := json.Marshal(policy); err == nil { + if file, err = os.Create(cfg.GlobalCfg.RestorePath + policy.Metadata["policyName"] + ".yaml"); err == nil { + if policyBytes, err := yl.Marshal(policy); err == nil { if _, err = file.Write(policyBytes); err == nil { if err := file.Close(); err != nil { dm.Logger.Errf(err.Error()) @@ -730,30 +732,35 @@ func (dm *KubeArmorDaemon) backupKubeArmorContainerPolicy(policy tp.SecurityPoli } func (dm *KubeArmorDaemon) restoreKubeArmorPolicies() { - if _, err := os.Stat(cfg.PolicyDir); err != nil { - kg.Warn("Policies dir not found for restoration") - return + if _, err := os.Stat(cfg.GlobalCfg.RestorePath); err != nil { + if err = os.MkdirAll(cfg.GlobalCfg.RestorePath, 0700); err != nil { + kg.Warnf("Dir creation failed for [%v], setting restore path to %s", cfg.GlobalCfg.RestorePath, cfg.PolicyDir) + cfg.GlobalCfg.RestorePath = cfg.PolicyDir + return + } else { + } } - // List all policies files from "/opt/kubearmor/policies" path - if policyFiles, err := os.ReadDir(cfg.PolicyDir); err == nil { + // List all policies files from RestorePath variable + if policyFiles, err := os.ReadDir(cfg.GlobalCfg.RestorePath); err == nil { for _, file := range policyFiles { - if data, err := os.ReadFile(cfg.PolicyDir + file.Name()); err == nil { + if data, err := os.ReadFile(cfg.GlobalCfg.RestorePath + file.Name()); err == nil { var k struct { + Kind string `json:"kind"` Metadata map[string]string `json:"metadata"` } - err := json.Unmarshal(data, &k) + err := yl.Unmarshal(data, &k) if err != nil { kg.Errf("Failed to unmarshal policy: %v", err) continue } - if _, ok := k.Metadata["namespaceName"]; ok { // ContainerPolicy contains namespaceName + if k.Kind == KubeArmorPolicy { // ContainerPolicy contains namespaceName var containerPolicy tp.K8sKubeArmorPolicy - if err := json.Unmarshal(data, &containerPolicy); err == nil { - containerPolicy.Metadata.Name = k.Metadata["policyName"] + if err := yl.Unmarshal(data, &containerPolicy); err == nil { + containerPolicy.Metadata.Name = k.Metadata["name"] dm.ParseAndUpdateContainerSecurityPolicy(tp.K8sKubeArmorPolicyEvent{ Type: "ADDED", Object: containerPolicy, @@ -762,8 +769,8 @@ func (dm *KubeArmorDaemon) restoreKubeArmorPolicies() { } else { // HostSecurityPolicy var hostPolicy tp.K8sKubeArmorHostPolicy - if err := json.Unmarshal(data, &hostPolicy); err == nil { - hostPolicy.Metadata.Name = k.Metadata["policyName"] + if err := yl.Unmarshal(data, &hostPolicy); err == nil { + hostPolicy.Metadata.Name = k.Metadata["name"] dm.ParseAndUpdateHostSecurityPolicy(tp.K8sKubeArmorHostPolicyEvent{ Type: "ADDED", Object: hostPolicy, @@ -784,7 +791,7 @@ func (dm *KubeArmorDaemon) restoreKubeArmorPolicies() { // removeBackUpPolicy Function func (dm *KubeArmorDaemon) removeBackUpPolicy(name string) { - fname := cfg.PolicyDir + name + ".yaml" + fname := cfg.GlobalCfg.RestorePath + name + ".yaml" // Check for "/opt/kubearmor/policies" path. If dir not found, create the same if _, err := os.Stat(fname); err != nil { kg.Printf("Backup policy [%v] not exist", fname) diff --git a/KubeArmor/go.mod b/KubeArmor/go.mod index 583eaa810..d22d9ee25 100644 --- a/KubeArmor/go.mod +++ b/KubeArmor/go.mod @@ -30,6 +30,7 @@ require ( github.com/containerd/containerd v1.7.13 github.com/containerd/typeurl/v2 v2.1.1 github.com/docker/docker v25.0.5+incompatible + github.com/fsnotify/fsnotify v1.7.0 github.com/golang/protobuf v1.5.4 github.com/google/uuid v1.6.0 github.com/kubearmor/KubeArmor/pkg/KubeArmorController v0.0.0-20240110164432-c2c1b121cd94 @@ -48,6 +49,7 @@ require ( k8s.io/klog/v2 v2.120.0 k8s.io/utils v0.0.0-20240310230437-4693a0247e57 sigs.k8s.io/controller-runtime v0.15.3 + sigs.k8s.io/yaml v1.4.0 ) require ( @@ -64,7 +66,6 @@ require ( github.com/emicklei/go-restful/v3 v3.11.2 // indirect github.com/evanphx/json-patch/v5 v5.7.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect @@ -132,5 +133,4 @@ require ( k8s.io/kube-openapi v0.0.0-20240105020646-a37d4de58910 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect )