Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Equip KubeArmor with Default Armors #602

Merged
merged 6 commits into from
Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.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 @@ -811,19 +812,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) {
nam-jaehyun marked this conversation as resolved.
Show resolved Hide resolved
} 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 @@ -881,6 +890,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 @@ -984,10 +997,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
daemon1024 marked this conversation as resolved.
Show resolved Hide resolved

profileBody := ""
Expand Down Expand Up @@ -1086,11 +1095,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 @@ -1103,17 +1114,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) {
nam-jaehyun marked this conversation as resolved.
Show resolved Hide resolved
} 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"
}
daemon1024 marked this conversation as resolved.
Show resolved Hide resolved

Expand Down Expand Up @@ -1145,6 +1160,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" {
daemon1024 marked this conversation as resolved.
Show resolved Hide resolved
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
nam-jaehyun marked this conversation as resolved.
Show resolved Hide resolved
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
nam-jaehyun marked this conversation as resolved.
Show resolved Hide resolved
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
nam-jaehyun marked this conversation as resolved.
Show resolved Hide resolved
result: failed
---
operation: Network
condition: SOCK_STREAM
action: Block
nam-jaehyun marked this conversation as resolved.
Show resolved Hide resolved
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)
daemon1024 marked this conversation as resolved.
Show resolved Hide resolved
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