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

Improved container and host policy fuzzer #1891

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
212 changes: 147 additions & 65 deletions KubeArmor/core/containerPolicy_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package core
import (
"context"
"testing"
"encoding/json"
tp "github.com/kubearmor/KubeArmor/KubeArmor/types"

"github.com/kubearmor/KubeArmor/KubeArmor/policy"
pb "github.com/kubearmor/KubeArmor/protobuf"
Expand All @@ -13,78 +15,146 @@ import (
func FuzzContainerPolicy(f *testing.F) {
Data1 := &pb.Policy{
Policy: []byte(`
apiVersion: security.kubearmor.com/v1
kind: KubeArmorPolicy
metadata:
name: ksp-group-1-proc-path-block
namespace: multiubuntu
spec:
selector:
matchLabels:
group: group-1
process:
matchPaths:
- path: /bin/sleep
action:
Block
{
"type": "ContainerPolicy",
"object": {
"apiVersion": "security.kubearmor.com/v1",
"kind": "KubeArmorPolicy",
"metadata": {
"name": "ksp-group-1-proc-path-block",
"namespace": "multiubuntu"
},
"spec": {
"selector": {
"matchLabels": {
"group": "group-1"
}
},
"process": {
"matchPaths": [
{
"path": "/bin/sleep"
}
]
},
"action": "Block"
}
}
}


`),
}
//ksp-group-2-allow-file-path-from-source-path.yaml
Data2 := &pb.Policy{
Policy: []byte(`
apiVersion: security.kubearmor.com/v1
kind: KubeArmorPolicy
metadata:
name: ksp-group-2-allow-file-path-from-source-path
namespace: multiubuntu
spec:
severity: 5
message: "allow /bin/cat to access /secret.txt"
selector:
matchLabels:
group: group-2
process:
matchDirectories:
- dir: /bin/
recursive: true
file:
matchPaths:
- path: /secret.txt
fromSource:
- path: /bin/cat
- path: /dev/tty
- path: /lib/terminfo/x/xterm
matchDirectories:
- dir: /pts/
recursive: true
- dir: /proc/
recursive: true
- dir: /dev/
recursive: true
- dir: /lib/x86_64-linux-gnu/
- dir: /bin/
action:
Allow
{
"type": "ContainerPolicy",
"object": {
"apiVersion": "security.kubearmor.com/v1",
"kind": "KubeArmorPolicy",
"metadata": {
"name": "ksp-group-2-allow-file-path-from-source-path",
"namespace": "multiubuntu"
},
"spec": {
"severity": 5,
"message": "allow /bin/cat to access /secret.txt",
"selector": {
"matchLabels": {
"group": "group-2"
}
},
"process": {
"matchDirectories": [
{
"dir": "/bin/",
"recursive": true
}
]
},
"file": {
"matchPaths": [
{
"path": "/secret.txt",
"fromSource": [
{
"path": "/bin/cat"
}
]
},
{
"path": "/dev/tty"
},
{
"path": "/lib/terminfo/x/xterm"
}
],
"matchDirectories": [
{
"dir": "/pts/",
"recursive": true
},
{
"dir": "/proc/",
"recursive": true
},
{
"dir": "/dev/",
"recursive": true
},
{
"dir": "/lib/x86_64-linux-gnu/"
},
{
"dir": "/bin/"
}
]
},
"action": "Allow"
}
}
}


`),
}

Data3 := &pb.Policy{
Policy: []byte(`
apiVersion: security.kubearmor.com/v1
kind: KubeArmorPolicy
metadata:
name: ksp-ubuntu-1-allow-net-tcp-from-source
namespace: multiubuntu
spec:
severity: 8
selector:
matchLabels:
container: ubuntu-1
network:
matchProtocols:
- protocol: tcp
fromSource:
- path: /usr/bin/curl
action: Allow
{
"type": "ContainerPolicy",
"object": {
"apiVersion": "security.kubearmor.com/v1",
"kind": "KubeArmorPolicy",
"metadata": {
"name": "ksp-ubuntu-1-allow-net-tcp-from-source",
"namespace": "multiubuntu"
},
"spec": {
"severity": 8,
"selector": {
"matchLabels": {
"container": "ubuntu-1"
}
},
"network": {
"matchProtocols": [
{
"protocol": "tcp",
"fromSource": [
{
"path": "/usr/bin/curl"
}
]
}
]
},
"action": "Allow"
}
}
}

`),
}

Expand All @@ -101,12 +171,24 @@ spec:
policy := &pb.Policy{
Policy: data,
}
policyEvent := tp.K8sKubeArmorPolicyEvent{}
if err := json.Unmarshal(data, &policyEvent); err != nil {
// Skip invalid JSON requests that may be generated during fuzz
t.Skip("invalid json")
}
res, err := p.ContainerPolicy(context.Background(), policy)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if res.Status != pb.PolicyStatus_Invalid && res.Status != pb.PolicyStatus_Applied && res.Status != pb.PolicyStatus_Modified {
t.Errorf("Unexpected status: %v, %v", res.Status, data)
if res.Status != pb.PolicyStatus_Applied && res.Status != pb.PolicyStatus_Modified {
if policyEvent.Object.Metadata.Name == "" && res.Status == pb.PolicyStatus_Invalid{
t.Skip("no name metadata")
}
if len(policyEvent.Object.Spec.Selector.MatchLabels) == 0 && res.Status == pb.PolicyStatus_Invalid{
t.Skip("No labels to match found on policy.")
}

t.Errorf("Unexpected status: %v", res.Status)
}
})
}
84 changes: 58 additions & 26 deletions KubeArmor/core/hostPolicy_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,58 @@ import (
"github.com/kubearmor/KubeArmor/KubeArmor/policy"
pb "github.com/kubearmor/KubeArmor/protobuf"
"testing"
"encoding/json"
tp "github.com/kubearmor/KubeArmor/KubeArmor/types"

)

func FuzzHostPolicy(f *testing.F) {
data := &pb.Policy{
Policy: []byte(`
apiVersion: security.kubearmor.com/v1
kind: KubeArmorHostPolicy
metadata:
name: hsp-cve-2019-14271
spec:
tags: ["CVE-2019-14271","docker-cp","libraries","docker-tar","root-code-execution"]
message: "Alert! Docker Binary Has Been Executed."
nodeSelector:
matchLabels:
kubernetes.io/hostname: gke-ubuntu #change with your hostname
process:
severity: 2
matchPaths:
- path: /usr/bin/docker
- path: /usr/sbin/chroot
- path: /usr/lib/tar
- path: /usr/lib/chmod
action: Block
file:
severity: 3
matchDirectories:
- dir: /lib/x86_64-linux-gnu/
- dir: /var/log/
action: Block
{
"type": "HostPolicy",
"object": {
"apiVersion": "security.kubearmor.com/v1",
"kind": "KubeArmorHostPolicy",
"metadata": {
"name": "hsp-cve-2019-14271"
},
"spec": {
"tags": [
"CVE-2019-14271",
"docker-cp",
"libraries",
"docker-tar",
"root-code-execution"
],
"message": "Alert! Docker Binary Has Been Executed.",
"nodeSelector": {
"matchLabels": {
"kubernetes.io/hostname": "gke-ubuntu"
}
},
"process": {
"severity": 2,
"matchPaths": [
{ "path": "/usr/bin/docker" },
{ "path": "/usr/sbin/chroot" },
{ "path": "/usr/lib/tar" },
{ "path": "/usr/lib/chmod" }
],
"action": "Block"
},
"file": {
"severity": 3,
"matchDirectories": [
{ "dir": "/lib/x86_64-linux-gnu/" },
{ "dir": "/var/log/" }
],
"action": "Block"
}
}
}


`),
}
dm := NewKubeArmorDaemon()
Expand All @@ -48,12 +71,21 @@ spec:
policy := &pb.Policy{
Policy: data,
}
policyEvent := tp.K8sKubeArmorPolicyEvent{}
if err := json.Unmarshal(data, &policyEvent); err != nil {
// Skip invalid JSON requests that may be generated during fuzz
t.Skip("invalid json")
}
res, err := p.HostPolicy(context.Background(), policy)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if res.Status != pb.PolicyStatus_Invalid && res.Status != pb.PolicyStatus_Applied {
t.Errorf("Unexpected status: %v, %v", res.Status, data)
if len(policyEvent.Object.Spec.Selector.MatchLabels) == 0 && res.Status == pb.PolicyStatus_Invalid{
t.Skip("No labels to match found on policy.")
}

if res.Status != pb.PolicyStatus_Applied {
t.Errorf("Unexpected status: %v", res.Status)
}
})
}
8 changes: 5 additions & 3 deletions KubeArmor/policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
)

// PolicyServer provides structure to serve Policy gRPC service
type PolicyServer struct {

Check warning on line 17 in KubeArmor/policy/policy.go

View workflow job for this annotation

GitHub Actions / go-lint

type name will be used as policy.PolicyServer by other packages, and that stutters; consider calling this Server
pb.PolicyServiceServer
UpdateContainerPolicy func(tp.K8sKubeArmorPolicyEvent) pb.PolicyStatus
UpdateHostPolicy func(tp.K8sKubeArmorHostPolicyEvent) pb.PolicyStatus
Expand All @@ -23,7 +23,7 @@
}

// ContainerPolicy accepts container events on gRPC and update container security policies
func (p *PolicyServer) ContainerPolicy(c context.Context, data *pb.Policy) (*pb.Response, error) {

Check warning on line 26 in KubeArmor/policy/policy.go

View workflow job for this annotation

GitHub Actions / go-lint

parameter 'c' seems to be unused, consider removing or renaming it as _
res := new(pb.Response)
if !p.ContainerPolicyEnabled {
res.Status = pb.PolicyStatus_NotEnabled
Expand All @@ -43,19 +43,20 @@
res.Status = pb.PolicyStatus_Invalid
kg.Warn("Empty Container Policy Event")
}

return res, nil

} else {

kg.Warn("Invalid Container Policy Event")

res.Status = pb.PolicyStatus_Invalid
return res, err
}

Check warning on line 54 in KubeArmor/policy/policy.go

View workflow job for this annotation

GitHub Actions / go-lint

if block ends with a return statement, so drop this else and outdent its block

return res, nil
}

// HostPolicy accepts host policy event on gRPC service and updates host security policies. It responds with 1 if success else 0.
func (p *PolicyServer) HostPolicy(c context.Context, data *pb.Policy) (*pb.Response, error) {

Check warning on line 59 in KubeArmor/policy/policy.go

View workflow job for this annotation

GitHub Actions / go-lint

parameter 'c' seems to be unused, consider removing or renaming it as _
res := new(pb.Response)
if !p.HostPolicyEnabled {
res.Status = pb.PolicyStatus_NotEnabled
Expand All @@ -78,11 +79,12 @@
res.Status = pb.PolicyStatus_Invalid

}
return res, nil

} else {
kg.Warn("Invalid Host Policy Event")
res.Status = pb.PolicyStatus_Invalid
return res, err
}

Check warning on line 88 in KubeArmor/policy/policy.go

View workflow job for this annotation

GitHub Actions / go-lint

if block ends with a return statement, so drop this else and outdent its block

return res, nil
}
Loading