From a8fb83c194c5f3f8273646f63b2b3a5a7cafd729 Mon Sep 17 00:00:00 2001 From: daemon1024 Date: Tue, 30 Jul 2024 11:10:04 +0530 Subject: [PATCH] fix(apparmor/host): streamline host profile generation with container template generation - deprecating special handling of host profiles - making reload of apparmor profiles only in k8s env Signed-off-by: daemon1024 --- KubeArmor/enforcer/appArmorEnforcer.go | 44 +- KubeArmor/enforcer/appArmorHostProfile.go | 799 ---------------------- KubeArmor/enforcer/appArmorProfile.go | 53 +- KubeArmor/enforcer/appArmorTemplate.go | 26 +- KubeArmor/feeder/policyMatcher.go | 8 +- 5 files changed, 77 insertions(+), 853 deletions(-) delete mode 100644 KubeArmor/enforcer/appArmorHostProfile.go diff --git a/KubeArmor/enforcer/appArmorEnforcer.go b/KubeArmor/enforcer/appArmorEnforcer.go index 9f02be266..29d03ecba 100644 --- a/KubeArmor/enforcer/appArmorEnforcer.go +++ b/KubeArmor/enforcer/appArmorEnforcer.go @@ -522,13 +522,16 @@ func (ae *AppArmorEnforcer) UpdateAppArmorProfile(endPoint tp.EndPoint, appArmor ae.Logger.Warnf("Unable to update %d security rule(s) to %s/%s/%s (%s)", policyCount, endPoint.NamespaceName, endPoint.EndPointName, appArmorProfile, err.Error()) return } - if err := kl.RunCommandAndWaitWithErr("aa-disable", []string{"/etc/apparmor.d/" + appArmorProfile}); err != nil { - ae.Logger.Warnf("Unable to disable for a weird issue %d security rule(s) to %s/%s/%s (%s)", policyCount, endPoint.NamespaceName, endPoint.EndPointName, appArmorProfile, err.Error()) - return - } - if err := kl.RunCommandAndWaitWithErr("aa-enforce", []string{"/etc/apparmor.d/" + appArmorProfile}); err != nil { - ae.Logger.Warnf("Unable to enforce back for a weird issue %d security rule(s) to %s/%s/%s (%s)", policyCount, endPoint.NamespaceName, endPoint.EndPointName, appArmorProfile, err.Error()) - return + + if cfg.GlobalCfg.K8sEnv { + if err := kl.RunCommandAndWaitWithErr("aa-disable", []string{"/etc/apparmor.d/" + appArmorProfile}); err != nil { + ae.Logger.Warnf("Unable to disable for a weird issue %d security rule(s) to %s/%s/%s (%s)", policyCount, endPoint.NamespaceName, endPoint.EndPointName, appArmorProfile, err.Error()) + return + } + if err := kl.RunCommandAndWaitWithErr("aa-enforce", []string{"/etc/apparmor.d/" + appArmorProfile}); err != nil { + ae.Logger.Warnf("Unable to enforce back for a weird issue %d security rule(s) to %s/%s/%s (%s)", policyCount, endPoint.NamespaceName, endPoint.EndPointName, appArmorProfile, err.Error()) + return + } } ae.Logger.Printf("Updated %d security rule(s) to %s/%s/%s", policyCount, endPoint.NamespaceName, endPoint.EndPointName, appArmorProfile) @@ -579,7 +582,30 @@ func (ae *AppArmorEnforcer) UpdateAppArmorHostProfile(secPolicies []tp.HostSecur CapabilitiesAction: cfg.GlobalCfg.HostDefaultCapabilitiesPosture, } - if policyCount, newProfile, ok := ae.GenerateAppArmorHostProfile(secPolicies, globalDefaultPosture); ok { + var hostPolicies []tp.SecurityPolicy + + // Typecast HostSecurityPolicy spec to normal SecurityPolicies + for _, secPolicy := range secPolicies { + var hostPolicy tp.SecurityPolicy + if err := kl.Clone(secPolicy.Spec.Process, &hostPolicy.Spec.Process); err != nil { + ae.Logger.Warnf("Error cloning host policy spec process to sec policy construct") + } + if err := kl.Clone(secPolicy.Spec.File, &hostPolicy.Spec.File); err != nil { + ae.Logger.Warnf("Error cloning host policy spec file to sec policy construct") + } + if err := kl.Clone(secPolicy.Spec.Network, &hostPolicy.Spec.Network); err != nil { + ae.Logger.Warnf("Error cloning host policy spec network to sec policy construct") + } + if err := kl.Clone(secPolicy.Spec.Capabilities, &hostPolicy.Spec.Capabilities); err != nil { + ae.Logger.Warnf("Error cloning host policy spec capabilities to sec policy construct") + } + if err := kl.Clone(secPolicy.Spec.Syscalls, &hostPolicy.Spec.Syscalls); err != nil { + ae.Logger.Warnf("Error cloning host policy spec syscall to sec policy construct") + } + hostPolicies = append(hostPolicies, hostPolicy) + } + + if policyCount, newProfile, ok := ae.GenerateAppArmorProfile("kubearmor.host /{usr/,}bin/*sh", hostPolicies, globalDefaultPosture, true); ok { newfile, err := os.Create(filepath.Clean(appArmorHostFile)) if err != nil { ae.Logger.Warnf("Unable to open the KubeArmor host profile in %s (%s)", cfg.GlobalCfg.Host, err.Error()) @@ -619,6 +645,8 @@ func (ae *AppArmorEnforcer) UpdateAppArmorHostProfile(secPolicies []tp.HostSecur ae.Logger.Printf("Updated %d host security rules to the KubeArmor host profile in %s", policyCount, cfg.GlobalCfg.Host) ae.ClearKubeArmorHostFile(appArmorHostFile) + } else if newProfile != "" { + ae.Logger.Errf("Error Generating %s AppArmor profile: %s", appArmorHostFile, newProfile) } } diff --git a/KubeArmor/enforcer/appArmorHostProfile.go b/KubeArmor/enforcer/appArmorHostProfile.go deleted file mode 100644 index 51acac597..000000000 --- a/KubeArmor/enforcer/appArmorHostProfile.go +++ /dev/null @@ -1,799 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2021 Authors of KubeArmor - -package enforcer - -import ( - "bufio" - "fmt" - "strings" - - kl "github.com/kubearmor/KubeArmor/KubeArmor/common" - tp "github.com/kubearmor/KubeArmor/KubeArmor/types" -) - -// == // - -// AllowedHostProcessMatchPaths Function -func (ae *AppArmorEnforcer) AllowedHostProcessMatchPaths(path tp.ProcessPathType, fromSources map[string][]string) { - if len(path.FromSource) == 0 { - // TODO: Why are we not handling whitelist rules without fromsource - return - } - - for _, src := range path.FromSource { - line := "" - - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[src.Path]; !ok { - fromSources[src.Path] = []string{} - } - - if path.OwnerOnly { - line = fmt.Sprintf(" owner %s ix,\n", path.Path) - } else { // !path.OwnerOnly - line = fmt.Sprintf(" %s ix,\n", path.Path) - } - - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// AllowedHostProcessMatchDirectories Function -func (ae *AppArmorEnforcer) AllowedHostProcessMatchDirectories(dir tp.ProcessDirectoryType, fromSources map[string][]string) { - if len(dir.FromSource) == 0 { - return - } - - for _, src := range dir.FromSource { - line := "" - - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - if dir.Recursive && dir.OwnerOnly { - line = fmt.Sprintf(" owner %s{*,**} ix,\n", dir.Directory) - } else if dir.Recursive && !dir.OwnerOnly { - line = fmt.Sprintf(" %s{*,**} ix,\n", dir.Directory) - } else if !dir.Recursive && dir.OwnerOnly { - line = fmt.Sprintf(" owner %s* ix,\n", dir.Directory) - } else { // !dir.Recursive && !dir.OwnerOnly - line = fmt.Sprintf(" %s* ix,\n", dir.Directory) - } - - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// AllowedHostFileMatchPaths Function -func (ae *AppArmorEnforcer) AllowedHostFileMatchPaths(path tp.FilePathType, fromSources map[string][]string) { - if len(path.FromSource) == 0 { - return - } - - for _, src := range path.FromSource { - line := "" - - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - if path.ReadOnly && path.OwnerOnly { - line = fmt.Sprintf(" owner %s r,\n", path.Path) - } else if path.ReadOnly && !path.OwnerOnly { - line = fmt.Sprintf(" %s r,\n", path.Path) - } else if !path.ReadOnly && path.OwnerOnly { - line = fmt.Sprintf(" owner %s rw,\n", path.Path) - } else { // !path.ReadOnly && !path.OwnerOnly - line = fmt.Sprintf(" %s rw,\n", path.Path) - } - - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// AllowedHostFileMatchDirectories Function -func (ae *AppArmorEnforcer) AllowedHostFileMatchDirectories(dir tp.FileDirectoryType, fromSources map[string][]string) { - if len(dir.FromSource) == 0 { - return - } - - for _, src := range dir.FromSource { - line := "" - - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - if dir.ReadOnly && dir.OwnerOnly { - if dir.Recursive { - line = fmt.Sprintf(" owner %s{*,**} r,\n", dir.Directory) - } else { - line = fmt.Sprintf(" owner %s* r,\n", dir.Directory) - } - } else if dir.ReadOnly && !dir.OwnerOnly { - if dir.Recursive { - line = fmt.Sprintf(" %s{*,**} r,\n", dir.Directory) - } else { - line = fmt.Sprintf(" %s* r,\n", dir.Directory) - } - } else if !dir.ReadOnly && dir.OwnerOnly { - if dir.Recursive { - line = fmt.Sprintf(" owner %s{*,**} rw,\n", dir.Directory) - } else { - line = fmt.Sprintf(" owner %s* rw,\n", dir.Directory) - } - } else { // !dir.ReadOnly && !dir.OwnerOnly - if dir.Recursive { - line = fmt.Sprintf(" %s{*,**} rw,\n", dir.Directory) - } else { - line = fmt.Sprintf(" %s* rw,\n", dir.Directory) - } - } - - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// AllowedHostNetworkMatchProtocols Function -func (ae *AppArmorEnforcer) AllowedHostNetworkMatchProtocols(proto tp.NetworkProtocolType, fromSources map[string][]string) { - if len(proto.FromSource) == 0 { - return - } - - for _, src := range proto.FromSource { - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - line := fmt.Sprintf(" network %s,\n", proto.Protocol) - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// AllowedHostCapabilitiesMatchCapabilities Function -func (ae *AppArmorEnforcer) AllowedHostCapabilitiesMatchCapabilities(cap tp.CapabilitiesCapabilityType, fromSources map[string][]string) { - if len(cap.FromSource) == 0 { - return - } - - for _, src := range cap.FromSource { - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - line := fmt.Sprintf(" capability %s,\n", cap.Capability) - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// - -// BlockedHostProcessMatchPaths Function -func (ae *AppArmorEnforcer) BlockedHostProcessMatchPaths(path tp.ProcessPathType, processBlackList *[]string, fromSources map[string][]string) { - proc := "" - if len(path.ExecName) > 0 { - proc = "/**/" + path.ExecName - } else { - proc = path.Path - } - - if proc == "" { - return - } - - if len(path.FromSource) == 0 { - line := "" - - if path.OwnerOnly { - line = fmt.Sprintf(" owner %s ix,\n deny other %s x,\n", proc, proc) - } else { // !path.OwnerOnly - line = fmt.Sprintf(" deny %s x,\n", proc) - } - - if !kl.ContainsElement(*processBlackList, line) { - *processBlackList = append(*processBlackList, line) - } - - return - } - - for _, src := range path.FromSource { - line := "" - - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - if path.OwnerOnly { - line = fmt.Sprintf(" owner %s ix,\n deny other %s x,\n", proc, proc) - } else { // !path.OwnerOnly - line = fmt.Sprintf(" deny %s x,\n", proc) - } - - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// BlockedHostProcessMatchDirectories Function -func (ae *AppArmorEnforcer) BlockedHostProcessMatchDirectories(dir tp.ProcessDirectoryType, processBlackList *[]string, fromSources map[string][]string) { - if len(dir.FromSource) == 0 { - line := "" - - if dir.Recursive && dir.OwnerOnly { - line = fmt.Sprintf(" owner %s{*,**} ix,\n deny other %s{*,**} x,\n", dir.Directory, dir.Directory) - } else if dir.Recursive && !dir.OwnerOnly { - line = fmt.Sprintf(" deny %s{*,**} x,\n", dir.Directory) - } else if !dir.Recursive && dir.OwnerOnly { - line = fmt.Sprintf(" owner %s* ix,\n deny other %s* x,\n", dir.Directory, dir.Directory) - } else { // !dir.Recursive && !dir.OwnerOnly - line = fmt.Sprintf(" deny %s* x,\n", dir.Directory) - } - - if !kl.ContainsElement(*processBlackList, line) { - *processBlackList = append(*processBlackList, line) - } - - return - } - - for _, src := range dir.FromSource { - line := "" - - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - if dir.Recursive && dir.OwnerOnly { - line = fmt.Sprintf(" owner %s{*,**} ix,\n deny other %s{*,**} x,\n", dir.Directory, dir.Directory) - } else if dir.Recursive && !dir.OwnerOnly { - line = fmt.Sprintf(" deny %s{*,**} x,\n", dir.Directory) - } else if !dir.Recursive && dir.OwnerOnly { - line = fmt.Sprintf(" owner %s* ix,\n deny other %s* x,\n", dir.Directory, dir.Directory) - } else { // !dir.Recursive && !dir.OwnerOnly - line = fmt.Sprintf(" deny %s* x,\n", dir.Directory) - } - - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// BlockedHostProcessMatchPatterns Function -func (ae *AppArmorEnforcer) BlockedHostProcessMatchPatterns(pat tp.ProcessPatternType, processBlackList *[]string) { - line := "" - - if pat.OwnerOnly { - line = fmt.Sprintf(" owner %s ix,\n deny other %s x,\n", pat.Pattern, pat.Pattern) - } else { // !path.OwnerOnly - line = fmt.Sprintf(" deny %s x,\n", pat.Pattern) - } - - if !kl.ContainsElement(*processBlackList, line) { - *processBlackList = append(*processBlackList, line) - } -} - -// BlockedHostFileMatchPaths Function -func (ae *AppArmorEnforcer) BlockedHostFileMatchPaths(path tp.FilePathType, fileBlackList *[]string, fromSources map[string][]string) { - if len(path.FromSource) == 0 { - line := "" - - if path.ReadOnly && path.OwnerOnly { - line = fmt.Sprintf(" deny owner %s w,\n deny other %s rw,\n", path.Path, path.Path) - } else if path.ReadOnly && !path.OwnerOnly { - line = fmt.Sprintf(" deny %s w,\n", path.Path) - } else if !path.ReadOnly && path.OwnerOnly { - line = fmt.Sprintf(" owner %s rw,\n deny other %s rw,\n", path.Path, path.Path) - } else { // !path.ReadOnly && !path.OwnerOnly - line = fmt.Sprintf(" deny %s rw,\n", path.Path) - } - - if !kl.ContainsElement(*fileBlackList, line) { - *fileBlackList = append(*fileBlackList, line) - } - - return - } - - for _, src := range path.FromSource { - line := "" - - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - if path.ReadOnly && path.OwnerOnly { - line = fmt.Sprintf(" deny owner %s w,\n deny other %s rw,\n", path.Path, path.Path) - } else if path.ReadOnly && !path.OwnerOnly { - line = fmt.Sprintf(" deny %s w,\n", path.Path) - } else if !path.ReadOnly && path.OwnerOnly { - line = fmt.Sprintf(" owner %s rw,\n deny other %s rw,\n", path.Path, path.Path) - } else { // !path.ReadOnly && !path.OwnerOnly - line = fmt.Sprintf(" deny %s rw,\n", path.Path) - } - - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// BlockedHostFileMatchDirectories Function -func (ae *AppArmorEnforcer) BlockedHostFileMatchDirectories(dir tp.FileDirectoryType, fileBlackList *[]string, fromSources map[string][]string) { - if len(dir.FromSource) == 0 { - line := "" - - if dir.ReadOnly && dir.OwnerOnly { - if dir.Recursive { - line = fmt.Sprintf(" deny owner %s{*,**} w,\n deny other %s{*,**} rw,\n", dir.Directory, dir.Directory) - } else { - line = fmt.Sprintf(" deny owner %s* w,\n deny other %s* rw,\n", dir.Directory, dir.Directory) - } - } else if dir.ReadOnly && !dir.OwnerOnly { - if dir.Recursive { - line = fmt.Sprintf(" deny %s{*,**} w,\n", dir.Directory) - } else { - line = fmt.Sprintf(" deny %s* w,\n", dir.Directory) - } - } else if !dir.ReadOnly && dir.OwnerOnly { - if dir.Recursive { - line = fmt.Sprintf(" owner %s{*,**} rw,\n deny other %s{*,**} rw,\n", dir.Directory, dir.Directory) - } else { - line = fmt.Sprintf(" owner %s* rw,\n deny other %s* w,\n", dir.Directory, dir.Directory) - } - } else { // !dir.ReadOnly && !dir.OwnerOnly - if dir.Recursive { - line = fmt.Sprintf(" deny %s{*,**} rw,\n", dir.Directory) - } else { - line = fmt.Sprintf(" deny %s* rw,\n", dir.Directory) - } - } - - if !kl.ContainsElement(*fileBlackList, line) { - *fileBlackList = append(*fileBlackList, line) - } - - return - } - - for _, src := range dir.FromSource { - line := "" - - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - if dir.ReadOnly && dir.OwnerOnly { - if dir.Recursive { - line = fmt.Sprintf(" deny owner %s{*,**} w,\n deny other %s{*,**} rw,\n", dir.Directory, dir.Directory) - } else { - line = fmt.Sprintf(" deny owner %s* w,\n deny other %s* rw,\n", dir.Directory, dir.Directory) - } - } else if dir.ReadOnly && !dir.OwnerOnly { - if dir.Recursive { - line = fmt.Sprintf(" deny %s{*,**} w,\n", dir.Directory) - } else { - line = fmt.Sprintf(" deny %s* w,\n", dir.Directory) - } - } else if !dir.ReadOnly && dir.OwnerOnly { - if dir.Recursive { - line = fmt.Sprintf(" owner %s{*,**} rw,\n deny other %s{*,**} rw,\n", dir.Directory, dir.Directory) - } else { - line = fmt.Sprintf(" owner %s* rw,\n deny other %s* w,\n", dir.Directory, dir.Directory) - } - } else { // !dir.ReadOnly && !dir.OwnerOnly - if dir.Recursive { - line = fmt.Sprintf(" deny %s{*,**} rw,\n", dir.Directory) - } else { - line = fmt.Sprintf(" deny %s* rw,\n", dir.Directory) - } - } - - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// BlockedHostFileMatchPatterns Function -func (ae *AppArmorEnforcer) BlockedHostFileMatchPatterns(pat tp.FilePatternType, fileBlackList *[]string) { - line := "" - - if pat.ReadOnly && pat.OwnerOnly { - line = fmt.Sprintf(" deny owner %s w,\n deny other %s rw,\n", pat.Pattern, pat.Pattern) - } else if pat.ReadOnly && !pat.OwnerOnly { - line = fmt.Sprintf(" deny %s w,\n", pat.Pattern) - } else if !pat.ReadOnly && pat.OwnerOnly { - line = fmt.Sprintf(" owner %s rw,\n deny other %s rw,\n", pat.Pattern, pat.Pattern) - } else { // !pat.ReadOnly && !pat.OwnerOnly - line = fmt.Sprintf(" deny %s rw,\n", pat.Pattern) - } - - if !kl.ContainsElement(*fileBlackList, line) { - *fileBlackList = append(*fileBlackList, line) - } -} - -// BlockedHostNetworkMatchProtocols Function -func (ae *AppArmorEnforcer) BlockedHostNetworkMatchProtocols(proto tp.NetworkProtocolType, fromSources map[string][]string) { - if len(proto.FromSource) == 0 { - return - } - - for _, src := range proto.FromSource { - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - line := fmt.Sprintf(" deny network %s,\n", proto.Protocol) - if !kl.ContainsElement(fromSources[source], line) { - fromSources[source] = append(fromSources[source], line) - } - } -} - -// BlockedHostCapabilitiesMatchCapabilities Function -func (ae *AppArmorEnforcer) BlockedHostCapabilitiesMatchCapabilities(cap tp.CapabilitiesCapabilityType, fromSources map[string][]string) { - if len(cap.FromSource) == 0 { - return - } - - for _, src := range cap.FromSource { - if len(src.Path) == 0 { - continue - } - - source := src.Path - if _, ok := fromSources[source]; !ok { - fromSources[source] = []string{} - } - - line := fmt.Sprintf(" deny capability %s,\n", cap.Capability) - if !kl.ContainsElement(fromSources[src.Path], line) { - fromSources[src.Path] = append(fromSources[src.Path], line) - } - } -} - -// == // - -// GenerateHostProfileHead Function -func (ae *AppArmorEnforcer) GenerateHostProfileHead() string { - profileHead := `## == Managed by KubeArmor == ## - -#include - -profile kubearmor.host /{usr/,}bin/*sh flags=(attach_disconnected,mediate_deleted) { -## == PRE START == ## -#include -mount, -umount, -signal, -unix, -ptrace, - -file, -network, -capability, -## == PRE END == ## -` - return profileHead -} - -// GenerateHostProfileFoot Function -func (ae *AppArmorEnforcer) GenerateHostProfileFoot() string { - profileFoot := "}\n" - - return profileFoot -} - -// == // - -// GenerateHostProfileBody Function -func (ae *AppArmorEnforcer) GenerateHostProfileBody(securityPolicies []tp.HostSecurityPolicy, defaultPosture tp.DefaultPosture) (int, string) { - count := 0 - - processBlackList := []string{} - - fileBlackList := []string{} - - fromSources := map[string][]string{} - - nativeAppArmorRules := []string{} - - // preparation - - for _, secPolicy := range securityPolicies { - if len(secPolicy.Spec.AppArmor) > 0 { - scanner := bufio.NewScanner(strings.NewReader(secPolicy.Spec.AppArmor)) - for scanner.Scan() { - line := " " + strings.TrimSpace(scanner.Text()) + "\n" - nativeAppArmorRules = append(nativeAppArmorRules, line) - } - } - - if len(secPolicy.Spec.Process.MatchPaths) > 0 { - for _, path := range secPolicy.Spec.Process.MatchPaths { - if path.Action == "Allow" { - ae.AllowedHostProcessMatchPaths(path, fromSources) - } else if path.Action == "Block" { - ae.BlockedHostProcessMatchPaths(path, &processBlackList, fromSources) - } - } - } - if len(secPolicy.Spec.Process.MatchDirectories) > 0 { - for _, dir := range secPolicy.Spec.Process.MatchDirectories { - if dir.Action == "Allow" { - ae.AllowedHostProcessMatchDirectories(dir, fromSources) - } else if dir.Action == "Block" { - ae.BlockedHostProcessMatchDirectories(dir, &processBlackList, fromSources) - } - } - } - if len(secPolicy.Spec.Process.MatchPatterns) > 0 { - for _, pat := range secPolicy.Spec.Process.MatchPatterns { - if pat.Action == "Block" { - ae.BlockedHostProcessMatchPatterns(pat, &processBlackList) - } - } - } - - if len(secPolicy.Spec.File.MatchPaths) > 0 { - for _, path := range secPolicy.Spec.File.MatchPaths { - if path.Action == "Allow" { - ae.AllowedHostFileMatchPaths(path, fromSources) - } else if path.Action == "Block" { - ae.BlockedHostFileMatchPaths(path, &fileBlackList, fromSources) - } - } - } - if len(secPolicy.Spec.File.MatchDirectories) > 0 { - for _, dir := range secPolicy.Spec.File.MatchDirectories { - if dir.Action == "Allow" { - ae.AllowedHostFileMatchDirectories(dir, fromSources) - } else if dir.Action == "Block" { - ae.BlockedHostFileMatchDirectories(dir, &fileBlackList, fromSources) - } - } - } - if len(secPolicy.Spec.File.MatchPatterns) > 0 { - for _, pat := range secPolicy.Spec.File.MatchPatterns { - if pat.Action == "Block" { - ae.BlockedHostFileMatchPatterns(pat, &fileBlackList) - } - } - } - - if len(secPolicy.Spec.Network.MatchProtocols) > 0 { - for _, proto := range secPolicy.Spec.Network.MatchProtocols { - if proto.Action == "Allow" { - ae.AllowedHostNetworkMatchProtocols(proto, fromSources) - } else if proto.Action == "Block" { - ae.BlockedHostNetworkMatchProtocols(proto, fromSources) - } - } - } - - if len(secPolicy.Spec.Capabilities.MatchCapabilities) > 0 { - for _, cap := range secPolicy.Spec.Capabilities.MatchCapabilities { - if cap.Action == "Allow" { - ae.AllowedHostCapabilitiesMatchCapabilities(cap, fromSources) - } else if cap.Action == "Block" { - ae.BlockedHostCapabilitiesMatchCapabilities(cap, fromSources) - } - } - } - } - - // body - - profileBody := "" - - // body - black list - - for _, line := range processBlackList { - profileBody = profileBody + line - } - - count = count + len(processBlackList) - - for _, line := range fileBlackList { - profileBody = profileBody + line - } - - count = count + len(fileBlackList) - - // body - from source - - bodyFromSource := "" - - for source, lines := range fromSources { - bodyFromSource = bodyFromSource + fmt.Sprintf(" %s cx,\n", source) - bodyFromSource = bodyFromSource + fmt.Sprintf(" profile %s {\n", source) - bodyFromSource = bodyFromSource + fmt.Sprintf(" %s rix,\n", source) - - bodyFromSource = bodyFromSource + fmt.Sprintf(" ## == PRE START (%s) == ##\n", source) - - bodyFromSource = bodyFromSource + " #include \n" - bodyFromSource = bodyFromSource + " mount,\n" - bodyFromSource = bodyFromSource + " umount,\n" - bodyFromSource = bodyFromSource + " signal,\n" - bodyFromSource = bodyFromSource + " unix,\n" - bodyFromSource = bodyFromSource + "\n" - - file := true - network := true - capability := true - - for _, line := range lines { - if strings.Contains(line, " network") { // matchProtocols + allow - network = false - continue - } - - if strings.Contains(line, " capability") { // matchCapabilities + allow - capability = false - continue - } - - if strings.Contains(line, " owner") && strings.Contains(line, "deny") { // ownerOnly + block - continue - } - - if strings.Contains(line, " deny") { // block - continue - } - - file = false // matchPaths or matchDirectories + allow - } - - 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 defaultPosture.NetworkAction == "block" && network { - bodyFromSource = bodyFromSource + " network,\n" - } else if defaultPosture.NetworkAction != "block" { - bodyFromSource = bodyFromSource + " network,\n" - } - - if defaultPosture.CapabilitiesAction == "block" && capability { - bodyFromSource = bodyFromSource + " capability,\n" - } else if defaultPosture.CapabilitiesAction != "block" { - bodyFromSource = bodyFromSource + " capability,\n" - } - - bodyFromSource = bodyFromSource + fmt.Sprintf(" ## == PRE END (%s) == ##\n\n", source) - - bodyFromSource = bodyFromSource + fmt.Sprintf(" ## == POLICY START (%s) == ##\n", source) - - bodyFromSource = bodyFromSource + strings.Replace(profileBody, " ", " ", -1) - - for _, line := range lines { - bodyFromSource = bodyFromSource + " " + line - } - - bodyFromSource = bodyFromSource + fmt.Sprintf(" ## == POLICY END (%s) == ##\n", source) - bodyFromSource = bodyFromSource + " }\n" - } - - for _, source := range fromSources { - count = count + len(source) - } - - // body - together - - profileBody = " ## == POLICY START == ##\n" + profileBody + bodyFromSource + " ## == POLICY END == ##\n\n" - - // body - native apparmor - - if len(nativeAppArmorRules) > 0 { - profileBody = profileBody + "\n ## == NATIVE POLICY START == ##\n" - for _, nativeRule := range nativeAppArmorRules { - profileBody = profileBody + nativeRule - } - profileBody = profileBody + " ## == NATIVE POLICY END == ##\n\n" - } - - count = count + len(nativeAppArmorRules) - - return count, profileBody -} - -// GenerateAppArmorHostProfile Function -func (ae *AppArmorEnforcer) GenerateAppArmorHostProfile(secPolicies []tp.HostSecurityPolicy, defaultPosture tp.DefaultPosture) (int, string, bool) { - - // generate a profile body - - count, profileBody := ae.GenerateHostProfileBody(secPolicies, defaultPosture) - - // generate a new profile - - newProfile := ae.GenerateHostProfileHead() + profileBody + ae.GenerateHostProfileFoot() - - // check the new profile with the old profile - - if ae.HostProfile != newProfile { - ae.HostProfile = newProfile - return count, newProfile, true - } - - return 0, "", false -} diff --git a/KubeArmor/enforcer/appArmorProfile.go b/KubeArmor/enforcer/appArmorProfile.go index 9183951b4..6068824db 100644 --- a/KubeArmor/enforcer/appArmorProfile.go +++ b/KubeArmor/enforcer/appArmorProfile.go @@ -77,7 +77,7 @@ func (ae *AppArmorEnforcer) SetProcessMatchPaths(path tp.ProcessPathType, prof * // SetProcessMatchDirectories Function func (ae *AppArmorEnforcer) SetProcessMatchDirectories(dir tp.ProcessDirectoryType, prof *Profile, deny bool, head bool) { - if deny == false { + if !deny { prof.File = head } rule := RuleConfig{} @@ -105,7 +105,7 @@ func (ae *AppArmorEnforcer) SetProcessMatchDirectories(dir tp.ProcessDirectoryTy fromsource.Rules.Init() prof.FromSource[source] = fromsource } - if deny == false { + if !deny { if val, ok := prof.FromSource[source]; ok { val.File = head prof.FromSource[source] = val @@ -117,7 +117,7 @@ func (ae *AppArmorEnforcer) SetProcessMatchDirectories(dir tp.ProcessDirectoryTy // SetProcessMatchPatterns Function func (ae *AppArmorEnforcer) SetProcessMatchPatterns(pat tp.ProcessPatternType, prof *Profile, deny bool, head bool) { - if deny == false { + if !deny { prof.File = head } rule := RuleConfig{} @@ -132,7 +132,7 @@ func (ae *AppArmorEnforcer) SetProcessMatchPatterns(pat tp.ProcessPatternType, p // SetFileMatchPaths Function func (ae *AppArmorEnforcer) SetFileMatchPaths(path tp.FilePathType, prof *Profile, deny bool, head bool) { - if deny == false { + if !deny { prof.File = head } rule := RuleConfig{} @@ -159,7 +159,7 @@ func (ae *AppArmorEnforcer) SetFileMatchPaths(path tp.FilePathType, prof *Profil fromsource.Rules.Init() prof.FromSource[source] = fromsource } - if deny == false { + if !deny { if val, ok := prof.FromSource[source]; ok { val.File = head prof.FromSource[source] = val @@ -171,7 +171,7 @@ func (ae *AppArmorEnforcer) SetFileMatchPaths(path tp.FilePathType, prof *Profil // SetFileMatchDirectories Function func (ae *AppArmorEnforcer) SetFileMatchDirectories(dir tp.FileDirectoryType, prof *Profile, deny bool, head bool) { - if deny == false { + if !deny { prof.File = head } rule := RuleConfig{} @@ -200,7 +200,7 @@ func (ae *AppArmorEnforcer) SetFileMatchDirectories(dir tp.FileDirectoryType, pr fromsource.Rules.Init() prof.FromSource[source] = fromsource } - if deny == false { + if !deny { if val, ok := prof.FromSource[source]; ok { val.File = head prof.FromSource[source] = val @@ -212,7 +212,7 @@ func (ae *AppArmorEnforcer) SetFileMatchDirectories(dir tp.FileDirectoryType, pr // SetFileMatchPatterns Function func (ae *AppArmorEnforcer) SetFileMatchPatterns(pat tp.FilePatternType, prof *Profile, deny bool, head bool) { - if deny == false { + if !deny { prof.File = head } rule := RuleConfig{} @@ -231,7 +231,7 @@ func (ae *AppArmorEnforcer) SetNetworkMatchProtocols(proto tp.NetworkProtocolTyp //forcing the protocol to lowercase proto.Protocol = strings.ToLower(proto.Protocol) - if deny == false { + if !deny { prof.Network = head } rule := RuleConfig{} @@ -254,7 +254,7 @@ func (ae *AppArmorEnforcer) SetNetworkMatchProtocols(proto tp.NetworkProtocolTyp fromsource.Rules.Init() prof.FromSource[source] = fromsource } - if deny == false { + if !deny { if val, ok := prof.FromSource[source]; ok { val.Network = head prof.FromSource[source] = val @@ -266,7 +266,7 @@ func (ae *AppArmorEnforcer) SetNetworkMatchProtocols(proto tp.NetworkProtocolTyp // SetCapabilitiesMatchCapabilities Function func (ae *AppArmorEnforcer) SetCapabilitiesMatchCapabilities(cap tp.CapabilitiesCapabilityType, prof *Profile, deny bool, head bool) { - if deny == false { + if !deny { prof.Capabilities = head } rule := RuleConfig{} @@ -289,7 +289,7 @@ func (ae *AppArmorEnforcer) SetCapabilitiesMatchCapabilities(cap tp.Capabilities fromsource.Rules.Init() prof.FromSource[source] = fromsource } - if deny == false { + if !deny { if val, ok := prof.FromSource[source]; ok { val.Capabilities = head prof.FromSource[source] = val @@ -462,18 +462,31 @@ func (ae *AppArmorEnforcer) GenerateProfileBody(securityPolicies []tp.SecurityPo // GenerateAppArmorProfile Function func (ae *AppArmorEnforcer) GenerateAppArmorProfile(appArmorProfile string, securityPolicies []tp.SecurityPolicy, defaultPosture tp.DefaultPosture, privileged bool) (int, string, bool) { // check apparmor profile + var oldProfile string + if strings.Contains(appArmorProfile, "kubearmor.host") { + if _, err := os.Stat(filepath.Clean("/etc/apparmor.d/" + "kubearmor.host")); os.IsNotExist(err) { + return 0, err.Error(), false + } - if _, err := os.Stat(filepath.Clean("/etc/apparmor.d/" + appArmorProfile)); os.IsNotExist(err) { - return 0, err.Error(), false - } + // get the old profile + profile, err := os.ReadFile(filepath.Clean("/etc/apparmor.d/" + "kubearmor.host")) + if err != nil { + return 0, err.Error(), false + } + oldProfile = string(profile) + } else { + if _, err := os.Stat(filepath.Clean("/etc/apparmor.d/" + appArmorProfile)); os.IsNotExist(err) { + return 0, err.Error(), false + } - // get the old profile + // get the old profile - profile, err := os.ReadFile(filepath.Clean("/etc/apparmor.d/" + appArmorProfile)) - if err != nil { - return 0, err.Error(), false + profile, err := os.ReadFile(filepath.Clean("/etc/apparmor.d/" + appArmorProfile)) + if err != nil { + return 0, err.Error(), false + } + oldProfile = string(profile) } - oldProfile := string(profile) // generate a profile body diff --git a/KubeArmor/enforcer/appArmorTemplate.go b/KubeArmor/enforcer/appArmorTemplate.go index 36d13d5e9..d85ea81e1 100644 --- a/KubeArmor/enforcer/appArmorTemplate.go +++ b/KubeArmor/enforcer/appArmorTemplate.go @@ -121,17 +121,16 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { ## == POST START == ## /lib/x86_64-linux-gnu/{*,**} rm, - + + {{ if not .Privileged }} deny @{PROC}/{*,**^[0-9*],sys/kernel/shm*} wkx, deny @{PROC}/sysrq-trigger rwklx, deny @{PROC}/mem rwklx, deny @{PROC}/kmem rwklx, deny @{PROC}/kcore rwklx, - {{ if not .Privileged }} deny mount, - {{end}} - + deny /sys/[^f]*/** wklx, deny /sys/f[^s]*/** wklx, deny /sys/fs/[^c]*/** wklx, @@ -139,6 +138,7 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { deny /sys/fs/cg[^r]*/** wklx, deny /sys/firmware/efi/efivars/** rwklx, deny /sys/kernel/security/** rwklx, + {{end}} ## == POST END == ## } @@ -288,24 +288,6 @@ profile {{$.Name}}-{{$source}} { ## == POST START == ## /lib/x86_64-linux-gnu/{*,**} rm, - deny @{PROC}/{*,**^[0-9*],sys/kernel/shm*} wkx, - deny @{PROC}/sysrq-trigger rwklx, - deny @{PROC}/mem rwklx, - deny @{PROC}/kmem rwklx, - deny @{PROC}/kcore rwklx, - - {{ if not .Privileged }} - deny mount, - {{end}} - - deny /sys/[^f]*/** wklx, - deny /sys/f[^s]*/** wklx, - deny /sys/fs/[^c]*/** wklx, - deny /sys/fs/c[^g]*/** wklx, - deny /sys/fs/cg[^r]*/** wklx, - deny /sys/firmware/efi/efivars/** rwklx, - deny /sys/kernel/security/** rwklx, - ## == POST END == ## {{- end -}} diff --git a/KubeArmor/feeder/policyMatcher.go b/KubeArmor/feeder/policyMatcher.go index 88f9c1d46..ad0dd7fd2 100644 --- a/KubeArmor/feeder/policyMatcher.go +++ b/KubeArmor/feeder/policyMatcher.go @@ -1760,19 +1760,19 @@ func (fd *Feeder) UpdateMatchedPolicy(log tp.Log) tp.Log { if log.Type == "" { // host log if log.Operation == "Process" { - if setLogFields(&log, existFileAllowPolicy, "allow", fd.Node.ProcessVisibilityEnabled, false) { + if setLogFields(&log, existFileAllowPolicy, cfg.GlobalCfg.DefaultFilePosture, fd.Node.ProcessVisibilityEnabled, false) { return log } } else if log.Operation == "File" { - if setLogFields(&log, existFileAllowPolicy, "allow", fd.Node.FileVisibilityEnabled, false) { + if setLogFields(&log, existFileAllowPolicy, cfg.GlobalCfg.DefaultFilePosture, fd.Node.FileVisibilityEnabled, false) { return log } } else if log.Operation == "Network" { - if setLogFields(&log, existNetworkAllowPolicy, "allow", fd.Node.NetworkVisibilityEnabled, false) { + if setLogFields(&log, existNetworkAllowPolicy, cfg.GlobalCfg.DefaultNetworkPosture, fd.Node.NetworkVisibilityEnabled, false) { return log } } else if log.Operation == "Capabilities" { - if setLogFields(&log, existCapabilitiesAllowPolicy, "allow", fd.Node.CapabilitiesVisibilityEnabled, false) { + if setLogFields(&log, existCapabilitiesAllowPolicy, cfg.GlobalCfg.DefaultCapabilitiesPosture, fd.Node.CapabilitiesVisibilityEnabled, false) { return log } }