diff --git a/tests/nonk8s_env/hsp/hsp_suite_test.go b/tests/nonk8s_env/hsp/hsp_suite_test.go new file mode 100644 index 0000000000..3b8f09a392 --- /dev/null +++ b/tests/nonk8s_env/hsp/hsp_suite_test.go @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Authors of KubeArmor + +package hsp_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestHsp(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Hsp Suite") +} diff --git a/tests/nonk8s_env/hsp/hsp_test.go b/tests/nonk8s_env/hsp/hsp_test.go new file mode 100644 index 0000000000..cc01fadb20 --- /dev/null +++ b/tests/nonk8s_env/hsp/hsp_test.go @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Authors of KubeArmor + +package hsp + +import ( + "os" + "time" + + . "github.com/kubearmor/KubeArmor/tests/util" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("Non-k8s HSP tests", func() { + + AfterEach(func() { + KarmorLogStop() + }) + + BeforeEach(func() { + // Set the environment variable + os.Setenv("KUBEARMOR_SERVICE", ":32767") + }) + + Describe("HSP file path block", func() { + + It("can block access to /etc/hostname on the host", func() { + + policyPath := "res/hsp-kubearmor-dev-file-path-block.yaml" + err := SendPolicy("ADDED", policyPath) + Expect(err).To(BeNil()) + + // Start the karmor logs + err = KarmorLogStart("policy", "", "File", "") + Expect(err).To(BeNil()) + + // Access the /etc/hostname file + out, err := ExecCommandHost([]string{"bash", "-c", "cat /etc/hostname"}) + Expect(err).NotTo(BeNil()) + Expect(out).To(MatchRegexp(".*Permission denied")) + + // check policy violation alert + _, alerts, err := KarmorGetLogs(5*time.Second, 1) + Expect(err).To(BeNil()) + Expect(len(alerts)).To(BeNumerically(">=", 1)) + Expect(alerts[0].PolicyName).To(Equal("hsp-kubearmor-dev-file-path-block")) + Expect(alerts[0].Severity).To(Equal("5")) + Expect(alerts[0].Action).To(Equal("Block")) + + // delete the policy + err = SendPolicy("DELETED", policyPath) + Expect(err).To(BeNil()) + + }) + }) + + Describe("HSP Process path block", func() { + + It("can block execution of diff command in host", func() { + + policyPath := "res/hsp-kubearmor-dev-proc-path-block.yaml" + err := SendPolicy("ADDED", policyPath) + Expect(err).To(BeNil()) + + // Start the karmor logs + err = KarmorLogStart("policy", "", "Process", "") + Expect(err).To(BeNil()) + + // call the diff command + out, err := ExecCommandHost([]string{"bash", "-c", "diff --help"}) + Expect(err).NotTo(BeNil()) + Expect(out).To(MatchRegexp(".*Permission denied")) + + // check policy violation alert + _, alerts, err := KarmorGetLogs(5*time.Second, 1) + Expect(err).To(BeNil()) + Expect(len(alerts)).To(BeNumerically(">=", 1)) + Expect(alerts[0].PolicyName).To(Equal("hsp-kubearmor-dev-proc-path-block")) + Expect(alerts[0].Severity).To(Equal("5")) + Expect(alerts[0].Action).To(Equal("Block")) + + // delete the policy + err = SendPolicy("DELETED", policyPath) + Expect(err).To(BeNil()) + }) + }) + + Describe("HSP dir block from source", func() { + + It("can allow access to everything except /etc/default/* from head", func() { + + policyPath := "res/hsp-kubearmor-dev-file-dir-block-fromSource.yaml" + err := SendPolicy("ADDED", policyPath) + Expect(err).To(BeNil()) + + // Start the karmor logs + err = KarmorLogStart("policy", "", "File", "") + Expect(err).To(BeNil()) + + // call the head command + out, err := ExecCommandHost([]string{"bash", "-c", "head /etc/hostname"}) + Expect(err).To(BeNil()) + Expect(out).NotTo(MatchRegexp(".*Permission denied")) + + // check policy violation alert + _, alerts, err := KarmorGetLogs(5*time.Second, 1) + Expect(err).To(BeNil()) + Expect(len(alerts)).To(BeNumerically("==", 0)) + + // delete the policy + err = SendPolicy("DELETED", policyPath) + Expect(err).To(BeNil()) + }) + + It("can block access to /etc/default/* from head", func() { + + policyPath := "res/hsp-kubearmor-dev-file-dir-block-fromSource.yaml" + err := SendPolicy("ADDED", policyPath) + Expect(err).To(BeNil()) + + // Start the karmor logs + err = KarmorLogStart("policy", "", "File", "") + Expect(err).To(BeNil()) + + // call the head command + out, err := ExecCommandHost([]string{"bash", "-c", "head /etc/default/useradd"}) + Expect(err).NotTo(BeNil()) + Expect(out).To(MatchRegexp(".*Permission denied")) + + // check policy violation alert + _, alerts, err := KarmorGetLogs(5*time.Second, 1) + Expect(err).To(BeNil()) + Expect(len(alerts)).To(BeNumerically(">=", 1)) + Expect(alerts[0].PolicyName).To(Equal("hsp-kubearmor-dev-file-dir-block-fromsource")) + Expect(alerts[0].Severity).To(Equal("5")) + Expect(alerts[0].Action).To(Equal("Block")) + + // delete the policy + err = SendPolicy("DELETED", policyPath) + Expect(err).To(BeNil()) + }) + }) + + Describe("HSP file audit", func() { + + It("can audit access to /etc/passwd", func() { + + policyPath := "res/hsp-kubearmor-dev-file-path-audit.yaml" + err := SendPolicy("ADDED", policyPath) + Expect(err).To(BeNil()) + + // Start the karmor logs + err = KarmorLogStart("policy", "", "File", "") + Expect(err).To(BeNil()) + + // try to access the /etc/passwd file + out, err := ExecCommandHost([]string{"bash", "-c", "cat /etc/passwd"}) + Expect(err).To(BeNil()) + Expect(out).ToNot(MatchRegexp(".*Permission denied")) + + // check audit alerts + _, alerts, err := KarmorGetLogs(5*time.Second, 1) + Expect(err).To(BeNil()) + Expect(len(alerts)).To(BeNumerically(">=", 1)) + Expect(alerts[0].PolicyName).To(Equal("hsp-kubearmor-dev-file-path-audit")) + Expect(alerts[0].Severity).To(Equal("5")) + Expect(alerts[0].Action).To(Equal("Audit")) + + // delete the policy + err = SendPolicy("DELETED", policyPath) + Expect(err).To(BeNil()) + }) + }) + + Describe("HSP path block from source", func() { + + It("It can block access to /etc/hostname from head", func() { + + policyPath := "res/hsp-kubearmor-dev-file-path-block-fromSource.yaml" + err := SendPolicy("ADDED", policyPath) + Expect(err).To(BeNil()) + + // Start the karmor logs + err = KarmorLogStart("policy", "", "File", "") + Expect(err).To(BeNil()) + + // try to access the /etc/hostname file from head + out, err := ExecCommandHost([]string{"bash", "-c", "head /etc/hostname"}) + Expect(err).NotTo(BeNil()) + Expect(out).To(MatchRegexp(".*Permission denied")) + + // check policy violation alert + _, alerts, err := KarmorGetLogs(5*time.Second, 1) + Expect(err).To(BeNil()) + Expect(len(alerts)).To(BeNumerically(">=", 1)) + Expect(alerts[0].PolicyName).To(Equal("hsp-kubearmor-dev-file-path-block-fromsource")) + Expect(alerts[0].Severity).To(Equal("5")) + Expect(alerts[0].Action).To(Equal("Block")) + + // delete the policy + err = SendPolicy("DELETED", policyPath) + Expect(err).To(BeNil()) + }) + }) + + // Describe("HSP Process path block from source", func() { + + // It("can block date command from bash", func() { + + // policyPath := "res/hsp-kubearmor-dev-proc-path-block-fromSource.yaml" + // err := SendPolicy("ADDED", policyPath) + // Expect(err).To(BeNil()) + + // // Start the karmor logs + // err = KarmorLogStart("policy", "", "Process", "") + // Expect(err).To(BeNil()) + + // // call the date command from bash + // out, err := ExecCommandHost([]string{"bash", "-c", "date"}) + // Expect(err).To(BeNil()) + // Expect(out).To(MatchRegexp(".*Permission denied")) + + // // // execute ls command from bash + // // out2, err := ExecCommandHost([]string{"bash", "-c", "ls"}) + // // Expect(err).To(BeNil()) + // // Expect(out2).NotTo(MatchRegexp(".*Permission denied")) + + // // check policy violation alert + // _, alerts, err := KarmorGetLogs(5*time.Second, 1) + // Expect(err).To(BeNil()) + // Expect(len(alerts)).To(BeNumerically(">=", 1)) + // Expect(alerts[0].PolicyName).To(Equal("hsp-kubearmor-dev-proc-path-block-fromsource")) + // Expect(alerts[0].Severity).To(Equal("5")) + // Expect(alerts[0].Action).To(Equal("Block")) + + // // delete the policy + // err = SendPolicy("DELETED", policyPath) + // Expect(err).To(BeNil()) + // }) + // }) + + Describe("HSP Process path block", func() { + + It("can block diff command", func() { + + policyPath := "res/hsp-kubearmor-dev-proc-path-block.yaml" + err := SendPolicy("ADDED", policyPath) + Expect(err).To(BeNil()) + + // Start the karmor logs + err = KarmorLogStart("policy", "", "Process", "") + Expect(err).To(BeNil()) + + // run diff command + out, err := ExecCommandHost([]string{"bash", "-c", "diff"}) + Expect(err).NotTo(BeNil()) + Expect(out).To(MatchRegexp(".*Permission denied")) + + // check policy violation alert + _, alerts, err := KarmorGetLogs(5*time.Second, 1) + Expect(err).To(BeNil()) + Expect(len(alerts)).To(BeNumerically(">=", 1)) + Expect(alerts[0].PolicyName).To(Equal("hsp-kubearmor-dev-proc-path-block")) + Expect(alerts[0].Severity).To(Equal("5")) + Expect(alerts[0].Action).To(Equal("Block")) + + // delete the policy + err = SendPolicy("DELETED", policyPath) + Expect(err).To(BeNil()) + }) + }) + + Describe("HSP Network path block", func() { + + It("can block access to UDP protocol from curl", func() { + + policyPath := "res/hsp-kubearmor-dev-udp-block.yaml" + err := SendPolicy("ADDED", policyPath) + Expect(err).To(BeNil()) + + // Start the karmor logs + err = KarmorLogStart("policy", "", "Network", "") + Expect(err).To(BeNil()) + + // run diff command + out, err := ExecCommandHost([]string{"bash", "-c", "curl google.com"}) + Expect(err).NotTo(BeNil()) + Expect(out).To(MatchRegexp(".*Could not resolve host: google.com")) + + // check policy violation alert + _, alerts, err := KarmorGetLogs(5*time.Second, 1) + Expect(err).To(BeNil()) + Expect(len(alerts)).To(BeNumerically(">=", 1)) + Expect(alerts[0].PolicyName).To(Equal("hsp-kubearmor-dev-udp-block-curl")) + Expect(alerts[0].Severity).To(Equal("5")) + Expect(alerts[0].Action).To(Equal("Block")) + + // delete the policy + err = SendPolicy("DELETED", policyPath) + Expect(err).To(BeNil()) + }) + }) +}) diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-dir-allow-fromSource.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-dir-allow-fromSource.yaml new file mode 100644 index 0000000000..00a133c4aa --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-dir-allow-fromSource.yaml @@ -0,0 +1,29 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-file-dir-allow-fromsource +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + file: + matchDirectories: + - dir: /etc/default/ + recursive: true + fromSource: + - path: /usr/bin/head + action: + Allow + +# kubearmor-dev_test_08 + +# test +# $ head /etc/default/useradd +# Default values for useradd(8) ... +# $ head /etc/hostname +# head: /etc/hostname: Permission denied + +# expectation +# /usr/bin/head can only access /etc/default/* +# /usr/bin/head cannot access any others \ No newline at end of file diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-dir-block-fromSource.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-dir-block-fromSource.yaml new file mode 100644 index 0000000000..d92be29a6d --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-dir-block-fromSource.yaml @@ -0,0 +1,28 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-file-dir-block-fromsource +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + file: + matchDirectories: + - dir: /etc/default/ + fromSource: + - path: /usr/bin/head + action: + Block + +# kubearmor-dev_test_09 + +# test +# $ head /etc/default/useradd +# head: useradd: Permission denied +# $ head /etc/hostname +# kubearmor-dev + +# expectation +# /usr/bin/head cannot access /etc/default/* +# /usr/bin/head can access any others \ No newline at end of file diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-allow-fromSource.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-allow-fromSource.yaml new file mode 100644 index 0000000000..59c10830ad --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-allow-fromSource.yaml @@ -0,0 +1,28 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-file-path-allow-fromsource +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + file: + matchPaths: + - path: /etc/hostname + fromSource: + - path: /usr/bin/head + action: + Allow + +# kubearmor-dev_test_07 + +# test +# $ head /etc/hostname +# kubearmor-dev +# $ head /etc/hosts +# head: /etc/hosts: Permission denied + +# expectation +# /usr/bin/head can only access /etc/hostname +# /usr/bin/head cannot access any others \ No newline at end of file diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-audit.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-audit.yaml new file mode 100644 index 0000000000..e545f7bd42 --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-audit.yaml @@ -0,0 +1,25 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-file-path-audit +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + file: + matchPaths: + - path: /etc/passwd + action: + Audit + +# kubearmor-dev_test_02 + +# test +# $ cat /etc/passwd +# ... +# $ head /etc/passwd +# ... + +# expectation +# anyone can access /etc/passwd, but the access would be audited \ No newline at end of file diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-block-fromSource.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-block-fromSource.yaml new file mode 100644 index 0000000000..d405d896de --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-block-fromSource.yaml @@ -0,0 +1,28 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-file-path-block-fromsource +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + file: + matchPaths: + - path: /etc/hostname + fromSource: + - path: /usr/bin/head + action: + Block + +# kubearmor-dev_test_06 + +# test +# $ head /etc/hostname +# head: cannot open '/etc/hostname' for reading: Permission denied +# $ head /etc/hosts +# ... + +# expectation +# /usr/bin/head cannot access /etc/hostname +# /usr/bin/head can access any others \ No newline at end of file diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-block.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-block.yaml new file mode 100644 index 0000000000..323e014505 --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-file-path-block.yaml @@ -0,0 +1,23 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-file-path-block +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + file: + matchPaths: + - path: /etc/hostname + action: + Block + +# kubearmor-dev_test_03 + +# test +# $ cat /etc/hostname +# cat: /etc/hostname: Permission denied + +# expectation +# anyone cannot access /etc/hostname \ No newline at end of file diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-proc-path-allow-fromSource.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-proc-path-allow-fromSource.yaml new file mode 100644 index 0000000000..42270ff8ab --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-proc-path-allow-fromSource.yaml @@ -0,0 +1,31 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-proc-path-allow-fromsource +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + process: + matchPaths: + - path: /bin/date + fromSource: + - path: /bin/bash # ubuntu # ubuntu also uses /usr/bin/bash + - path: /usr/bin/date + fromSource: + - path: /usr/bin/bash # centos + action: + Allow + +# kubearmor-dev_test_05 + +# test +# $ bash -c date +# ... +# $ bash -c ls +# bash: /usr/bin/ls: Permission denied + +# expectation +# (/usr)/bin/bash can only execute (/usr)/bin/date +# (/usr)/bin/bash cannot execute any others \ No newline at end of file diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-proc-path-block-fromSource.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-proc-path-block-fromSource.yaml new file mode 100644 index 0000000000..e6e1482fb2 --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-proc-path-block-fromSource.yaml @@ -0,0 +1,31 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-proc-path-block-fromsource +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + process: + matchPaths: + - path: /bin/date + fromSource: + - path: /bin/bash + - path: /usr/bin/date + fromSource: + - path: /usr/bin/bash + action: + Block + +# kubearmor-dev_test_04 + +# test +# (/home/vagrant/selinux-test/) $ bash -c date +# bash: 1: date: Permission denied +# (/home/vagrant/selinux-test/) $ bash -c ls +# ls ... + +# expectation +# (/usr)/bin/bash cannot execute (/usr)/bin/date +# (/usr)/bin/bash can execute any others \ No newline at end of file diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-proc-path-block.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-proc-path-block.yaml new file mode 100644 index 0000000000..6c2ca56407 --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-proc-path-block.yaml @@ -0,0 +1,23 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-proc-path-block +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + process: + matchPaths: + - path: /usr/bin/diff + action: + Block + +# kubearmor-dev_test_01 + +# test +# $ diff --help +# -bash: /usr/bin/diff: Permission denied + +# expectation +# anyone cannot execute /usr/bin/diff \ No newline at end of file diff --git a/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-udp-block.yaml b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-udp-block.yaml new file mode 100644 index 0000000000..6076b2adef --- /dev/null +++ b/tests/nonk8s_env/hsp/res/hsp-kubearmor-dev-udp-block.yaml @@ -0,0 +1,25 @@ +apiVersion: security.kubearmor.com/v1 +kind: KubeArmorHostPolicy +metadata: + name: hsp-kubearmor-dev-udp-block-curl +spec: + nodeSelector: + matchLabels: + kubearmor.io/hostname: "*" + severity: 5 + network: + matchProtocols: + - protocol: udp + fromSource: + - path: /usr/bin/curl + action: + Block + + +# curl google.com +# curl: (6) Could not resolve host: google.com + +# curl 142.250.194.142 +# ... content + +# resolving google.com requires udp protocol \ No newline at end of file diff --git a/tests/util/kartutil.go b/tests/util/kartutil.go index 345fef4646..fadc608891 100644 --- a/tests/util/kartutil.go +++ b/tests/util/kartutil.go @@ -708,3 +708,18 @@ func ContainerInfo() (*pb.ProbeResponse, error) { } return resp, nil } + +// ExecCommandHost function executes command on the host +func ExecCommandHost(command []string) (string, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + cmd := exec.CommandContext(ctx, command[0], command[1:]...) + output, err := cmd.CombinedOutput() + + if err != nil { + return string(output), err + } + + return string(output), nil +}