Skip to content

Commit

Permalink
Merge pull request kubearmor#602 from daemon1024/default-armor-opt
Browse files Browse the repository at this point in the history
Equip KubeArmor with Default Armors
  • Loading branch information
nam-jaehyun authored Mar 21, 2022
2 parents 5c61070 + dbfb5cc commit 0971f72
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 27 deletions.
25 changes: 25 additions & 0 deletions KubeArmor/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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"

Expand All @@ -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()
Expand All @@ -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)
}

Expand Down Expand Up @@ -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"
Expand Down
41 changes: 30 additions & 11 deletions KubeArmor/enforcer/appArmorProfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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 <abstractions/base>\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"
}

Expand Down Expand Up @@ -882,6 +891,10 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo

fusionProcessWhiteList := []string{}

globalFile := true
globalNetwork := true
globalCapability := true

// preparation

for _, secPolicy := range securityPolicies {
Expand Down Expand Up @@ -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 := ""
Expand Down Expand Up @@ -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
}

Expand All @@ -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"
}

Expand Down Expand Up @@ -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"
Expand Down
60 changes: 48 additions & 12 deletions KubeArmor/feeder/policyMatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 := ""
Expand All @@ -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()
Expand Down Expand Up @@ -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 {
Expand All @@ -873,6 +900,11 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log {
continue
}
}

if secPolicy.Action == "Allow" {
considerNetworkPosture = true
}

}
}

Expand Down Expand Up @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions tests/scenarios/github_test_12/cmd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source: ubuntu-1-deployment
cmd: curl 142.250.193.46
result: passed
---
operation: Network
condition: SOCK_STREAM
action: Allow
7 changes: 7 additions & 0 deletions tests/scenarios/github_test_12/cmd2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source: ubuntu-1-deployment
cmd: curl google.com
result: failed
---
operation: Network
condition: SOCK_DGRAM
action: Block
7 changes: 7 additions & 0 deletions tests/scenarios/github_test_12/cmd3
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion tests/test-scenarios-github.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tests/test-scenarios-in-runtime.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/test-scenarios-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0971f72

Please sign in to comment.