diff --git a/KubeArmor/config/config.go b/KubeArmor/config/config.go index d6d6b9d7a9..e5a913a685 100644 --- a/KubeArmor/config/config.go +++ b/KubeArmor/config/config.go @@ -29,6 +29,10 @@ type KubearmorConfig struct { KVMAgent bool // Enable/Disable KVM Agent K8sEnv bool // Is k8s env ? + DefaultFilePosture string // Default Enforcement Action in Global File Context + DefaultNetworkPosture string // Default Enforcement Action in Global Network Context + DefaultCapabilitiesPosture string // Default Enforcement Action in Global Capabilities Context + CoverageTest bool // Enable/Disable Coverage Test } @@ -68,6 +72,15 @@ const ConfigKubearmorHostPolicy string = "enableKubeArmorHostPolicy" // ConfigKubearmorVM Kubearmor VM key const ConfigKubearmorVM string = "enableKubeArmorVm" +// ConfigDefaultFilePosture KubeArmor Default Global File Posture key +const ConfigDefaultFilePosture string = "defaultFilePosture" + +// ConfigDefaultNetworkPosture KubeArmor Default Global Network Posture key +const ConfigDefaultNetworkPosture string = "defaultNetworkPosture" + +// ConfigDefaultCapabilitiesPosture KubeArmor Default Global Capabilities Posture key +const ConfigDefaultCapabilitiesPosture string = "defaultCapabilitiesPosture" + // ConfigCoverageTest Coverage Test key const ConfigCoverageTest string = "coverageTest" @@ -91,6 +104,10 @@ 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]") + coverageTestB := flag.Bool(ConfigCoverageTest, false, "enabling CoverageTest") flag.Parse() @@ -110,6 +127,10 @@ func readCmdLineParams() { viper.SetDefault(ConfigKubearmorVM, *kvmAgentB) viper.SetDefault(ConfigK8sEnv, *k8sEnvB) + viper.SetDefault(ConfigDefaultFilePosture, *defaultFilePosture) + viper.SetDefault(ConfigDefaultNetworkPosture, *defaultNetworkPosture) + viper.SetDefault(ConfigDefaultCapabilitiesPosture, *defaultCapabilitiesPosture) + viper.SetDefault(ConfigCoverageTest, *coverageTestB) } @@ -155,6 +176,10 @@ func LoadConfig() error { } GlobalCfg.K8sEnv = viper.GetBool(ConfigK8sEnv) + GlobalCfg.DefaultFilePosture = viper.GetString(ConfigDefaultFilePosture) + GlobalCfg.DefaultNetworkPosture = viper.GetString(ConfigDefaultNetworkPosture) + GlobalCfg.DefaultCapabilitiesPosture = viper.GetString(ConfigDefaultCapabilitiesPosture) + if GlobalCfg.HostVisibility == "" { if GlobalCfg.KVMAgent || (!GlobalCfg.K8sEnv && GlobalCfg.HostPolicy) { GlobalCfg.HostVisibility = "process,file,network,capabilities" diff --git a/KubeArmor/enforcer/appArmorProfile.go b/KubeArmor/enforcer/appArmorProfile.go index 772df669c3..da10fdef8e 100644 --- a/KubeArmor/enforcer/appArmorProfile.go +++ b/KubeArmor/enforcer/appArmorProfile.go @@ -12,6 +12,7 @@ import ( "strings" kl "github.com/kubearmor/KubeArmor/KubeArmor/common" + cfg "github.com/kubearmor/KubeArmor/KubeArmor/config" tp "github.com/kubearmor/KubeArmor/KubeArmor/types" ) @@ -812,19 +813,27 @@ func (ae *AppArmorEnforcer) BlockedCapabilitiesMatchCapabilities(cap tp.Capabili // == // // GenerateProfileHead Function -func (ae *AppArmorEnforcer) GenerateProfileHead(processWhiteList, fileWhiteList, networkWhiteList, capabilityWhiteList []string) string { +func (ae *AppArmorEnforcer) GenerateProfileHead(processWhiteList, fileWhiteList, networkWhiteList, capabilityWhiteList []string, file, network, capability bool) string { profileHead := " #include \n" profileHead = profileHead + " umount,\n" - if len(processWhiteList) == 0 && len(fileWhiteList) == 0 { + // Block Access to Resource when + // -> Default Posture is Block + // AND + // -> Atleast one allow policy OR from source allow policy + + if cfg.GlobalCfg.DefaultFilePosture == "block" && ((len(processWhiteList) > 0 || len(fileWhiteList) > 0) || !file) { + } else { profileHead = profileHead + " file,\n" } - if len(networkWhiteList) == 0 { + if cfg.GlobalCfg.DefaultNetworkPosture == "block" && (len(networkWhiteList) > 0 || !network) { + } else { profileHead = profileHead + " network,\n" } - if len(capabilityWhiteList) == 0 { + if cfg.GlobalCfg.DefaultCapabilitiesPosture == "block" && (len(capabilityWhiteList) > 0 || !capability) { + } else { profileHead = profileHead + " capability,\n" } @@ -882,6 +891,10 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo fusionProcessWhiteList := []string{} + globalFile := true + globalNetwork := true + globalCapability := true + // preparation for _, secPolicy := range securityPolicies { @@ -985,10 +998,6 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo // Resolve conflicts ae.ResolvedProcessWhiteListConflicts(&processWhiteList, fromSources, &fusionProcessWhiteList) - // head - - profileHead := " ## == PRE START == ##\n" + ae.GenerateProfileHead(processWhiteList, fileWhiteList, networkWhiteList, capabilityWhiteList) + " ## == PRE END == ##\n\n" - // body profileBody := "" @@ -1087,11 +1096,13 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo for _, line := range lines { if strings.Contains(line, " network") { network = false + globalNetwork = false continue } if strings.Contains(line, " capability") { capability = false + globalCapability = false continue } @@ -1104,17 +1115,21 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo } file = false + globalFile = false } - if file && len(processWhiteList) == 0 && len(fileWhiteList) == 0 { + if cfg.GlobalCfg.DefaultFilePosture == "block" && ((len(processWhiteList) > 0 || len(fileWhiteList) > 0) || !file) { + } else { bodyFromSource = bodyFromSource + " file,\n" } - if network && len(networkWhiteList) == 0 { + if cfg.GlobalCfg.DefaultNetworkPosture == "block" && (len(networkWhiteList) > 0 || !network) { + } else { bodyFromSource = bodyFromSource + " network,\n" } - if capability && len(capabilityWhiteList) == 0 { + if cfg.GlobalCfg.DefaultCapabilitiesPosture == "block" && (len(capabilityWhiteList) > 0 || !capability) { + } else { bodyFromSource = bodyFromSource + " capability,\n" } @@ -1146,6 +1161,10 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo count = count + len(source) } + // head + + profileHead := " ## == PRE START == ##\n" + ae.GenerateProfileHead(processWhiteList, fileWhiteList, networkWhiteList, capabilityWhiteList, globalFile, globalNetwork, globalCapability) + " ## == PRE END == ##\n\n" + // body - together profileBody = " ## == POLICY START == ##\n" + profileBody + bodyFromSource + " ## == POLICY END == ##\n\n" diff --git a/KubeArmor/feeder/policyMatcher.go b/KubeArmor/feeder/policyMatcher.go index ffdf8d40e8..b95547e502 100644 --- a/KubeArmor/feeder/policyMatcher.go +++ b/KubeArmor/feeder/policyMatcher.go @@ -673,6 +673,25 @@ func lastString(ss []string) string { return ss[len(ss)-1] } +// Update Log Fields based on default posture and visibility configuration and return false if no updates +func setLogFields(action string, visibility bool, log *tp.Log, considerPosture bool) bool { + if considerPosture && action == "block" { + (*log).Type = "MatchedPolicy" + (*log).PolicyName = "DefaultPosture" + (*log).Action = "Block" + return true + } else if considerPosture && action == "audit" { + (*log).Type = "MatchedPolicy" + (*log).PolicyName = "DefaultPosture" + (*log).Action = "Audit" + return true + } else if visibility { + (*log).Type = "ContainerLog" + return true + } + return false +} + // UpdateMatchedPolicy Function func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { allowProcPolicy := "" @@ -691,6 +710,8 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { allowNetworkMessage := "" mightBeNative := false + considerFilePosture := false + considerNetworkPosture := false if log.Result == "Passed" || log.Result == "Operation not permitted" || log.Result == "Permission denied" { fd.SecurityPoliciesLock.RLock() @@ -851,6 +872,12 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { continue } } + + if !matched { + if secPolicy.Action == "Allow" { + considerFilePosture = true + } + } } case "Network": if secPolicy.Operation == log.Operation { @@ -873,6 +900,11 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { continue } } + + if secPolicy.Action == "Allow" { + considerNetworkPosture = true + } + } } @@ -1008,18 +1040,22 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { } } - if log.ProcessVisibilityEnabled && log.Operation == "Process" { - log.Type = "ContainerLog" - return log - } else if log.FileVisibilityEnabled && log.Operation == "File" { - log.Type = "ContainerLog" - return log - } else if log.NetworkVisibilityEnabled && log.Operation == "Network" { - log.Type = "ContainerLog" - return log - } else if log.CapabilitiesVisibilityEnabled && log.Operation == "Capabilities" { - log.Type = "ContainerLog" - return log + if log.Operation == "Process" { + if setLogFields(cfg.GlobalCfg.DefaultFilePosture, log.ProcessVisibilityEnabled, &log, considerFilePosture) { + return log + } + } else if log.Operation == "File" { + if setLogFields(cfg.GlobalCfg.DefaultFilePosture, log.FileVisibilityEnabled, &log, considerFilePosture) { + return log + } + } else if log.Operation == "Network" { + if setLogFields(cfg.GlobalCfg.DefaultNetworkPosture, log.NetworkVisibilityEnabled, &log, considerNetworkPosture) { + return log + } + } else if log.Operation == "Capabilities" { + if setLogFields(cfg.GlobalCfg.DefaultCapabilitiesPosture, log.CapabilitiesVisibilityEnabled, &log, false) { + return log + } } } else if log.Type == "MatchedPolicy" { if log.PolicyEnabled == tp.KubeArmorPolicyAudited { diff --git a/tests/scenarios/github_test_12/cmd1 b/tests/scenarios/github_test_12/cmd1 new file mode 100644 index 0000000000..df68e636d5 --- /dev/null +++ b/tests/scenarios/github_test_12/cmd1 @@ -0,0 +1,7 @@ +source: ubuntu-1-deployment +cmd: curl 142.250.193.46 +result: passed +--- +operation: Network +condition: SOCK_STREAM +action: Allow diff --git a/tests/scenarios/github_test_12/cmd2 b/tests/scenarios/github_test_12/cmd2 new file mode 100644 index 0000000000..0558fa201e --- /dev/null +++ b/tests/scenarios/github_test_12/cmd2 @@ -0,0 +1,7 @@ +source: ubuntu-1-deployment +cmd: curl google.com +result: failed +--- +operation: Network +condition: SOCK_DGRAM +action: Block diff --git a/tests/scenarios/github_test_12/cmd3 b/tests/scenarios/github_test_12/cmd3 new file mode 100644 index 0000000000..c9483388b5 --- /dev/null +++ b/tests/scenarios/github_test_12/cmd3 @@ -0,0 +1,7 @@ +source: ubuntu-1-deployment +cmd: wget --tries=1 142.250.193.46 +result: failed +--- +operation: Network +condition: SOCK_STREAM +action: Block diff --git a/tests/scenarios/github_test_12/ksp-ubuntu-1-net-tcp-from-source-allow.yaml b/tests/scenarios/github_test_12/ksp-ubuntu-1-net-tcp-from-source-allow.yaml new file mode 100644 index 0000000000..cfeb8bd1ad --- /dev/null +++ b/tests/scenarios/github_test_12/ksp-ubuntu-1-net-tcp-from-source-allow.yaml @@ -0,0 +1,16 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorPolicy +metadata: + name: ksp-ubuntu-1-net-tcp-from-source-allow-curl + namespace: github +spec: + severity: 8 + selector: + matchLabels: + container: ubuntu-1 + network: + matchProtocols: + - protocol: tcp + fromSource: + - path: /usr/bin/curl + action: Allow diff --git a/tests/test-scenarios-github.sh b/tests/test-scenarios-github.sh index 00f512bd37..db07257552 100755 --- a/tests/test-scenarios-github.sh +++ b/tests/test-scenarios-github.sh @@ -266,7 +266,7 @@ function should_find_blocked_log() { fi if [[ $6 -eq 0 ]]; then - audit_log=$($CAT_LOG | grep -E "$1.*policyName.*\"$2\".*$match_type.*$3.*resource.*$4.*$5" | tail -n 1 | grep -v Passed) + audit_log=$($CAT_LOG | grep -E "$1.*policyName.*\"$2|DefaultPosture\".*$match_type.*$3.*resource.*$4.*$5" | tail -n 1 | grep -v Passed) else audit_log=$($CAT_LOG | grep -E "$1.*policyName.*\"NativePolicy\".*$match_type.*$3.*resource.*$4.*$5" | tail -n 1 | grep -v Passed) fi diff --git a/tests/test-scenarios-in-runtime.sh b/tests/test-scenarios-in-runtime.sh index ad675759c3..1b905b1ae4 100755 --- a/tests/test-scenarios-in-runtime.sh +++ b/tests/test-scenarios-in-runtime.sh @@ -208,7 +208,7 @@ function should_find_blocked_log() { if [[ $KUBEARMOR = "kubearmor"* ]]; then if [[ $6 -eq 0 ]]; then - audit_log=$(kubectl -n kube-system exec $KUBEARMOR -- grep -E "$1.*policyName.*\"$2\".*$match_type.*$3.*resource.*$4.*$5" $ARMOR_LOG | tail -n 1 | grep -v Passed) + audit_log=$(kubectl -n kube-system exec $KUBEARMOR -- grep -E "$1.*policyName.*\"$2|DefaultPosture\".*$match_type.*$3.*resource.*$4.*$5" $ARMOR_LOG | tail -n 1 | grep -v Passed) else audit_log=$(kubectl -n kube-system exec $KUBEARMOR -- grep -E "$1.*policyName.*\"NativePolicy\".*$match_type.*$3.*resource.*$4.*$5" $ARMOR_LOG | tail -n 1 | grep -v Passed) fi @@ -222,7 +222,7 @@ function should_find_blocked_log() { fi else # local if [[ $6 -eq 0 ]]; then - audit_log=$(grep -E "$1.*policyName.*\"$2\".*$match_type.*$3.*resource.*$4.*$5" $ARMOR_LOG | tail -n 1 | grep -v Passed) + audit_log=$(grep -E "$1.*policyName.*\"$2|DefaultPosture\".*$match_type.*$3.*resource.*$4.*$5" $ARMOR_LOG | tail -n 1 | grep -v Passed) else audit_log=$(grep -E "$1.*policyName.*\"NativePolicy\".*$match_type.*$3.*resource.*$4.*$5" $ARMOR_LOG | tail -n 1 | grep -v Passed) fi diff --git a/tests/test-scenarios-local.sh b/tests/test-scenarios-local.sh index 8643762c10..4e05973fc3 100755 --- a/tests/test-scenarios-local.sh +++ b/tests/test-scenarios-local.sh @@ -225,7 +225,7 @@ function should_find_blocked_log() { fi if [[ $6 -eq 0 ]]; then - audit_log=$(grep -E "$1.*policyName.*\"$2\".*$match_type.*$3.*resource.*$4.*$5" $ARMOR_LOG | tail -n 1 | grep -v Passed) + audit_log=$(grep -E "$1.*policyName.*\"$2|DefaultPosture\".*$match_type.*$3.*resource.*$4.*$5" $ARMOR_LOG | tail -n 1 | grep -v Passed) else audit_log=$(grep -E "$1.*policyName.*\"NativePolicy\".*$match_type.*$3.*resource.*$4.*$5" $ARMOR_LOG | tail -n 1 | grep -v Passed) fi