diff --git a/KubeArmor/config/config.go b/KubeArmor/config/config.go index 4a71d8700c..1a667f95a9 100644 --- a/KubeArmor/config/config.go +++ b/KubeArmor/config/config.go @@ -245,6 +245,7 @@ func LoadConfig() error { if cfgfile == "" { cfgfile = "kubearmor.yaml" } + if _, err := os.Stat(cfgfile); err == nil { kg.Printf("setting config from file [%s]", cfgfile) viper.SetConfigFile(cfgfile) @@ -254,6 +255,8 @@ func LoadConfig() error { } } + kg.Printf("Configuration [%+v]", GlobalCfg) + GlobalCfg.Cluster = viper.GetString(ConfigCluster) GlobalCfg.Host = viper.GetString(ConfigHost) if hostname, err := os.Hostname(); GlobalCfg.Host == "" && err == nil { @@ -275,9 +278,6 @@ func LoadConfig() error { return fmt.Errorf("CRI socket must start with 'unix://' (%s is invalid)", GlobalCfg.CRISocket) } - GlobalCfg.Visibility = viper.GetString(ConfigVisibility) - GlobalCfg.HostVisibility = viper.GetString(ConfigHostVisibility) - GlobalCfg.Policy = viper.GetBool(ConfigKubearmorPolicy) GlobalCfg.HostPolicy = viper.GetBool(ConfigKubearmorHostPolicy) GlobalCfg.KVMAgent = viper.GetBool(ConfigKubearmorVM) @@ -285,29 +285,11 @@ func LoadConfig() error { GlobalCfg.Debug = viper.GetBool(ConfigDebug) - GlobalCfg.DefaultFilePosture = viper.GetString(ConfigDefaultFilePosture) - GlobalCfg.DefaultNetworkPosture = viper.GetString(ConfigDefaultNetworkPosture) - GlobalCfg.DefaultCapabilitiesPosture = viper.GetString(ConfigDefaultCapabilitiesPosture) - - GlobalCfg.HostDefaultFilePosture = viper.GetString(ConfigHostDefaultFilePosture) - GlobalCfg.HostDefaultNetworkPosture = viper.GetString(ConfigHostDefaultNetworkPosture) - GlobalCfg.HostDefaultCapabilitiesPosture = viper.GetString(ConfigHostDefaultCapabilitiesPosture) - - kg.Printf("Configuration [%+v]", GlobalCfg) - if GlobalCfg.KVMAgent { GlobalCfg.Policy = false GlobalCfg.HostPolicy = true } - if GlobalCfg.HostVisibility == "default" { - if GlobalCfg.KVMAgent || (!GlobalCfg.K8sEnv && GlobalCfg.HostPolicy) { - GlobalCfg.HostVisibility = "process,file,network,capabilities" - } else { // k8s - GlobalCfg.HostVisibility = "none" - } - } - GlobalCfg.CoverageTest = viper.GetBool(ConfigCoverageTest) GlobalCfg.ConfigUntrackedNs = strings.Split(viper.GetString(ConfigUntrackedNs), ",") @@ -316,22 +298,46 @@ func LoadConfig() error { GlobalCfg.BPFFsPath = viper.GetString(BPFFsPath) - GlobalCfg.EnforcerAlerts = viper.GetBool(EnforcerAlerts) - - GlobalCfg.DefaultPostureLogs = viper.GetBool(ConfigDefaultPostureLogs) - GlobalCfg.InitTimeout = viper.GetString(ConfigInitTimeout) GlobalCfg.StateAgent = viper.GetBool(ConfigStateAgent) - GlobalCfg.AlertThrottling = viper.GetBool(ConfigAlertThrottling) - GlobalCfg.MaxAlertPerSec = int32(viper.GetInt(ConfigMaxAlertPerSec)) - GlobalCfg.ThrottleSec = int32(viper.GetInt(ConfigThrottleSec)) GlobalCfg.AnnotateResources = viper.GetBool(ConfigAnnotateResources) GlobalCfg.ProcFsMount = viper.GetString(ConfigProcFsMount) + LoadDynamicConfig() + kg.Printf("Final Configuration [%+v]", GlobalCfg) return nil } + +// LoadDynamicConfig set dynamic configuration which can be updated at runtime without restarting kubearmor +func LoadDynamicConfig() { + GlobalCfg.DefaultFilePosture = viper.GetString(ConfigDefaultFilePosture) + GlobalCfg.DefaultNetworkPosture = viper.GetString(ConfigDefaultNetworkPosture) + GlobalCfg.DefaultCapabilitiesPosture = viper.GetString(ConfigDefaultCapabilitiesPosture) + + GlobalCfg.HostDefaultFilePosture = viper.GetString(ConfigHostDefaultFilePosture) + GlobalCfg.HostDefaultNetworkPosture = viper.GetString(ConfigHostDefaultNetworkPosture) + GlobalCfg.HostDefaultCapabilitiesPosture = viper.GetString(ConfigHostDefaultCapabilitiesPosture) + + GlobalCfg.Visibility = viper.GetString(ConfigVisibility) + GlobalCfg.HostVisibility = viper.GetString(ConfigHostVisibility) + + if GlobalCfg.HostVisibility == "default" { + if GlobalCfg.KVMAgent || (!GlobalCfg.K8sEnv && GlobalCfg.HostPolicy) { + GlobalCfg.HostVisibility = "process,file,network,capabilities" + } else { // k8s + GlobalCfg.HostVisibility = "none" + } + } + + GlobalCfg.EnforcerAlerts = viper.GetBool(EnforcerAlerts) + GlobalCfg.DefaultPostureLogs = viper.GetBool(ConfigDefaultPostureLogs) + + GlobalCfg.AlertThrottling = viper.GetBool(ConfigAlertThrottling) + GlobalCfg.MaxAlertPerSec = int32(viper.GetInt(ConfigMaxAlertPerSec)) + GlobalCfg.ThrottleSec = int32(viper.GetInt(ConfigThrottleSec)) +} diff --git a/KubeArmor/core/kubeArmor.go b/KubeArmor/core/kubeArmor.go index 051842b819..e86991de70 100644 --- a/KubeArmor/core/kubeArmor.go +++ b/KubeArmor/core/kubeArmor.go @@ -413,6 +413,8 @@ func KubeArmor() { dm.Node.KernelVersion = kl.GetCommandOutputWithoutErr("uname", []string{"-r"}) dm.Node.KernelVersion = strings.TrimSuffix(dm.Node.KernelVersion, "\n") + dm.WatchConfigChanges() + dm.NodeLock.Unlock() } else if cfg.GlobalCfg.K8sEnv { diff --git a/KubeArmor/core/unorchestratedUpdates.go b/KubeArmor/core/unorchestratedUpdates.go index 3038bdb3b0..13f3a0fce5 100644 --- a/KubeArmor/core/unorchestratedUpdates.go +++ b/KubeArmor/core/unorchestratedUpdates.go @@ -5,6 +5,8 @@ package core import ( "encoding/json" + "github.com/fsnotify/fsnotify" + "github.com/spf13/viper" "os" "regexp" "sort" @@ -38,6 +40,50 @@ func (dm *KubeArmorDaemon) SetContainerNSVisibility() { dm.UpdateVisibility("ADDED", "container_namespace", visibility) } +// =================== // +// == Config Update == // +// =================== // + +// WatchConfigChanges watches for configuration changes and updates the default posture +func (dm *KubeArmorDaemon) WatchConfigChanges() { + viper.OnConfigChange(func(e fsnotify.Event) { + dm.Logger.Printf("Config file changed: %s", e.Name) + cfg.LoadDynamicConfig() + + // Update the default posture + globalPosture := tp.DefaultPosture{ + FileAction: validateGlobalDefaultPosture(cfg.GlobalCfg.DefaultFilePosture), + NetworkAction: validateGlobalDefaultPosture(cfg.GlobalCfg.DefaultNetworkPosture), + CapabilitiesAction: validateGlobalDefaultPosture(cfg.GlobalCfg.DefaultCapabilitiesPosture), + } + // Update the visibility + visibility := tp.Visibility{ + File: dm.validateVisibility("file", cfg.GlobalCfg.Visibility), + Process: dm.validateVisibility("process", cfg.GlobalCfg.Visibility), + Network: dm.validateVisibility("network", cfg.GlobalCfg.Visibility), + Capabilities: dm.validateVisibility("capabilities", cfg.GlobalCfg.Visibility), + } + + // Apply the changes to the daemon + dm.UpdateGlobalPosture(globalPosture) + + // Update default posture for endpoints + for _, ep := range dm.EndPoints { + dm.Logger.Printf("Updating Default Posture for endpoint %s", ep.EndPointName) + dm.UpdateDefaultPosture("MODIFIED", ep.NamespaceName, globalPosture, false) + dm.UpdateVisibility("MODIFIED", ep.NamespaceName, visibility) + } + + // Update throttling configs + dm.SystemMonitor.UpdateThrottlingConfig() + + // Update the default posture and visibility for the unorchestrated containers + dm.SystemMonitor.UpdateVisibility() + dm.UpdateHostSecurityPolicies() + }) + viper.WatchConfig() +} + // ====================================== // // == Container Security Policy Update == // // ====================================== // diff --git a/KubeArmor/go.mod b/KubeArmor/go.mod index 583eaa8103..76362e622b 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 @@ -64,7 +65,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