From 9abb9d2f9ef1a852547526969e58974f072f1c29 Mon Sep 17 00:00:00 2001 From: Jaehyun Nam Date: Mon, 6 Jun 2022 11:13:40 +0000 Subject: [PATCH] update default posture and audit mode Signed-off-by: Jaehyun Nam --- KubeArmor/config/config.go | 31 +- KubeArmor/core/kubeUpdate.go | 14 +- KubeArmor/enforcer/appArmorEnforcer.go | 6 +- KubeArmor/enforcer/appArmorHostProfile.go | 26 +- KubeArmor/enforcer/appArmorProfile.go | 58 +- KubeArmor/feeder/policyMatcher.go | 667 +++++++++--------- contribution/k3s/install_k3s.sh | 6 +- contribution/vagrant/Vagrantfile | 9 +- tests/scenarios/github_test_05/cmd2 | 4 +- tests/scenarios/github_test_06/cmd2 | 4 +- tests/scenarios/github_test_06/cmd3 | 4 +- tests/scenarios/github_test_06/cmd4 | 4 +- .../cmd1 | 4 +- .../ksp-ubuntu-1-net-icmp-audit.yaml | 2 +- .../cmd1 | 0 .../cmd2 | 2 +- .../ksp-ubuntu-1-cap-net-raw-block.yaml | 2 +- tests/scenarios/github_test_11/cmd1 | 2 +- tests/scenarios/github_test_11/cmd2 | 2 +- tests/scenarios/github_test_12/cmd2 | 4 +- tests/scenarios/github_test_12/cmd3 | 4 +- tests/scenarios/github_test_14/cmd1 | 2 +- tests/scenarios/multiubuntu_test_08/cmd2 | 4 +- tests/scenarios/multiubuntu_test_09/cmd2 | 4 +- tests/scenarios/multiubuntu_test_10/cmd1 | 2 +- tests/scenarios/multiubuntu_test_10/cmd2 | 2 +- tests/scenarios/multiubuntu_test_14/cmd1 | 4 +- tests/scenarios/multiubuntu_test_17/cmd2 | 4 +- tests/scenarios/multiubuntu_test_19/cmd2 | 4 +- tests/scenarios/multiubuntu_test_19/cmd3 | 4 +- tests/scenarios/multiubuntu_test_21/cmd2 | 4 +- tests/scenarios/multiubuntu_test_22/cmd2 | 4 +- tests/scenarios/multiubuntu_test_22/cmd3 | 4 +- tests/scenarios/multiubuntu_test_22/cmd4 | 4 +- tests/scenarios/multiubuntu_test_28/cmd1 | 2 +- tests/test-scenarios-github.sh | 66 +- tests/test-scenarios-in-runtime.sh | 82 ++- tests/test-scenarios-local.sh | 80 ++- 38 files changed, 627 insertions(+), 504 deletions(-) rename tests/scenarios/{FAILING_IN_GHA_github_test_09 => github_test_09}/cmd1 (65%) rename tests/scenarios/{FAILING_IN_GHA_github_test_09 => github_test_09}/ksp-ubuntu-1-net-icmp-audit.yaml (85%) rename tests/scenarios/{FAILING_IN_GHA_github_test_10 => github_test_10}/cmd1 (100%) rename tests/scenarios/{FAILING_IN_GHA_github_test_10 => github_test_10}/cmd2 (78%) rename tests/scenarios/{FAILING_IN_GHA_github_test_10 => github_test_10}/ksp-ubuntu-1-cap-net-raw-block.yaml (70%) diff --git a/KubeArmor/config/config.go b/KubeArmor/config/config.go index 09e20136c8..f0d1ea0d81 100644 --- a/KubeArmor/config/config.go +++ b/KubeArmor/config/config.go @@ -35,6 +35,10 @@ type KubearmorConfig struct { DefaultNetworkPosture string // Default Enforcement Action in Global Network Context DefaultCapabilitiesPosture string // Default Enforcement Action in Global Capabilities Context + HostDefaultFilePosture string // Default Enforcement Action in Global File Context + HostDefaultNetworkPosture string // Default Enforcement Action in Global Network Context + HostDefaultCapabilitiesPosture string // Default Enforcement Action in Global Capabilities Context + CoverageTest bool // Enable/Disable Coverage Test } @@ -83,6 +87,15 @@ const ConfigDefaultNetworkPosture string = "defaultNetworkPosture" // ConfigDefaultCapabilitiesPosture KubeArmor Default Global Capabilities Posture key const ConfigDefaultCapabilitiesPosture string = "defaultCapabilitiesPosture" +// ConfigHostDefaultFilePosture KubeArmor Default Global File Posture key +const ConfigHostDefaultFilePosture string = "hostDefaultFilePosture" + +// ConfigHostDefaultNetworkPosture KubeArmor Default Global Network Posture key +const ConfigHostDefaultNetworkPosture string = "hostDefaultNetworkPosture" + +// ConfigHostDefaultCapabilitiesPosture KubeArmor Default Global Capabilities Posture key +const ConfigHostDefaultCapabilitiesPosture string = "hostDefaultCapabilitiesPosture" + // ConfigCoverageTest Coverage Test key const ConfigCoverageTest string = "coverageTest" @@ -106,9 +119,13 @@ func readCmdLineParams() { kvmAgentB := flag.Bool(ConfigKubearmorVM, false, "enabling KubeArmorVM") k8sEnvB := flag.Bool(ConfigK8sEnv, true, "is k8s env?") - defaultFilePosture := flag.String(ConfigDefaultFilePosture, "block", "configuring default enforcement action in global file context [audit,block]") - defaultNetworkPosture := flag.String(ConfigDefaultNetworkPosture, "block", "configuring default enforcement action in global network context [audit,block]") - defaultCapabilitiesPosture := flag.String(ConfigDefaultCapabilitiesPosture, "block", "configuring default enforcement action in global capability context [audit,block]") + defaultFilePosture := flag.String(ConfigDefaultFilePosture, "block", "configuring default enforcement action in global file context {allow|audit|block}") + defaultNetworkPosture := flag.String(ConfigDefaultNetworkPosture, "block", "configuring default enforcement action in global network context {allow|audit|block}") + defaultCapabilitiesPosture := flag.String(ConfigDefaultCapabilitiesPosture, "block", "configuring default enforcement action in global capability context {allow|audit|block}") + + hostDefaultFilePosture := flag.String(ConfigHostDefaultFilePosture, "block", "configuring default enforcement action in global file context {allow|audit|block}") + hostDefaultNetworkPosture := flag.String(ConfigHostDefaultNetworkPosture, "block", "configuring default enforcement action in global network context {allow|audit|block}") + hostDefaultCapabilitiesPosture := flag.String(ConfigHostDefaultCapabilitiesPosture, "block", "configuring default enforcement action in global capability context {allow|audit|block}") coverageTestB := flag.Bool(ConfigCoverageTest, false, "enabling CoverageTest") @@ -140,6 +157,10 @@ func readCmdLineParams() { viper.SetDefault(ConfigDefaultNetworkPosture, *defaultNetworkPosture) viper.SetDefault(ConfigDefaultCapabilitiesPosture, *defaultCapabilitiesPosture) + viper.SetDefault(ConfigHostDefaultFilePosture, *hostDefaultFilePosture) + viper.SetDefault(ConfigHostDefaultNetworkPosture, *hostDefaultNetworkPosture) + viper.SetDefault(ConfigHostDefaultCapabilitiesPosture, *hostDefaultCapabilitiesPosture) + viper.SetDefault(ConfigCoverageTest, *coverageTestB) } @@ -185,6 +206,10 @@ func LoadConfig() error { 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 { diff --git a/KubeArmor/core/kubeUpdate.go b/KubeArmor/core/kubeUpdate.go index 3c5ed087f9..eac45fa699 100644 --- a/KubeArmor/core/kubeUpdate.go +++ b/KubeArmor/core/kubeUpdate.go @@ -515,15 +515,7 @@ func (dm *KubeArmorDaemon) WatchK8sPods() { // exception: kubernetes app if pod.Metadata["namespaceName"] == "kube-system" { - if _, ok := pod.Labels["k8s-app"]; ok { - pod.Annotations["kubearmor-policy"] = "audited" - } - - if value, ok := pod.Labels["component"]; ok { - if value == "etcd" || value == "kube-apiserver" || value == "kube-controller-manager" || value == "kube-scheduler" { - pod.Annotations["kubearmor-policy"] = "audited" - } - } + pod.Annotations["kubearmor-policy"] = "audited" } // exception: cilium-operator @@ -1704,6 +1696,8 @@ func (dm *KubeArmorDaemon) UpdateDefaultPosture(action string, namespace string, dm.DefaultPostures[namespace] = defaultPosture + dm.Logger.UpdateDefaultPosture(action, namespace, defaultPosture) + for idx, endPoint := range dm.EndPoints { // update a security policy if namespace == endPoint.NamespaceName { @@ -1711,8 +1705,6 @@ func (dm *KubeArmorDaemon) UpdateDefaultPosture(action string, namespace string, continue } - dm.Logger.UpdateDefaultPosture(action, namespace, defaultPosture) - dm.EndPoints[idx].DefaultPosture = defaultPosture dm.Logger.Printf("Updating default posture for %s with %v/%v", endPoint.EndPointName, dm.EndPoints[idx].DefaultPosture, dm.DefaultPostures[namespace]) diff --git a/KubeArmor/enforcer/appArmorEnforcer.go b/KubeArmor/enforcer/appArmorEnforcer.go index 97f9a1d7ea..430f31c72c 100644 --- a/KubeArmor/enforcer/appArmorEnforcer.go +++ b/KubeArmor/enforcer/appArmorEnforcer.go @@ -527,9 +527,9 @@ func (ae *AppArmorEnforcer) UpdateSecurityPolicies(endPoint tp.EndPoint) { // UpdateAppArmorHostProfile Function func (ae *AppArmorEnforcer) UpdateAppArmorHostProfile(secPolicies []tp.HostSecurityPolicy) { globalDefaultPosture := tp.DefaultPosture{ - FileAction: cfg.GlobalCfg.DefaultFilePosture, - NetworkAction: cfg.GlobalCfg.DefaultNetworkPosture, - CapabilitiesAction: cfg.GlobalCfg.DefaultCapabilitiesPosture, + FileAction: cfg.GlobalCfg.HostDefaultFilePosture, + NetworkAction: cfg.GlobalCfg.HostDefaultNetworkPosture, + CapabilitiesAction: cfg.GlobalCfg.HostDefaultCapabilitiesPosture, } if policyCount, newProfile, ok := ae.GenerateAppArmorHostProfile(secPolicies, globalDefaultPosture); ok { diff --git a/KubeArmor/enforcer/appArmorHostProfile.go b/KubeArmor/enforcer/appArmorHostProfile.go index 71bb653118..61415d346d 100644 --- a/KubeArmor/enforcer/appArmorHostProfile.go +++ b/KubeArmor/enforcer/appArmorHostProfile.go @@ -685,36 +685,46 @@ func (ae *AppArmorEnforcer) GenerateHostProfileBody(securityPolicies []tp.HostSe capability := true for _, line := range lines { - if strings.Contains(line, " network") { + if strings.Contains(line, " network") { // matchProtocols + allow network = false continue } - if strings.Contains(line, " capability") { + if strings.Contains(line, " capability") { // matchCapabilities + allow capability = false continue } - if strings.Contains(line, " owner") && strings.Contains(line, "deny") { + if strings.Contains(line, " owner") && strings.Contains(line, "deny") { // ownerOnly + block continue } - if strings.Contains(line, " deny") { + if strings.Contains(line, " deny") { // block continue } - file = false + file = false // matchPaths or matchDirectories + allow } - if file { + if defaultPosture.FileAction == "block" && file { + // if defaultPosture == block and there is at least one fromSource-based allow policy, block others (by the same source) + // hoever, if defaultPosture == block and there is no fromSource-based allow policy, allow others as usual + bodyFromSource = bodyFromSource + " file,\n" + } else if defaultPosture.FileAction != "block" { + // if defaultPosture == audit, audit others (= allow others) (by the same source) + // if defaultPosture == allow, skip (ignore) allow policies while still enforcing block policies bodyFromSource = bodyFromSource + " file,\n" } - if network { + if defaultPosture.NetworkAction == "block" && network { + bodyFromSource = bodyFromSource + " network,\n" + } else if defaultPosture.NetworkAction != "block" { bodyFromSource = bodyFromSource + " network,\n" } - if capability { + if defaultPosture.CapabilitiesAction == "block" && capability { + bodyFromSource = bodyFromSource + " capability,\n" + } else if defaultPosture.CapabilitiesAction != "block" { bodyFromSource = bodyFromSource + " capability,\n" } diff --git a/KubeArmor/enforcer/appArmorProfile.go b/KubeArmor/enforcer/appArmorProfile.go index a3ec7e1fae..843b1eda1e 100644 --- a/KubeArmor/enforcer/appArmorProfile.go +++ b/KubeArmor/enforcer/appArmorProfile.go @@ -675,21 +675,25 @@ func (ae *AppArmorEnforcer) GenerateProfileHead(numProcessWhiteList, numFileWhit profileHead := " #include \n" profileHead = profileHead + " umount,\n" - if defaultPosture.FileAction == "block" && !(numProcessWhiteList > 0 || numFileWhiteList > 0 || !fromSourceFile) { + if defaultPosture.FileAction == "block" && (numProcessWhiteList+numFileWhiteList == 0 && fromSourceFile) { + // if defaultPosture == block and there is at least one (fromSource-based) allow policy, block others + // hoever, if defaultPosture == block and there is no (fromSource-based) allow policy, allow others as usual profileHead = profileHead + " file,\n" - } else if numProcessWhiteList == 0 && numFileWhiteList == 0 { + } else if defaultPosture.FileAction != "block" { + // if defaultPosture == audit, audit others (= allow others) + // if defaultPosture == allow, skip (ignore) allow policies while still enforcing block policies profileHead = profileHead + " file,\n" } - if defaultPosture.NetworkAction == "block" && !(numNetworkWhiteList > 0 || !fromSourceNetwork) { + if defaultPosture.NetworkAction == "block" && (numNetworkWhiteList == 0 && fromSourceNetwork) { profileHead = profileHead + " network,\n" - } else if numNetworkWhiteList == 0 { + } else if defaultPosture.NetworkAction != "block" { profileHead = profileHead + " network,\n" } - if defaultPosture.CapabilitiesAction == "block" && !(numCapabilityWhiteList > 0 || !fromSourceCapability) { + if defaultPosture.CapabilitiesAction == "block" && (numCapabilityWhiteList == 0 && fromSourceCapability) { profileHead = profileHead + " capability,\n" - } else if numCapabilityWhiteList == 0 { + } else if defaultPosture.CapabilitiesAction != "block" { profileHead = profileHead + " capability,\n" } @@ -762,7 +766,7 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo if len(secPolicy.Spec.Process.MatchPaths) > 0 { for _, path := range secPolicy.Spec.Process.MatchPaths { - if path.Action == "Allow" { + if path.Action == "Allow" && defaultPosture.FileAction == "block" { ae.AllowedProcessMatchPaths(path, &processWhiteList, fromSources) } else if path.Action == "Block" { ae.BlockedProcessMatchPaths(path, &processBlackList, fromSources) @@ -771,7 +775,7 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo } if len(secPolicy.Spec.Process.MatchDirectories) > 0 { for _, dir := range secPolicy.Spec.Process.MatchDirectories { - if dir.Action == "Allow" { + if dir.Action == "Allow" && defaultPosture.FileAction == "block" { ae.AllowedProcessMatchDirectories(dir, &processWhiteList, fromSources) } else if dir.Action == "Block" { ae.BlockedProcessMatchDirectories(dir, &processBlackList, fromSources) @@ -780,7 +784,7 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo } if len(secPolicy.Spec.Process.MatchPatterns) > 0 { for _, pat := range secPolicy.Spec.Process.MatchPatterns { - if pat.Action == "Allow" { + if pat.Action == "Allow" && defaultPosture.FileAction == "block" { ae.AllowedProcessMatchPatterns(pat, &processWhiteList) } else if pat.Action == "Block" { ae.BlockedProcessMatchPatterns(pat, &processBlackList) @@ -790,7 +794,7 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo if len(secPolicy.Spec.File.MatchPaths) > 0 { for _, path := range secPolicy.Spec.File.MatchPaths { - if path.Action == "Allow" { + if path.Action == "Allow" && defaultPosture.FileAction == "block" { ae.AllowedFileMatchPaths(path, &fileWhiteList, fromSources) } else if path.Action == "Block" { ae.BlockedFileMatchPaths(path, &fileBlackList, fromSources) @@ -799,7 +803,7 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo } if len(secPolicy.Spec.File.MatchDirectories) > 0 { for _, dir := range secPolicy.Spec.File.MatchDirectories { - if dir.Action == "Allow" { + if dir.Action == "Allow" && defaultPosture.FileAction == "block" { ae.AllowedFileMatchDirectories(dir, &fileWhiteList, fromSources) } else if dir.Action == "Block" { ae.BlockedFileMatchDirectories(dir, &fileBlackList, fromSources) @@ -808,7 +812,7 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo } if len(secPolicy.Spec.File.MatchPatterns) > 0 { for _, pat := range secPolicy.Spec.File.MatchPatterns { - if pat.Action == "Allow" { + if pat.Action == "Allow" && defaultPosture.FileAction == "block" { ae.AllowedFileMatchPatterns(pat, &fileWhiteList) } else if pat.Action == "Block" { ae.BlockedFileMatchPatterns(pat, &fileBlackList) @@ -818,7 +822,7 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo if len(secPolicy.Spec.Network.MatchProtocols) > 0 { for _, proto := range secPolicy.Spec.Network.MatchProtocols { - if proto.Action == "Allow" { + if proto.Action == "Allow" && defaultPosture.NetworkAction == "block" { ae.AllowedNetworkMatchProtocols(proto, &networkWhiteList, fromSources) } else if proto.Action == "Block" { ae.BlockedNetworkMatchProtocols(proto, &networkBlackList, fromSources) @@ -828,7 +832,7 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo if len(secPolicy.Spec.Capabilities.MatchCapabilities) > 0 { for _, cap := range secPolicy.Spec.Capabilities.MatchCapabilities { - if cap.Action == "Allow" { + if cap.Action == "Allow" && defaultPosture.CapabilitiesAction == "block" { ae.AllowedCapabilitiesMatchCapabilities(cap, &capabilityWhiteList, fromSources) } else if cap.Action == "Block" { ae.BlockedCapabilitiesMatchCapabilities(cap, &capabilityBlackList, fromSources) @@ -916,45 +920,49 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo capability := true for _, line := range lines { - if strings.Contains(line, " network") { + if strings.Contains(line, " network") { // matchProtocols + allow network = false fromSourceNetwork = false continue } - if strings.Contains(line, " capability") { + if strings.Contains(line, " capability") { // matchCapabilities + allow capability = false fromSourceCapability = false continue } - if strings.Contains(line, " owner") && strings.Contains(line, "deny") { + if strings.Contains(line, " owner") && strings.Contains(line, "deny") { // ownerOnly + block continue } - if strings.Contains(line, " deny") { + if strings.Contains(line, " deny") { // block continue } - file = false + file = false // matchPaths or matchDirectories + allow fromSourceFile = false } - if defaultPosture.FileAction == "block" && !(numProcessWhiteList > 0 || numFileWhiteList > 0 || !file) { + if defaultPosture.FileAction == "block" && (numProcessWhiteList == 0 && numFileWhiteList == 0 && file) { + // if defaultPosture == block and there is at least one (fromSource-based) allow policy, block others + // hoever, if defaultPosture == block and there is no (fromSource-based) allow policy, allow others as usual bodyFromSource = bodyFromSource + " file,\n" - } else if file { + } else if defaultPosture.FileAction != "block" { + // if defaultPosture == audit, audit others (= allow others) + // if defaultPosture == allow, skip (ignore) allow policies while still enforcing block policies bodyFromSource = bodyFromSource + " file,\n" } - if defaultPosture.NetworkAction == "block" && !(numNetworkWhiteList > 0 || !network) { + if defaultPosture.NetworkAction == "block" && (numNetworkWhiteList == 0 && network) { bodyFromSource = bodyFromSource + " network,\n" - } else if network { + } else if defaultPosture.NetworkAction != "block" { bodyFromSource = bodyFromSource + " network,\n" } - if defaultPosture.CapabilitiesAction == "block" && !(numCapabilityWhiteList > 0 || !capability) { + if defaultPosture.CapabilitiesAction == "block" && (numCapabilityWhiteList == 0 && capability) { bodyFromSource = bodyFromSource + " capability,\n" - } else if capability { + } else if defaultPosture.CapabilitiesAction != "block" { bodyFromSource = bodyFromSource + " capability,\n" } diff --git a/KubeArmor/feeder/policyMatcher.go b/KubeArmor/feeder/policyMatcher.go index c684cbfa4b..f4cc8c363d 100644 --- a/KubeArmor/feeder/policyMatcher.go +++ b/KubeArmor/feeder/policyMatcher.go @@ -11,7 +11,6 @@ import ( "strings" "syscall" - kl "github.com/kubearmor/KubeArmor/KubeArmor/common" cfg "github.com/kubearmor/KubeArmor/KubeArmor/config" tp "github.com/kubearmor/KubeArmor/KubeArmor/types" ) @@ -24,11 +23,11 @@ import ( func getProtocolFromName(proto string) string { switch strings.ToLower(proto) { case "tcp": - return "protocol=TCP" + return "protocol=TCP,type=SOCK_STREAM" case "udp": - return "protocol=UDP" + return "protocol=UDP,type=SOCK_DGRAM" case "icmp": - return "protocol=ICMP" + return "protocol=ICMP,type=SOCK_RAW" case "raw": return "type=SOCK_RAW" default: @@ -690,33 +689,31 @@ func (fd *Feeder) UpdateDefaultPosture(action string, namespace string, defaultP } // Update Log Fields based on default posture and visibility configuration and return false if no updates -func setLogFields(log *tp.Log, action string, considerPosture, visibility, containerLog bool) bool { - if considerPosture && action == "block" { - if containerLog { - (*log).Type = "MatchedPolicy" - } else { - (*log).Type = "MatchedHostPolicy" - } - (*log).PolicyName = "DefaultPosture" - (*log).Action = "Block" - return true - } else if considerPosture && action == "audit" { - if containerLog { +func setLogFields(log *tp.Log, defaultPosture string, visibility, containerEvent bool) bool { + if defaultPosture == "audit" && (*log).Result == "Passed" { + if containerEvent { (*log).Type = "MatchedPolicy" } else { (*log).Type = "MatchedHostPolicy" } + (*log).PolicyName = "DefaultPosture" + (*log).Enforcer = "eBPF Monitor" (*log).Action = "Audit" + return true - } else if visibility { - if containerLog { + } + + if visibility { + if containerEvent { (*log).Type = "ContainerLog" } else { (*log).Type = "HostLog" } + return true } + return false } @@ -725,33 +722,15 @@ func setLogFields(log *tp.Log, action string, considerPosture, visibility, conta // ==================== // func getDirectoryPart(path string) string { - dirs := strings.Split(path, "/") - if len(dirs) > 1 { - return strings.Join(dirs[0:len(dirs)-2], "/") + dir := filepath.Dir(path) + if strings.HasPrefix(dir, "/") { + return dir + "/" } - return "__no_directory__" + return "__not_absolute_path__" } // UpdateMatchedPolicy Function func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { - allowProcPolicy := "" - allowProcPolicySeverity := "" - allowProcTags := []string{} - allowProcMessage := "" - - allowFilePolicy := "" - allowFilePolicySeverity := "" - allowFileTags := []string{} - allowFileMessage := "" - - allowNetworkPolicy := "" - allowNetworkPolicySeverity := "" - allowNetworkTags := []string{} - allowNetworkMessage := "" - - considerFilePosture := false - considerNetworkPosture := false - if log.Result == "Passed" || log.Result == "Operation not permitted" || log.Result == "Permission denied" { fd.SecurityPoliciesLock.RLock() @@ -763,160 +742,235 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { secPolicies := fd.SecurityPolicies[key].Policies for _, secPolicy := range secPolicies { - firstLogSource := strings.Replace(strings.Split(log.Source, " ")[0], "./", "", 1) - firstLogResource := strings.Replace(strings.Split(log.Resource, " ")[0], "./", "", 1) - - if strings.Contains(secPolicy.Action, "Allow") { - if secPolicy.Source == "" || (secPolicy.IsFromSource && - ((secPolicy.Operation == "Process" && (secPolicy.Source == log.ParentProcessName || secPolicy.Source == log.ProcessName)) || // ./bash -> xxx || ./bash -c xxx - (secPolicy.Operation != "Process" && (secPolicy.Source == log.ProcessName || strings.Contains(secPolicy.Source, firstLogSource))))) { - - if secPolicy.Operation == "Process" { - if allowProcPolicy == "" { - allowProcPolicy = secPolicy.PolicyName - allowProcPolicySeverity = secPolicy.Severity - - for _, tag := range secPolicy.Tags { - if !kl.ContainsElement(allowProcTags, tag) { - allowProcTags = append(allowProcTags, tag) - } + if fd.DefaultPostures[log.NamespaceName].FileAction == "allow" && (secPolicy.Action == "Allow" || secPolicy.Action == "Audit (Allow)") { + continue + } + + firstLogResource := strings.Split(log.Resource, " ")[0] + firstLogResourceDir := getDirectoryPart(firstLogResource) + firstLogResourceDirCount := strings.Count(firstLogResourceDir, "/") + + switch log.Operation { + case "Process", "File": + if secPolicy.Operation != log.Operation { + continue + } + + // match sources + if (!secPolicy.IsFromSource) || (secPolicy.IsFromSource && (secPolicy.Source == log.ParentProcessName || secPolicy.Source == log.ProcessName)) { + matchedRegex := false + + switch secPolicy.ResourceType { + case "Glob": + // Match using a globbing syntax very similar to the AppArmor's + matchedRegex, _ = filepath.Match(secPolicy.Resource, log.Resource) // pattern (secPolicy.Resource) -> string (log.Resource) + case "Regexp": + if secPolicy.Regexp != nil { + // Match using compiled regular expression + matchedRegex = secPolicy.Regexp.MatchString(log.Resource) // regexp (secPolicy.Regexp) -> string (log.Resource) + } + } + + // match resources + if matchedRegex || (secPolicy.ResourceType == "Path" && secPolicy.Resource == firstLogResource) || + (secPolicy.ResourceType == "Directory" && strings.HasPrefix(firstLogResourceDir, secPolicy.Resource) && + ((!secPolicy.Recursive && firstLogResourceDirCount == strings.Count(secPolicy.Resource, "/")) || + (secPolicy.Recursive && firstLogResourceDirCount >= strings.Count(secPolicy.Resource, "/")))) { + + matchedFlags := false + + if secPolicy.ReadOnly && log.Resource != "" && secPolicy.OwnerOnly && log.MergedDir != "" { + // read only && owner only + if strings.Contains(log.Data, "O_RDONLY") && strconv.Itoa(int(log.UID)) == getFileProcessUID(log.MergedDir+log.Resource) { + matchedFlags = true + } + } else if secPolicy.ReadOnly && log.Resource != "" { + // read only + if strings.Contains(log.Data, "O_RDONLY") { + matchedFlags = true + } + } else if secPolicy.OwnerOnly && log.MergedDir != "" { + // owner only + if strconv.Itoa(int(log.UID)) == getFileProcessUID(log.MergedDir+log.Resource) { + matchedFlags = true } + } else { + // ! read only && ! owner only + matchedFlags = true + } - allowProcMessage = secPolicy.Message - } else if !strings.Contains(allowProcPolicy, secPolicy.PolicyName) { - allowProcPolicy = allowProcPolicy + "," + secPolicy.PolicyName - allowProcPolicySeverity = allowProcPolicySeverity + "," + secPolicy.Severity + if matchedFlags && (secPolicy.Action == "Allow" || secPolicy.Action == "Audit (Allow)") && log.Result == "Passed" { + // allow policy or allow policy with audit mode + // matched source + matched resource + matched flags + matched action + expected result -> going to be skipped - for _, tag := range secPolicy.Tags { - if !kl.ContainsElement(allowProcTags, tag) { - allowProcTags = append(allowProcTags, tag) - } + log.Type = "MatchedPolicy" + + log.PolicyName = secPolicy.PolicyName + log.Severity = secPolicy.Severity + + if len(secPolicy.Tags) > 0 { + log.Tags = strings.Join(secPolicy.Tags[:], ",") } - allowProcMessage = allowProcMessage + "," + secPolicy.Message - } - } else if secPolicy.Operation == "File" { - if allowFilePolicy == "" { - allowFilePolicy = secPolicy.PolicyName - allowFilePolicySeverity = secPolicy.Severity - - for _, tag := range secPolicy.Tags { - if !kl.ContainsElement(allowFileTags, tag) { - allowFileTags = append(allowFileTags, tag) - } + if len(secPolicy.Message) > 0 { + log.Message = secPolicy.Message } - allowFileMessage = secPolicy.Message - } else if !strings.Contains(allowFilePolicy, secPolicy.PolicyName) { - allowFilePolicy = allowFilePolicy + "," + secPolicy.PolicyName - allowFilePolicySeverity = allowFilePolicySeverity + "," + secPolicy.Severity + if log.PolicyEnabled == tp.KubeArmorPolicyAudited { + log.Enforcer = "eBPF Monitor" + } else { + log.Enforcer = fd.Enforcer + } - for _, tag := range secPolicy.Tags { - if !kl.ContainsElement(allowFileTags, tag) { - allowFileTags = append(allowFileTags, tag) - } + log.Action = "Allow" + + continue + } + + if matchedFlags && secPolicy.Action == "Audit" && log.Result == "Passed" { + // audit policy + // matched source + matched resource + matched flags + matched action + expected result -> alert (audit log) + + log.Type = "MatchedPolicy" + + log.PolicyName = secPolicy.PolicyName + log.Severity = secPolicy.Severity + + if len(secPolicy.Tags) > 0 { + log.Tags = strings.Join(secPolicy.Tags[:], ",") + } + + if len(secPolicy.Message) > 0 { + log.Message = secPolicy.Message } - allowFileMessage = allowFileMessage + "," + secPolicy.Message + log.Enforcer = "eBPF Monitor" + log.Action = secPolicy.Action + + continue } - } else if secPolicy.Operation == "Network" { - if allowNetworkPolicy == "" { - allowNetworkPolicy = secPolicy.PolicyName - allowNetworkPolicySeverity = secPolicy.Severity - - for _, tag := range secPolicy.Tags { - if !kl.ContainsElement(allowNetworkTags, tag) { - allowNetworkTags = append(allowNetworkTags, tag) - } + + if (secPolicy.Action == "Block" && log.Result != "Passed") || + (matchedFlags && (!secPolicy.OwnerOnly && !secPolicy.ReadOnly) && secPolicy.Action == "Audit (Block)" && log.Result == "Passed") || + (!matchedFlags && (secPolicy.OwnerOnly || secPolicy.ReadOnly) && secPolicy.Action == "Audit (Block)" && log.Result == "Passed") { + // block policy or block policy with audit mode + // matched source + matched resource + matched action + expected result -> alert + + log.Type = "MatchedPolicy" + + log.PolicyName = secPolicy.PolicyName + log.Severity = secPolicy.Severity + + if len(secPolicy.Tags) > 0 { + log.Tags = strings.Join(secPolicy.Tags[:], ",") } - allowNetworkMessage = secPolicy.Message - } else if !strings.Contains(allowNetworkPolicy, secPolicy.PolicyName) { - allowNetworkPolicy = allowNetworkPolicy + "," + secPolicy.PolicyName - allowNetworkPolicySeverity = allowNetworkPolicySeverity + "," + secPolicy.Severity + if len(secPolicy.Message) > 0 { + log.Message = secPolicy.Message + } - for _, tag := range secPolicy.Tags { - if !kl.ContainsElement(allowNetworkTags, tag) { - allowNetworkTags = append(allowNetworkTags, tag) - } + if log.PolicyEnabled == tp.KubeArmorPolicyAudited { + log.Enforcer = "eBPF Monitor" + } else { + log.Enforcer = fd.Enforcer } - allowNetworkMessage = allowNetworkMessage + "," + secPolicy.Message + log.Action = secPolicy.Action + + continue } } - } - } - switch log.Operation { - case "Process", "File": - if secPolicy.Operation == log.Operation { - matched := false + if secPolicy.Action == "Allow" && log.Result != "Passed" { + // matched source + !(matched resource) + action = allow + result = blocked -> default posture / allow policy violation - switch secPolicy.ResourceType { - case "Glob": - // Match using a globbing syntax very similar to the AppArmor's - matched, _ = filepath.Match(secPolicy.Resource, log.Resource) // pattern (secPolicy.Resource) -> string (log.Resource) - case "Regexp": - if secPolicy.Regexp != nil { - // Match using compiled regular expression - matched = secPolicy.Regexp.MatchString(log.Resource) // regexp (secPolicy.Regexp) -> string (log.Resource) + log.Type = "MatchedPolicy" + + log.PolicyName = "DefaultPosture" + + log.Severity = "" + log.Tags = "" + log.Message = "" + + log.Enforcer = "eBPF Monitor" + log.Action = "Block" + + continue + } + + if secPolicy.Action == "Audit (Allow)" && log.Result == "Passed" { + // matched source + !(matched resource) + action = audit (allow) + result = passed -> default posture / allow policy violation (audit mode) + + log.Type = "MatchedPolicy" + + log.PolicyName = "DefaultPosture" + + log.Severity = "" + log.Tags = "" + log.Message = "" + + log.Enforcer = "eBPF Monitor" + + if fd.DefaultPostures[log.NamespaceName].FileAction == "block" { + log.Action = "Audit (Block)" + } else { // fd.DefaultPostures[log.NamespaceName].FileAction == "audit" + log.Action = "Audit" } + + continue } + } - if secPolicy.Source == "" || (secPolicy.IsFromSource && - ((secPolicy.Operation == "Process" && (secPolicy.Source == log.ParentProcessName || secPolicy.Source == log.ProcessName)) || // ./bash -> xxx || ./bash -c xxx - (secPolicy.Operation == "File" && (secPolicy.Source == log.ProcessName || strings.Contains(secPolicy.Source, firstLogSource))))) { - - if matched || - (secPolicy.ResourceType == "Path" && secPolicy.Resource == log.Resource) || // exact path match - (secPolicy.ResourceType == "Path" && strings.HasSuffix(secPolicy.Resource, firstLogResource)) || // file name match - (secPolicy.ResourceType == "Directory" && strings.HasPrefix(log.Resource, secPolicy.Resource)) || // exact directory match (non-recursive and recursive) - (secPolicy.ResourceType == "Directory" && strings.HasSuffix(secPolicy.Resource, getDirectoryPart(firstLogResource))) { // surffix match (non-recurisve) - - matchedFlags := false - - if (secPolicy.Action == "Audit" && log.Result == "Passed") || (log.PolicyEnabled == tp.KubeArmorPolicyAudited && strings.Contains(secPolicy.Action, "Allow")) { - if secPolicy.ReadOnly && log.Resource != "" && secPolicy.OwnerOnly && log.MergedDir != "" { - // read only && owner only - if strings.Contains(log.Data, "O_RDONLY") && strconv.Itoa(int(log.UID)) == getFileProcessUID(log.MergedDir+log.Resource) { - matchedFlags = true - } - } else if secPolicy.ReadOnly && log.Resource != "" { - // read only - if strings.Contains(log.Data, "O_RDONLY") { - matchedFlags = true - } - } else if secPolicy.OwnerOnly && log.MergedDir != "" { - // owner only - if strconv.Itoa(int(log.UID)) == getFileProcessUID(log.MergedDir+log.Resource) { - matchedFlags = true - } - } else { - // ! read only && ! owner only - matchedFlags = true - } + if fd.DefaultPostures[log.NamespaceName].FileAction == "block" && secPolicy.Action == "Audit (Allow)" && log.Result == "Passed" { + // defaultPosture = block + audit mode - } else if log.PolicyEnabled == tp.KubeArmorPolicyAudited && strings.Contains(secPolicy.Action, "Block") { - if secPolicy.ReadOnly && log.Resource != "" && secPolicy.OwnerOnly && log.MergedDir != "" { - // read only && owner only - if strings.Contains(log.Data, "O_RDONLY") && strconv.Itoa(int(log.UID)) == getFileProcessUID(log.MergedDir+log.Resource) { - matchedFlags = true - } - } else if secPolicy.ReadOnly && log.Resource != "" { - // read only - if strings.Contains(log.Data, "O_RDONLY") { - matchedFlags = true - } - } else if secPolicy.OwnerOnly && log.MergedDir != "" { - // owner only - if strconv.Itoa(int(log.UID)) == getFileProcessUID(log.MergedDir+log.Resource) { - matchedFlags = true - } - } - // otherwise, being supposed to be blocked - } + log.Type = "MatchedPolicy" + + log.PolicyName = "DefaultPosture" + + log.Severity = "" + log.Tags = "" + log.Message = "" + + log.Enforcer = "eBPF Monitor" + log.Action = "Audit (Block)" + } + + if fd.DefaultPostures[log.NamespaceName].FileAction == "audit" && (secPolicy.Action == "Allow" || secPolicy.Action == "Audit (Allow)") && log.Result == "Passed" { + // defaultPosture = audit + + log.Type = "MatchedPolicy" + + log.PolicyName = "DefaultPosture" + + log.Severity = "" + log.Tags = "" + log.Message = "" + + log.Enforcer = "eBPF Monitor" + log.Action = "Audit" + } + + case "Network": + if secPolicy.Operation != log.Operation { + continue + } + + // match sources + if (!secPolicy.IsFromSource) || (secPolicy.IsFromSource && (secPolicy.Source == log.ParentProcessName || secPolicy.Source == log.ProcessName)) { + skip := false + + for _, matchProtocol := range strings.Split(secPolicy.Resource, ",") { + if skip { + break + } + + // match resources + if strings.Contains(log.Resource, matchProtocol) { + if (secPolicy.Action == "Allow" || secPolicy.Action == "Audit (Allow)") && log.Result == "Passed" { + // allow policy or allow policy with audit mode + // matched source + matched resource + matched action + expected result -> going to be skipped - if (matchedFlags && secPolicy.Action == "Audit" && log.Result == "Passed") || (!matchedFlags && log.PolicyEnabled == tp.KubeArmorPolicyAudited && (strings.Contains(secPolicy.Action, "Allow") || strings.Contains(secPolicy.Action, "Block"))) { log.Type = "MatchedPolicy" log.PolicyName = secPolicy.PolicyName @@ -930,18 +984,22 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { log.Message = secPolicy.Message } - if secPolicy.Action == "Audit" || log.PolicyEnabled == tp.KubeArmorPolicyAudited { + if log.PolicyEnabled == tp.KubeArmorPolicyAudited { log.Enforcer = "eBPF Monitor" } else { log.Enforcer = fd.Enforcer } - log.Action = secPolicy.Action + log.Action = "Allow" + skip = true continue } - if log.PolicyEnabled == tp.KubeArmorPolicyEnabled && log.Result != "Passed" { + if secPolicy.Action == "Audit" && log.Result == "Passed" { + // audit policy + // matched source + matched resource + matched action + expected result -> alert (audit log) + log.Type = "MatchedPolicy" log.PolicyName = secPolicy.PolicyName @@ -955,21 +1013,18 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { log.Message = secPolicy.Message } - log.Enforcer = fd.Enforcer + log.Enforcer = "eBPF Monitor" log.Action = secPolicy.Action + skip = true continue } - } - } - } - case "Network": - if secPolicy.Operation == log.Operation { - if secPolicy.Source == "" || (secPolicy.IsFromSource && (secPolicy.Source == log.ProcessName || strings.Contains(secPolicy.Source, firstLogSource))) { - if strings.Contains(log.Resource, secPolicy.Resource) { + if (secPolicy.Action == "Block" && log.Result != "Passed") || + (secPolicy.Action == "Audit (Block)" && log.Result == "Passed") { + // block policy or block policy with audit mode + // matched source + matched resource + matched action + expected result -> alert - if (log.PolicyEnabled == tp.KubeArmorPolicyEnabled && log.Result != "Passed") || (secPolicy.Action == "Audit" && log.Result == "Passed") || (log.PolicyEnabled == tp.KubeArmorPolicyAudited && strings.Contains(secPolicy.Action, "Block")) { log.Type = "MatchedPolicy" log.PolicyName = secPolicy.PolicyName @@ -983,7 +1038,7 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { log.Message = secPolicy.Message } - if secPolicy.Action == "Audit" || log.PolicyEnabled == tp.KubeArmorPolicyAudited { + if log.PolicyEnabled == tp.KubeArmorPolicyAudited { log.Enforcer = "eBPF Monitor" } else { log.Enforcer = fd.Enforcer @@ -991,106 +1046,112 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { log.Action = secPolicy.Action + skip = true continue } } } - } - } - } - fd.SecurityPoliciesLock.RUnlock() + if skip { + continue + } - if log.Result == "Operation not permitted" || log.Result == "Permission denied" { - if log.Operation == "Process" && allowProcPolicy == "" { - considerFilePosture = true - } else if log.Operation == "File" && allowFilePolicy == "" { - considerFilePosture = true - } else if log.Operation == "Network" && allowNetworkPolicy == "" { - considerNetworkPosture = true - } - } - } + if secPolicy.Action == "Allow" && log.Result != "Passed" { + // matched source + !(matched resource) + action = allow + result = blocked -> allow policy violation - if log.ContainerID != "" { // container - if log.Type == "" { - if (log.PolicyEnabled == tp.KubeArmorPolicyEnabled && log.Result != "Passed") || (log.PolicyEnabled == tp.KubeArmorPolicyAudited) { - if log.Operation == "Process" && allowProcPolicy != "" { - log.Type = "MatchedPolicy" + log.Type = "MatchedPolicy" - log.PolicyName = allowProcPolicy - log.Severity = allowProcPolicySeverity + log.PolicyName = "DefaultPosture" - if len(allowProcTags) > 0 { - log.Tags = strings.Join(allowProcTags[:], ",") - } + log.Severity = "" + log.Tags = "" + log.Message = "" - if len(allowProcMessage) > 0 { - log.Message = allowProcMessage - } - - if log.PolicyEnabled == tp.KubeArmorPolicyAudited { log.Enforcer = "eBPF Monitor" - log.Action = "Audit (Allow)" - } else { - log.Enforcer = fd.Enforcer - log.Action = "Allow" - } + log.Action = "Block" - return log + continue + } - } else if log.Operation == "File" && allowFilePolicy != "" { - log.Type = "MatchedPolicy" + if secPolicy.Action == "Audit (Allow)" && log.Result == "Passed" { + // matched source + !(matched resource) + action = audit (allow) + result = passed -> allow policy violation (audit mode) - log.PolicyName = allowFilePolicy - log.Severity = allowFilePolicySeverity + log.Type = "MatchedPolicy" - if len(allowFileTags) > 0 { - log.Tags = strings.Join(allowFileTags[:], ",") - } + log.PolicyName = "DefaultPosture" - if len(allowFileMessage) > 0 { - log.Message = allowFileMessage - } + log.Severity = "" + log.Tags = "" + log.Message = "" - if log.PolicyEnabled == tp.KubeArmorPolicyAudited { log.Enforcer = "eBPF Monitor" - log.Action = "Audit (Allow)" - } else { - log.Enforcer = fd.Enforcer - log.Action = "Allow" + + if fd.DefaultPostures[log.NamespaceName].NetworkAction == "block" { + log.Action = "Audit (Block)" + } else { // fd.DefaultPostures[log.NamespaceName].NetworkAction == "audit" + log.Action = "Audit" + } + + continue } + } - return log + if fd.DefaultPostures[log.NamespaceName].NetworkAction == "block" && secPolicy.Action == "Audit (Allow)" && log.Result == "Passed" { + // defaultPosture = block + audit mode - } else if log.Operation == "Network" && allowNetworkPolicy != "" { log.Type = "MatchedPolicy" - log.PolicyName = allowNetworkPolicy - log.Severity = allowNetworkPolicySeverity + log.PolicyName = "DefaultPosture" - if len(allowNetworkTags) > 0 { - log.Tags = strings.Join(allowNetworkTags[:], ",") - } + log.Severity = "" + log.Tags = "" + log.Message = "" - if len(allowNetworkMessage) > 0 { - log.Message = allowNetworkMessage - } + log.Enforcer = "eBPF Monitor" + log.Action = "Audit (Block)" + } - if log.PolicyEnabled == tp.KubeArmorPolicyAudited { - log.Enforcer = "eBPF Monitor" - log.Action = "Audit (Allow)" - } else { - log.Enforcer = fd.Enforcer - log.Action = "Allow" - } + if fd.DefaultPostures[log.NamespaceName].NetworkAction == "audit" && (secPolicy.Action == "Allow" || secPolicy.Action == "Audit (Allow)") && log.Result == "Passed" { + // defaultPosture = audit - return log + log.Type = "MatchedPolicy" + + log.PolicyName = "DefaultPosture" + + log.Severity = "" + log.Tags = "" + log.Message = "" + + log.Enforcer = "eBPF Monitor" + log.Action = "Audit" } } + } + + fd.SecurityPoliciesLock.RUnlock() + + if log.PolicyName == "" && log.Result != "Passed" { + // default posture (block) or native policy + // no matched policy, but result = blocked -> default posture + + log.Type = "MatchedPolicy" + + log.PolicyName = "DefaultPosture" + + log.Severity = "" + log.Tags = "" + log.Message = "" + + log.Enforcer = fd.Enforcer + log.Action = "Block" + } + } + + if log.ContainerID != "" { // container + if log.Type == "" { + // defaultPosture (audit) or container log fd.DefaultPosturesLock.Lock() - defer fd.DefaultPosturesLock.Unlock() if _, ok := fd.DefaultPostures[log.NamespaceName]; !ok { globalDefaultPosture := tp.DefaultPosture{ @@ -1101,20 +1162,22 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { fd.DefaultPostures[log.NamespaceName] = globalDefaultPosture } + fd.DefaultPosturesLock.Unlock() + if log.Operation == "Process" { - if setLogFields(&log, fd.DefaultPostures[log.NamespaceName].FileAction, considerFilePosture, log.ProcessVisibilityEnabled, true) { + if setLogFields(&log, fd.DefaultPostures[log.NamespaceName].FileAction, log.ProcessVisibilityEnabled, true) { return log } } else if log.Operation == "File" { - if setLogFields(&log, fd.DefaultPostures[log.NamespaceName].FileAction, considerFilePosture, log.FileVisibilityEnabled, true) { + if setLogFields(&log, fd.DefaultPostures[log.NamespaceName].FileAction, log.FileVisibilityEnabled, true) { return log } } else if log.Operation == "Network" { - if setLogFields(&log, fd.DefaultPostures[log.NamespaceName].NetworkAction, considerNetworkPosture, log.NetworkVisibilityEnabled, true) { + if setLogFields(&log, fd.DefaultPostures[log.NamespaceName].NetworkAction, log.NetworkVisibilityEnabled, true) { return log } } else if log.Operation == "Capabilities" { - if setLogFields(&log, fd.DefaultPostures[log.NamespaceName].CapabilitiesAction, false, log.CapabilitiesVisibilityEnabled, true) { + if setLogFields(&log, fd.DefaultPostures[log.NamespaceName].CapabilitiesAction, log.CapabilitiesVisibilityEnabled, true) { return log } } @@ -1123,109 +1186,27 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { if log.Action == "Allow" && log.Result == "Passed" { return tp.Log{} } + return log } } else { // host if log.Type == "" { - if (log.PolicyEnabled == tp.KubeArmorPolicyEnabled && log.Result != "Passed") || (log.PolicyEnabled == tp.KubeArmorPolicyAudited) { - if log.Operation == "Process" && allowProcPolicy != "" { - log.Type = "MatchedHostPolicy" - - log.PolicyName = allowProcPolicy - log.Severity = allowProcPolicySeverity - - if len(allowProcTags) > 0 { - log.Tags = strings.Join(allowProcTags[:], ",") - } - - if len(allowProcMessage) > 0 { - log.Message = allowProcMessage - } - - if log.PolicyEnabled == tp.KubeArmorPolicyAudited { - log.Enforcer = "eBPF Monitor" - log.Action = "Audit (Allow)" - } else { - log.Enforcer = fd.Enforcer - log.Action = "Allow" - } - - return log - - } else if log.Operation == "File" && allowFilePolicy != "" { - log.Type = "MatchedHostPolicy" - - log.PolicyName = allowFilePolicy - log.Severity = allowFilePolicySeverity - - if len(allowFileTags) > 0 { - log.Tags = strings.Join(allowFileTags[:], ",") - } - - if len(allowFileMessage) > 0 { - log.Message = allowFileMessage - } - - if log.PolicyEnabled == tp.KubeArmorPolicyAudited { - log.Enforcer = "eBPF Monitor" - log.Action = "Audit (Allow)" - } else { - log.Enforcer = fd.Enforcer - log.Action = "Allow" - } - - return log - - } else if log.Operation == "Network" && allowNetworkPolicy != "" { - log.Type = "MatchedHostPolicy" - - log.PolicyName = allowNetworkPolicy - log.Severity = allowNetworkPolicySeverity - - if len(allowNetworkTags) > 0 { - log.Tags = strings.Join(allowNetworkTags[:], ",") - } - - if len(allowNetworkMessage) > 0 { - log.Message = allowNetworkMessage - } - - if log.PolicyEnabled == tp.KubeArmorPolicyAudited { - log.Enforcer = "eBPF Monitor" - log.Action = "Audit (Allow)" - } else { - log.Enforcer = fd.Enforcer - log.Action = "Allow" - } - - return log - } - } - - if log.Result == "Operation not permitted" || log.Result == "Permission denied" { - if log.Operation == "Process" && allowProcPolicy == "" { - considerFilePosture = true - } else if log.Operation == "File" && allowFilePolicy == "" { - considerFilePosture = true - } else if log.Operation == "Network" && allowNetworkPolicy == "" { - considerNetworkPosture = true - } - } + // host log if log.Operation == "Process" { - if setLogFields(&log, "block", considerFilePosture, fd.Node.ProcessVisibilityEnabled, false) { + if setLogFields(&log, "allow", fd.Node.ProcessVisibilityEnabled, false) { return log } } else if log.Operation == "File" { - if setLogFields(&log, "block", considerFilePosture, fd.Node.FileVisibilityEnabled, false) { + if setLogFields(&log, "allow", fd.Node.FileVisibilityEnabled, false) { return log } } else if log.Operation == "Network" { - if setLogFields(&log, "block", considerNetworkPosture, fd.Node.NetworkVisibilityEnabled, false) { + if setLogFields(&log, "allow", fd.Node.NetworkVisibilityEnabled, false) { return log } } else if log.Operation == "Capabilities" { - if setLogFields(&log, "block", false, fd.Node.CapabilitiesVisibilityEnabled, false) { + if setLogFields(&log, "allow", fd.Node.CapabilitiesVisibilityEnabled, false) { return log } } diff --git a/contribution/k3s/install_k3s.sh b/contribution/k3s/install_k3s.sh index 7f2abc5802..b02583a484 100755 --- a/contribution/k3s/install_k3s.sh +++ b/contribution/k3s/install_k3s.sh @@ -21,6 +21,7 @@ if [[ $(hostname) = kubearmor-dev* ]]; then mkdir -p /home/vagrant/.kube sudo cp /etc/rancher/k3s/k3s.yaml /home/vagrant/.kube/config sudo chown -R vagrant:vagrant /home/vagrant/.kube + echo "export KUBECONFIG=/home/vagrant/.kube/config" | tee -a /home/vagrant/.bashrc else KUBEDIR=$HOME/.kube KUBECONFIG=$KUBEDIR/config @@ -31,6 +32,7 @@ else fi sudo cp /etc/rancher/k3s/k3s.yaml $KUBECONFIG sudo chown $USER:$USER $KUBECONFIG + echo "export KUBECONFIG=$KUBECONFIG" | tee -a ~/.bashrc fi echo "wait for initialization" @@ -38,10 +40,10 @@ sleep 15 for (( ; ; )) do - status=$(kubectl get pods -A -o jsonpath={.items[*].status.phase}) + status=$(/usr/local/bin/kubectl get pods -A -o jsonpath={.items[*].status.phase}) [[ $(echo $status | grep -v Running | wc -l) -eq 0 ]] && break echo "wait for initialization" sleep 1 done -kubectl get pods -A +/usr/local/bin/kubectl get pods -A diff --git a/contribution/vagrant/Vagrantfile b/contribution/vagrant/Vagrantfile index 213f12c070..8446700687 100644 --- a/contribution/vagrant/Vagrantfile +++ b/contribution/vagrant/Vagrantfile @@ -92,10 +92,10 @@ Vagrant.configure("2") do |config| if ENV['RUNTIME'] != "k3s" then # initialize Kubernetes config.vm.provision :shell, :inline => "CNI=cilium MASTER=true /home/vagrant/KubeArmor/contribution/self-managed-k8s-selinux/k8s/initialize_kubernetes.sh" - end - # enable SELinux - config.vm.provision :shell, path: kubearmor_home + "/contribution/self-managed-k8s-selinux/enable_selinux.sh" + # enable SELinux + config.vm.provision :shell, path: kubearmor_home + "/contribution/self-managed-k8s-selinux/enable_selinux.sh" + end else # ubuntu # install base dependencies @@ -127,9 +127,6 @@ Vagrant.configure("2") do |config| end end - # install karmor - config.vm.provision :shell, :inline => "curl -sfL https://raw.githubusercontent.com/kubearmor/kubearmor-client/main/install.sh | sudo sh -s -- -b /usr/local/bin latest" - # change permissions config.vm.provision :shell, :inline => "mkdir -p /home/vagrant/go; chown -R vagrant:vagrant /home/vagrant/go" diff --git a/tests/scenarios/github_test_05/cmd2 b/tests/scenarios/github_test_05/cmd2 index 2a35604c67..8e2251f64d 100644 --- a/tests/scenarios/github_test_05/cmd2 +++ b/tests/scenarios/github_test_05/cmd2 @@ -1,7 +1,7 @@ source: ubuntu-1-deployment cmd: cat /etc/hosts -result: failed +result: default --- operation: File condition: /etc/hosts -action: Allow +action: default diff --git a/tests/scenarios/github_test_06/cmd2 b/tests/scenarios/github_test_06/cmd2 index 377a773ab7..1c0f6fb6dc 100644 --- a/tests/scenarios/github_test_06/cmd2 +++ b/tests/scenarios/github_test_06/cmd2 @@ -1,7 +1,7 @@ source: ubuntu-1-deployment cmd: su - user1 -c "echo test >> /home/user1/secret_data1.txt" -result: failed +result: default --- operation: File condition: /home/user1/secret_data1.txt -action: Allow +action: default diff --git a/tests/scenarios/github_test_06/cmd3 b/tests/scenarios/github_test_06/cmd3 index 51b4e54f48..a28ec016d0 100644 --- a/tests/scenarios/github_test_06/cmd3 +++ b/tests/scenarios/github_test_06/cmd3 @@ -1,7 +1,7 @@ source: ubuntu-1-deployment cmd: cat /home/user1/secret_data1.txt -result: failed +result: default --- operation: File condition: /home/user1/secret_data1.txt -action: Allow +action: default diff --git a/tests/scenarios/github_test_06/cmd4 b/tests/scenarios/github_test_06/cmd4 index e51d4b5385..d814d41f0f 100644 --- a/tests/scenarios/github_test_06/cmd4 +++ b/tests/scenarios/github_test_06/cmd4 @@ -1,7 +1,7 @@ source: ubuntu-1-deployment cmd: echo test >> /home/user1/secret_data1.txt -result: failed +result: default --- operation: File condition: /home/user1/secret_data1.txt -action: Allow +action: default diff --git a/tests/scenarios/FAILING_IN_GHA_github_test_09/cmd1 b/tests/scenarios/github_test_09/cmd1 similarity index 65% rename from tests/scenarios/FAILING_IN_GHA_github_test_09/cmd1 rename to tests/scenarios/github_test_09/cmd1 index 3937ec820f..fc203f3312 100644 --- a/tests/scenarios/FAILING_IN_GHA_github_test_09/cmd1 +++ b/tests/scenarios/github_test_09/cmd1 @@ -1,7 +1,7 @@ source: ubuntu-1-deployment -cmd: ping -c 1 8.8.8.8 +cmd: ping -c 1 127.0.0.1 result: passed --- operation: Network -condition: SOCK_RAW +condition: ICMP action: Audit diff --git a/tests/scenarios/FAILING_IN_GHA_github_test_09/ksp-ubuntu-1-net-icmp-audit.yaml b/tests/scenarios/github_test_09/ksp-ubuntu-1-net-icmp-audit.yaml similarity index 85% rename from tests/scenarios/FAILING_IN_GHA_github_test_09/ksp-ubuntu-1-net-icmp-audit.yaml rename to tests/scenarios/github_test_09/ksp-ubuntu-1-net-icmp-audit.yaml index 5efc3ca59f..68a2559773 100644 --- a/tests/scenarios/FAILING_IN_GHA_github_test_09/ksp-ubuntu-1-net-icmp-audit.yaml +++ b/tests/scenarios/github_test_09/ksp-ubuntu-1-net-icmp-audit.yaml @@ -10,6 +10,6 @@ spec: container: ubuntu-1 network: matchProtocols: - - protocol: icmp # try 'ping 8.8.8.8' + - protocol: icmp action: Audit diff --git a/tests/scenarios/FAILING_IN_GHA_github_test_10/cmd1 b/tests/scenarios/github_test_10/cmd1 similarity index 100% rename from tests/scenarios/FAILING_IN_GHA_github_test_10/cmd1 rename to tests/scenarios/github_test_10/cmd1 diff --git a/tests/scenarios/FAILING_IN_GHA_github_test_10/cmd2 b/tests/scenarios/github_test_10/cmd2 similarity index 78% rename from tests/scenarios/FAILING_IN_GHA_github_test_10/cmd2 rename to tests/scenarios/github_test_10/cmd2 index 377b08f655..9264401795 100644 --- a/tests/scenarios/FAILING_IN_GHA_github_test_10/cmd2 +++ b/tests/scenarios/github_test_10/cmd2 @@ -1,5 +1,5 @@ source: ubuntu-1-deployment -cmd: ping -c 1 8.8.8.8 +cmd: arping -c 1 127.0.0.1 result: failed --- operation: Network diff --git a/tests/scenarios/FAILING_IN_GHA_github_test_10/ksp-ubuntu-1-cap-net-raw-block.yaml b/tests/scenarios/github_test_10/ksp-ubuntu-1-cap-net-raw-block.yaml similarity index 70% rename from tests/scenarios/FAILING_IN_GHA_github_test_10/ksp-ubuntu-1-cap-net-raw-block.yaml rename to tests/scenarios/github_test_10/ksp-ubuntu-1-cap-net-raw-block.yaml index 960b24eb01..45bc100d45 100644 --- a/tests/scenarios/FAILING_IN_GHA_github_test_10/ksp-ubuntu-1-cap-net-raw-block.yaml +++ b/tests/scenarios/github_test_10/ksp-ubuntu-1-cap-net-raw-block.yaml @@ -10,6 +10,6 @@ spec: container: ubuntu-1 capabilities: matchCapabilities: - - capability: net_raw # try 'ping 8.8.8.8' (operation not permitted) and 'curl www.kubearmor.com' (success) + - capability: net_raw action: Block diff --git a/tests/scenarios/github_test_11/cmd1 b/tests/scenarios/github_test_11/cmd1 index 751a25b3c4..e7d3cf9712 100644 --- a/tests/scenarios/github_test_11/cmd1 +++ b/tests/scenarios/github_test_11/cmd1 @@ -1,6 +1,6 @@ source: ubuntu-1-deployment cmd: cat /etc/shells -result: failed +result: default --- operation: File condition: /etc/shells diff --git a/tests/scenarios/github_test_11/cmd2 b/tests/scenarios/github_test_11/cmd2 index 351ab50255..6379845145 100644 --- a/tests/scenarios/github_test_11/cmd2 +++ b/tests/scenarios/github_test_11/cmd2 @@ -1,6 +1,6 @@ source: ubuntu-1-deployment cmd: cat /etc/hostname -result: failed +result: default --- operation: File condition: /etc/hostname diff --git a/tests/scenarios/github_test_12/cmd2 b/tests/scenarios/github_test_12/cmd2 index 0558fa201e..138a0a3be4 100644 --- a/tests/scenarios/github_test_12/cmd2 +++ b/tests/scenarios/github_test_12/cmd2 @@ -1,7 +1,7 @@ source: ubuntu-1-deployment cmd: curl google.com -result: failed +result: default --- operation: Network condition: SOCK_DGRAM -action: Block +action: default diff --git a/tests/scenarios/github_test_12/cmd3 b/tests/scenarios/github_test_12/cmd3 index c6017dfdb1..c534d6c2c3 100644 --- a/tests/scenarios/github_test_12/cmd3 +++ b/tests/scenarios/github_test_12/cmd3 @@ -1,7 +1,7 @@ source: ubuntu-1-deployment cmd: wget --tries=1 142.250.193.46 -result: passed +result: default --- operation: Network condition: SOCK_STREAM -action: Allow +action: default diff --git a/tests/scenarios/github_test_14/cmd1 b/tests/scenarios/github_test_14/cmd1 index d3241f23c4..9264401795 100644 --- a/tests/scenarios/github_test_14/cmd1 +++ b/tests/scenarios/github_test_14/cmd1 @@ -1,5 +1,5 @@ source: ubuntu-1-deployment -cmd: ping -c 1 127.0.0.1 +cmd: arping -c 1 127.0.0.1 result: failed --- operation: Network diff --git a/tests/scenarios/multiubuntu_test_08/cmd2 b/tests/scenarios/multiubuntu_test_08/cmd2 index dc6786608a..19f07571c3 100644 --- a/tests/scenarios/multiubuntu_test_08/cmd2 +++ b/tests/scenarios/multiubuntu_test_08/cmd2 @@ -1,7 +1,7 @@ source: ubuntu-3-deployment cmd: cat /etc/hostname -result: failed +result: default --- operation: File condition: /etc/hostname -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_09/cmd2 b/tests/scenarios/multiubuntu_test_09/cmd2 index 6029c362ee..a61b201e2a 100644 --- a/tests/scenarios/multiubuntu_test_09/cmd2 +++ b/tests/scenarios/multiubuntu_test_09/cmd2 @@ -1,7 +1,7 @@ source: ubuntu-4-deployment cmd: echo test >> /credentials/password -result: failed +result: default --- operation: File condition: /credentials/password -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_10/cmd1 b/tests/scenarios/multiubuntu_test_10/cmd1 index bc9f59c016..7f1a3b2662 100644 --- a/tests/scenarios/multiubuntu_test_10/cmd1 +++ b/tests/scenarios/multiubuntu_test_10/cmd1 @@ -1,6 +1,6 @@ source: ubuntu-2-deployment cmd: cat /etc/shells -result: failed +result: default --- operation: File condition: /etc/shells diff --git a/tests/scenarios/multiubuntu_test_10/cmd2 b/tests/scenarios/multiubuntu_test_10/cmd2 index d33134c6bc..77f575265b 100644 --- a/tests/scenarios/multiubuntu_test_10/cmd2 +++ b/tests/scenarios/multiubuntu_test_10/cmd2 @@ -1,6 +1,6 @@ source: ubuntu-3-deployment cmd: cat /etc/hostname -result: failed +result: default --- operation: File condition: /etc/hostname diff --git a/tests/scenarios/multiubuntu_test_14/cmd1 b/tests/scenarios/multiubuntu_test_14/cmd1 index 94693f178f..87220408ff 100644 --- a/tests/scenarios/multiubuntu_test_14/cmd1 +++ b/tests/scenarios/multiubuntu_test_14/cmd1 @@ -1,7 +1,7 @@ source: ubuntu-3-deployment cmd: /home/user1/hello -result: failed +result: default --- operation: Process condition: /home/user1/hello -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_17/cmd2 b/tests/scenarios/multiubuntu_test_17/cmd2 index 17a593924c..87cd83af00 100644 --- a/tests/scenarios/multiubuntu_test_17/cmd2 +++ b/tests/scenarios/multiubuntu_test_17/cmd2 @@ -1,7 +1,7 @@ source: ubuntu-4-deployment cmd: cat /etc/hosts -result: failed +result: default --- operation: File condition: /etc/hosts -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_19/cmd2 b/tests/scenarios/multiubuntu_test_19/cmd2 index e280688287..1d194d7e76 100644 --- a/tests/scenarios/multiubuntu_test_19/cmd2 +++ b/tests/scenarios/multiubuntu_test_19/cmd2 @@ -1,7 +1,7 @@ source: ubuntu-4-deployment cmd: /readwrite -w /credentials/password -result: failed +result: default --- operation: File condition: /credentials/password -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_19/cmd3 b/tests/scenarios/multiubuntu_test_19/cmd3 index a516d5ad02..6beac3387d 100644 --- a/tests/scenarios/multiubuntu_test_19/cmd3 +++ b/tests/scenarios/multiubuntu_test_19/cmd3 @@ -1,7 +1,7 @@ source: ubuntu-4-deployment cmd: /readwrite -r /secret.txt -result: failed +result: default --- operation: File condition: /secret.txt -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_21/cmd2 b/tests/scenarios/multiubuntu_test_21/cmd2 index e71c4f66b3..bb4554aa13 100644 --- a/tests/scenarios/multiubuntu_test_21/cmd2 +++ b/tests/scenarios/multiubuntu_test_21/cmd2 @@ -1,7 +1,7 @@ source: ubuntu-3-deployment cmd: cat /home/user1/secret_data1.txt -result: failed +result: default --- operation: File condition: /home/user1/secret_data1.txt -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_22/cmd2 b/tests/scenarios/multiubuntu_test_22/cmd2 index bbfd751e54..a1908623c7 100644 --- a/tests/scenarios/multiubuntu_test_22/cmd2 +++ b/tests/scenarios/multiubuntu_test_22/cmd2 @@ -1,7 +1,7 @@ source: ubuntu-5-deployment cmd: su - user1 -c "echo test >> /home/user1/secret_data1.txt" -result: failed +result: default --- operation: File condition: /home/user1/secret_data1.txt -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_22/cmd3 b/tests/scenarios/multiubuntu_test_22/cmd3 index cbfdb0cd67..fb46ebf864 100644 --- a/tests/scenarios/multiubuntu_test_22/cmd3 +++ b/tests/scenarios/multiubuntu_test_22/cmd3 @@ -1,7 +1,7 @@ source: ubuntu-5-deployment cmd: cat /home/user1/secret_data1.txt -result: failed +result: default --- operation: File condition: /home/user1/secret_data1.txt -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_22/cmd4 b/tests/scenarios/multiubuntu_test_22/cmd4 index 27c0d73147..8d9f4c2435 100644 --- a/tests/scenarios/multiubuntu_test_22/cmd4 +++ b/tests/scenarios/multiubuntu_test_22/cmd4 @@ -1,7 +1,7 @@ source: ubuntu-5-deployment cmd: echo test >> /home/user1/secret_data1.txt -result: failed +result: default --- operation: File condition: /home/user1/secret_data1.txt -action: Allow +action: default diff --git a/tests/scenarios/multiubuntu_test_28/cmd1 b/tests/scenarios/multiubuntu_test_28/cmd1 index d3241f23c4..9264401795 100644 --- a/tests/scenarios/multiubuntu_test_28/cmd1 +++ b/tests/scenarios/multiubuntu_test_28/cmd1 @@ -1,5 +1,5 @@ source: ubuntu-1-deployment -cmd: ping -c 1 127.0.0.1 +cmd: arping -c 1 127.0.0.1 result: failed --- operation: Network diff --git a/tests/test-scenarios-github.sh b/tests/test-scenarios-github.sh index 209e922029..973de0f290 100755 --- a/tests/test-scenarios-github.sh +++ b/tests/test-scenarios-github.sh @@ -35,6 +35,10 @@ if [ $? == 0 ]; then LSM="apparmor" fi +if [ "$DEFAULT_POSTURE" == "" ]; then + DEFAULT_POSTURE="block" +fi + ARMOR_OPTIONS=() SKIP_CONTAINER_POLICY=1 @@ -62,15 +66,13 @@ case $1 in if [ "$LSM" == "selinux" ]; then echo "If you want to test host policies, please run KubeArmor separately and use test-scenarios-in-runtime.sh" echo "KubeArmor does not support native policies if AppArmor is not enabled" - SKIP_CONTAINER_POLICY=0 elif [ "$LSM" == "apparmor" ]; then echo "If you want to test host policies, please run KubeArmor separately and use test-scenarios-in-runtime.sh" - SKIP_CONTAINER_POLICY=0 SKIP_NATIVE_POLICY=0 else # none echo "KubeArmor does not support native policies if AppArmor is not enabled" - SKIP_CONTAINER_POLICY=0 fi + SKIP_CONTAINER_POLICY=0 ARMOR_OPTIONS=$@ ;; esac @@ -272,7 +274,7 @@ function should_find_blocked_log() { sleep 5 - audit_log=$($CAT_LOG | grep -E "$1.*policyName.*$2|DefaultPosture.*MatchedPolicy.*operation.*$3.*resource.*$4.*data.*action.*$5" | grep -v grep | tail -n 1 | grep -v Passed) + audit_log=$($CAT_LOG | grep -E "$1.*policyName.*$2.*MatchedPolicy.*operation.*$3.*resource.*$4.*data.*action.*$5" | grep -v grep | tail -n 1 | grep -v Passed) if [ $? != 0 ]; then audit_log="" FAIL "Failed to find the log from logs" @@ -320,7 +322,7 @@ function should_find_blocked_host_log() { sleep 5 - audit_log=$($CAT_LOG | grep -E "$HOST_NAME.*policyName.*$1|DefaultPosture.*MatchedHostPolicy.*operation.*$2.*resource.*$3.*data.*action.*$4" | grep -v grep | tail -n 1 | grep -v Passed) + audit_log=$($CAT_LOG | grep -E "$HOST_NAME.*policyName.*$1.*MatchedHostPolicy.*operation.*$2.*resource.*$3.*data.*action.*$4" | grep -v grep | tail -n 1 | grep -v Passed) if [ $? != 0 ]; then audit_log="" FAIL "Failed to find the log from logs" @@ -337,6 +339,7 @@ function run_test_scenario() { YAML_FILE=$(ls *.yaml) POLICY_TYPE=$(echo $YAML_FILE | awk '{split($0,a,"-"); print a[1]}') POLICY=$(grep "name:" $YAML_FILE | head -n1 | awk '{ print $2}') + POLICY_ACTION=$(cat $YAML_FILE | grep "^action" | awk '{print $2}') NATIVE_POLICY=0 HOST_POLICY=0 @@ -346,6 +349,11 @@ function run_test_scenario() { skipped_testcases+=("$3") return fi + if [[ "$DEFAULT_POSTURE" == "allow" ]] && [[ "$POLICY_ACTION" == "Allow" ]]; then + WARN "Skipped $3" + skipped_testcases+=("$3") + return + fi elif [[ $POLICY_TYPE == "nsp" ]]; then # skip a policy with a native profile unless AppArmor is enabled if [ "$LSM" != "apparmor" ]; then @@ -400,11 +408,33 @@ function run_test_scenario() { CMD=$(cat $cmd | grep "^cmd" | cut -d' ' -f2-) RESULT=$(cat $cmd | grep "^result" | awk '{print $2}') + POLICY_NAME=$POLICY OP=$(cat $cmd | grep "^operation" | awk '{print $2}') COND=$(cat $cmd | grep "^condition" | cut -d' ' -f2-) ACTION=$(cat $cmd | grep "^action" | awk '{print $2}') - # if SELinux is enabled but a test policy not for hosts + if [[ $HOST_POLICY -eq 0 ]] && [[ "$RESULT" == "default" ]]; then + if [ "$ACTION" == "default" ]; then # default posture + if [ "$DEFAULT_POSTURE" == "block" ]; then + RESULT="failed" + POLICY_NAME="DefaultPosture" + ACTION="Block" + elif [ "$DEFAULT_POSTURE" == "audit" ]; then + RESULT="passed" + POLICY_NAME="DefaultPosture" + ACTION="Audit" + elif [ "$DEFAULT_POSTURE" == "allow" ]; then + RESULT="passed" + POLICY_NAME="DefaultPosture" + ACTION="Allow" + fi + elif [ "$ACTION" == "Block" ]; then # native policy + RESULT="failed" + POLICY_NAME="DefaultPosture" + fi + fi + + # if SELinux is enabled but a test policy is not for hosts if [[ "$LSM" == "selinux" ]] && [[ $HOST_POLICY -eq 0 ]]; then # replace Block with Audit if [ "$ACTION" == "Block" ]; then @@ -457,52 +487,52 @@ function run_test_scenario() { if [ "$ACTION" == "Allow" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_not_find_any_log $POD $POLICY $OP $COND $ACTION $CMD + should_not_find_any_log $POD $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, but the command should be failed" - should_find_blocked_log $POD $POLICY $OP $COND $ACTION + should_find_blocked_log $POD $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Audit" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_find_passed_log $POD $POLICY $OP $COND $ACTION + should_find_passed_log $POD $POLICY_NAME $OP $COND $ACTION else DBG "$ACTION action, but the command should be failed" - should_find_blocked_log $POD $POLICY $OP $COND $ACTION + should_find_blocked_log $POD $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Block" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, but the command should be passed" - should_not_find_any_log $POD $POLICY $OP $COND $ACTION $CMD + should_not_find_any_log $POD $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, and the command should be failed" - should_find_blocked_log $POD $POLICY $OP $COND $ACTION + should_find_blocked_log $POD $POLICY_NAME $OP $COND $ACTION fi fi else if [ "$ACTION" == "Allow" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_not_find_any_host_log $POLICY $OP $COND $ACTION $CMD + should_not_find_any_host_log $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, but the command should be failed" - should_find_blocked_host_log $POLICY $OP $COND $ACTION + should_find_blocked_host_log $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Audit" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_find_passed_host_log $POLICY $OP $COND $ACTION + should_find_passed_host_log $POLICY_NAME $OP $COND $ACTION else DBG "$ACTION action, but the command should be failed" - should_find_blocked_host_log $POLICY $OP $COND $ACTION + should_find_blocked_host_log $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Block" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, but the command should be passed" - should_not_find_any_host_log $POLICY $OP $COND $ACTION $CMD + should_not_find_any_host_log $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, and the command should be failed" - should_find_blocked_host_log $POLICY $OP $COND $ACTION + should_find_blocked_host_log $POLICY_NAME $OP $COND $ACTION fi fi fi diff --git a/tests/test-scenarios-in-runtime.sh b/tests/test-scenarios-in-runtime.sh index ac3ca40ad5..4b03e2a229 100755 --- a/tests/test-scenarios-in-runtime.sh +++ b/tests/test-scenarios-in-runtime.sh @@ -33,6 +33,10 @@ if [ $? == 0 ]; then LSM="apparmor" fi +if [ "$DEFAULT_POSTURE" == "" ]; then + DEFAULT_POSTURE="block" +fi + SKIP_CONTAINER_POLICY=1 SKIP_NATIVE_POLICY=1 SKIP_HOST_POLICY=1 @@ -55,19 +59,13 @@ case $1 in ARMOR_OPTIONS=${@:2} ;; *) - if [ "$LSM" == "selinux" ]; then - echo "KubeArmor does not support native policies if AppArmor is not enabled" - SKIP_CONTAINER_POLICY=0 - SKIP_HOST_POLICY=0 - elif [ "$LSM" == "apparmor" ]; then - SKIP_CONTAINER_POLICY=0 + if [ "$LSM" == "apparmor" ]; then SKIP_NATIVE_POLICY=0 - SKIP_HOST_POLICY=0 - else # none + else echo "KubeArmor does not support native policies if AppArmor is not enabled" - SKIP_CONTAINER_POLICY=0 - SKIP_HOST_POLICY=0 fi + SKIP_CONTAINER_POLICY=0 + SKIP_HOST_POLICY=0 ARMOR_OPTIONS=$@ ;; esac @@ -217,7 +215,7 @@ function should_find_blocked_log() { KUBEARMOR=$(kubectl get pods -n kube-system -l kubearmor-app=kubearmor -o wide 2> /dev/null | grep $NODE | grep kubearmor | awk '{print $1}') if [[ $KUBEARMOR = "kubearmor"* ]]; then - audit_log=$(kubectl -n kube-system exec $KUBEARMOR -- grep -E "$1.*policyName.*$2|DefaultPosture.*MatchedPolicy.*operation.*$3.*resource.*$4.*data.*action.*$5" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) + audit_log=$(kubectl -n kube-system exec $KUBEARMOR -- grep -E "$1.*policyName.*$2.*MatchedPolicy.*operation.*$3.*resource.*$4.*data.*action.*$5" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) if [ $? != 0 ]; then audit_log="" FAIL "Failed to find the log from logs" @@ -227,7 +225,7 @@ function should_find_blocked_log() { DBG "Found the log from logs" fi else # local - audit_log=$(grep -E "$1.*policyName.*$2|DefaultPosture.*MatchedPolicy.*operation.*$3.*resource.*$4.*data.*action.*$5" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) + audit_log=$(grep -E "$1.*policyName.*$2.*MatchedPolicy.*operation.*$3.*resource.*$4.*data.*action.*$5" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) if [ $? != 0 ]; then audit_log="" FAIL "Failed to find the log from logs" @@ -310,7 +308,7 @@ function should_find_blocked_host_log() { KUBEARMOR=$(kubectl get pods -n kube-system -l kubearmor-app=kubearmor -o wide 2> /dev/null | grep $NODE | grep kubearmor | awk '{print $1}') if [[ $KUBEARMOR = "kubearmor"* ]]; then - audit_log=$(kubectl -n kube-system exec $KUBEARMOR -- grep -E "$HOST_NAME.*policyName.*$1|DefaultPosture.*MatchedHostPolicy.*operation.*$2.*resource.*$3.*data.*action.*$4" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) + audit_log=$(kubectl -n kube-system exec $KUBEARMOR -- grep -E "$HOST_NAME.*policyName.*$1.*MatchedHostPolicy.*operation.*$2.*resource.*$3.*data.*action.*$4" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) if [ $? != 0 ]; then audit_log="" FAIL "Failed to find the log from logs" @@ -320,7 +318,7 @@ function should_find_blocked_host_log() { DBG "Found the log from logs" fi else # local - audit_log=$(grep -E "$HOST_NAME.*policyName.*$1|DefaultPosture.*MatchedHostPolicy.*operation.*$2.*resource.*$3.*data.*action.*$4" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) + audit_log=$(grep -E "$HOST_NAME.*policyName.*$1.*MatchedHostPolicy.*operation.*$2.*resource.*$3.*data.*action.*$4" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) if [ $? != 0 ]; then audit_log="" FAIL "Failed to find the log from logs" @@ -338,6 +336,7 @@ function run_test_scenario() { YAML_FILE=$(ls *.yaml) POLICY_TYPE=$(echo $YAML_FILE | awk '{split($0,a,"-"); print a[1]}') POLICY=$(grep "name:" $YAML_FILE | head -n1 | awk '{ print $2}') + POLICY_ACTION=$(cat $YAML_FILE | grep "^action" | awk '{print $2}') NATIVE_POLICY=0 HOST_POLICY=0 @@ -347,6 +346,11 @@ function run_test_scenario() { skipped_testcases+=("$3") return fi + if [[ "$DEFAULT_POSTURE" == "allow" ]] && [[ "$POLICY_ACTION" == "Allow" ]]; then + WARN "Skipped $3" + skipped_testcases+=("$3") + return + fi elif [[ $POLICY_TYPE == "nsp" ]]; then # skip a policy with a native profile unless AppArmor is enabled if [ "$LSM" != "apparmor" ]; then @@ -401,11 +405,33 @@ function run_test_scenario() { CMD=$(cat $cmd | grep "^cmd" | cut -d' ' -f2-) RESULT=$(cat $cmd | grep "^result" | awk '{print $2}') + POLICY_NAME=$POLICY OP=$(cat $cmd | grep "^operation" | awk '{print $2}') COND=$(cat $cmd | grep "^condition" | cut -d' ' -f2-) ACTION=$(cat $cmd | grep "^action" | awk '{print $2}') - # if SELinux is enabled but a test policy not for hosts + if [[ $HOST_POLICY -eq 0 ]] && [[ "$RESULT" == "default" ]]; then + if [ "$ACTION" == "default" ]; then # default posture + if [ "$DEFAULT_POSTURE" == "block" ]; then + RESULT="failed" + POLICY_NAME="DefaultPosture" + ACTION="Block" + elif [ "$DEFAULT_POSTURE" == "audit" ]; then + RESULT="passed" + POLICY_NAME="DefaultPosture" + ACTION="Audit" + elif [ "$DEFAULT_POSTURE" == "allow" ]; then + RESULT="passed" + POLICY_NAME="DefaultPosture" + ACTION="Allow" + fi + elif [ "$ACTION" == "Block" ]; then # native policy + RESULT="failed" + POLICY_NAME="DefaultPosture" + fi + fi + + # if SELinux is enabled but a test policy is not for hosts if [[ "$LSM" == "selinux" ]] && [[ $HOST_POLICY -eq 0 ]]; then # replace Block with Audit if [ "$ACTION" == "Block" ]; then @@ -458,52 +484,52 @@ function run_test_scenario() { if [ "$ACTION" == "Allow" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_not_find_any_log $POD $POLICY $OP $COND $ACTION $CMD + should_not_find_any_log $POD $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, but the command should be failed" - should_find_blocked_log $POD $POLICY $OP $COND $ACTION + should_find_blocked_log $POD $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Audit" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_find_passed_log $POD $POLICY $OP $COND $ACTION + should_find_passed_log $POD $POLICY_NAME $OP $COND $ACTION else DBG "$ACTION action, but the command should be failed" - should_find_blocked_log $POD $POLICY $OP $COND $ACTION + should_find_blocked_log $POD $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Block" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, but the command should be passed" - should_not_find_any_log $POD $POLICY $OP $COND $ACTION $CMD + should_not_find_any_log $POD $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, and the command should be failed" - should_find_blocked_log $POD $POLICY $OP $COND $ACTION + should_find_blocked_log $POD $POLICY_NAME $OP $COND $ACTION fi fi else if [ "$ACTION" == "Allow" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_not_find_any_host_log $POLICY $OP $COND $ACTION $CMD + should_not_find_any_host_log $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, but the command should be failed" - should_find_blocked_host_log $POLICY $OP $COND $ACTION + should_find_blocked_host_log $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Audit" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_find_passed_host_log $POLICY $OP $COND $ACTION + should_find_passed_host_log $POLICY_NAME $OP $COND $ACTION else DBG "$ACTION action, but the command should be failed" - should_find_blocked_host_log $POLICY $OP $COND $ACTION + should_find_blocked_host_log $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Block" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, but the command should be passed" - should_not_find_any_host_log $POLICY $OP $COND $ACTION $CMD + should_not_find_any_host_log $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, and the command should be failed" - should_find_blocked_host_log $POLICY $OP $COND $ACTION + should_find_blocked_host_log $POLICY_NAME $OP $COND $ACTION fi fi fi @@ -538,6 +564,8 @@ function run_test_scenario() { fi sleep 1 + + # read -p "Press enter to continue" done if [ $res_case != 0 ]; then diff --git a/tests/test-scenarios-local.sh b/tests/test-scenarios-local.sh index e24a3c6951..ac827989f3 100755 --- a/tests/test-scenarios-local.sh +++ b/tests/test-scenarios-local.sh @@ -35,6 +35,10 @@ if [ $? == 0 ]; then LSM="apparmor" fi +if [ "$DEFAULT_POSTURE" == "" ]; then + DEFAULT_POSTURE="block" +fi + ARMOR_OPTIONS=() SKIP_CONTAINER_POLICY=1 @@ -130,12 +134,28 @@ function start_and_wait_for_kubearmor_initialization() { cd $ARMOR_HOME + if [ "$DEFAULT_POSTURE" == "allow" ]; then + ARMOR_OPTIONS+=("-defaultFilePosture=allow") + ARMOR_OPTIONS+=("-defaultNetworkPosture=allow") + ARMOR_OPTIONS+=("-defaultCapabilitiesPosture=allow") + elif [ "$DEFAULT_POSTURE" == "audit" ]; then + ARMOR_OPTIONS+=("-defaultFilePosture=audit") + ARMOR_OPTIONS+=("-defaultNetworkPosture=audit") + ARMOR_OPTIONS+=("-defaultCapabilitiesPosture=audit") + else # block + ARMOR_OPTIONS+=("-defaultFilePosture=block") + ARMOR_OPTIONS+=("-defaultNetworkPosture=block") + ARMOR_OPTIONS+=("-defaultCapabilitiesPosture=block") + fi + echo "Options: -logPath=$ARMOR_LOG ${ARMOR_OPTIONS[@]}" if [[ ! " ${ARMOR_OPTIONS[@]} " =~ "-enableKubeArmorHostPolicy" ]]; then SKIP_HOST_POLICY=1 fi + make clean; make sudo -E ./kubearmor -logPath=$ARMOR_LOG ${ARMOR_OPTIONS[@]} > $ARMOR_MSG & + echo "Executed KubeArmor" for (( ; ; )) do @@ -231,7 +251,7 @@ function should_find_blocked_log() { sleep 5 - audit_log=$(grep -E "$1.*policyName.*$2|DefaultPosture.*MatchedPolicy.*operation.*$3.*resource.*$4.*data.*action.*$5" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) + audit_log=$(grep -E "$1.*policyName.*$2.*MatchedPolicy.*operation.*$3.*resource.*$4.*data.*action.*$5" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) if [ $? != 0 ]; then audit_log="" FAIL "Failed to find the log from logs" @@ -279,7 +299,7 @@ function should_find_blocked_host_log() { sleep 5 - audit_log=$(grep -E "$HOST_NAME.*policyName.*$1|DefaultPosture.*MatchedHostPolicy.*operation.*$2.*resource.*$3.*data.*action.*$4" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) + audit_log=$(grep -E "$HOST_NAME.*policyName.*$1.*MatchedHostPolicy.*operation.*$2.*resource.*$3.*data.*action.*$4" $ARMOR_LOG | grep -v grep | tail -n 1 | grep -v Passed) if [ $? != 0 ]; then audit_log="" FAIL "Failed to find the log from logs" @@ -296,6 +316,7 @@ function run_test_scenario() { YAML_FILE=$(ls *.yaml) POLICY_TYPE=$(echo $YAML_FILE | awk '{split($0,a,"-"); print a[1]}') POLICY=$(grep "name:" $YAML_FILE | head -n1 | awk '{ print $2}') + POLICY_ACTION=$(cat $YAML_FILE | grep "^action" | awk '{print $2}') NATIVE_POLICY=0 HOST_POLICY=0 @@ -305,6 +326,11 @@ function run_test_scenario() { skipped_testcases+=("$3") return fi + if [[ "$DEFAULT_POSTURE" == "allow" ]] && [[ "$POLICY_ACTION" == "Allow" ]]; then + WARN "Skipped $3" + skipped_testcases+=("$3") + return + fi elif [[ $POLICY_TYPE == "nsp" ]]; then # skip a policy with a native profile unless AppArmor is enabled if [ "$LSM" != "apparmor" ]; then @@ -359,11 +385,33 @@ function run_test_scenario() { CMD=$(cat $cmd | grep "^cmd" | cut -d' ' -f2-) RESULT=$(cat $cmd | grep "^result" | awk '{print $2}') + POLICY_NAME=$POLICY OP=$(cat $cmd | grep "^operation" | awk '{print $2}') COND=$(cat $cmd | grep "^condition" | cut -d' ' -f2-) ACTION=$(cat $cmd | grep "^action" | awk '{print $2}') - # if SELinux is enabled but a test policy not for hosts + if [[ $HOST_POLICY -eq 0 ]] && [[ "$RESULT" == "default" ]]; then + if [ "$ACTION" == "default" ]; then # default posture + if [ "$DEFAULT_POSTURE" == "block" ]; then + RESULT="failed" + POLICY_NAME="DefaultPosture" + ACTION="Block" + elif [ "$DEFAULT_POSTURE" == "audit" ]; then + RESULT="passed" + POLICY_NAME="DefaultPosture" + ACTION="Audit" + elif [ "$DEFAULT_POSTURE" == "allow" ]; then + RESULT="passed" + POLICY_NAME="DefaultPosture" + ACTION="Allow" + fi + elif [ "$ACTION" == "Block" ]; then # native policy + RESULT="failed" + POLICY_NAME="DefaultPosture" + fi + fi + + # if SELinux is enabled but a test policy is not for hosts if [[ "$LSM" == "selinux" ]] && [[ $HOST_POLICY -eq 0 ]]; then # replace Block with Audit if [ "$ACTION" == "Block" ]; then @@ -416,52 +464,52 @@ function run_test_scenario() { if [ "$ACTION" == "Allow" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_not_find_any_log $POD $POLICY $OP $COND $ACTION $CMD + should_not_find_any_log $POD $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, but the command should be failed" - should_find_blocked_log $POD $POLICY $OP $COND $ACTION + should_find_blocked_log $POD $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Audit" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_find_passed_log $POD $POLICY $OP $COND $ACTION + should_find_passed_log $POD $POLICY_NAME $OP $COND $ACTION else DBG "$ACTION action, but the command should be failed" - should_find_blocked_log $POD $POLICY $OP $COND $ACTION + should_find_blocked_log $POD $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Block" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, but the command should be passed" - should_not_find_any_log $POD $POLICY $OP $COND $ACTION $CMD + should_not_find_any_log $POD $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, and the command should be failed" - should_find_blocked_log $POD $POLICY $OP $COND $ACTION + should_find_blocked_log $POD $POLICY_NAME $OP $COND $ACTION fi fi else if [ "$ACTION" == "Allow" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_not_find_any_host_log $POLICY $OP $COND $ACTION $CMD + should_not_find_any_host_log $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, but the command should be failed" - should_find_blocked_host_log $POLICY $OP $COND $ACTION + should_find_blocked_host_log $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Audit" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, and the command should be passed" - should_find_passed_host_log $POLICY $OP $COND $ACTION + should_find_passed_host_log $POLICY_NAME $OP $COND $ACTION else DBG "$ACTION action, but the command should be failed" - should_find_blocked_host_log $POLICY $OP $COND $ACTION + should_find_blocked_host_log $POLICY_NAME $OP $COND $ACTION fi elif [ "$ACTION" == "Block" ]; then if [ "$RESULT" == "passed" ]; then DBG "$ACTION action, but the command should be passed" - should_not_find_any_host_log $POLICY $OP $COND $ACTION $CMD + should_not_find_any_host_log $POLICY_NAME $OP $COND $ACTION $CMD else DBG "$ACTION action, and the command should be failed" - should_find_blocked_host_log $POLICY $OP $COND $ACTION + should_find_blocked_host_log $POLICY_NAME $OP $COND $ACTION fi fi fi @@ -496,6 +544,8 @@ function run_test_scenario() { fi sleep 1 + + # read -p "Press enter to continue" done if [ $res_case != 0 ]; then