diff --git a/configuration/ConfigurationFile.json b/configuration/ConfigurationFile.json new file mode 100644 index 0000000000..aa96d004bb --- /dev/null +++ b/configuration/ConfigurationFile.json @@ -0,0 +1,38 @@ +{ + "services": [ + { + "type": "sniffer", + "data": { + "ebpfEngine": { + "type": "falco", + "data": { + "kernelObjPath": "./resources/ebpf/kernel_obj.o", + "ebpfEngineLoaderPath": "./resources/ebpf/userspace_app" + } + }, + "node": { + "name": "minikube" + }, + "features": [ + { + "Name": "relevantCVEs" + } + ], + "containerSniffing": { + "sniffingTime": { + "sniffingMaxTime": "3600" + } + }, + "outputDataStorage": { + "type": "server", + "data": { + "dataStorage": { + "URL": "blabla.com/v1/store" + } + }, + "updateDataPeriod": "120" + } + } + } + ] +} \ No newline at end of file diff --git a/deps/install_dependencies.sh b/deps/install_dependencies.sh index 10089df1f4..d36a3b06c0 100755 --- a/deps/install_dependencies.sh +++ b/deps/install_dependencies.sh @@ -13,4 +13,4 @@ cmake .. make all cd ../../../ cp deps/dependencies/kubescape_ebpf_engine_sc/deps/dependencies/falco-libs/build/driver/bpf/probe.o ../resources/ebpf/kernel_obj.o -cp deps/dependencies/kubescape_ebpf_engine_sc/build/main ../resources/ebpf/sniffer +cp deps/dependencies/kubescape_ebpf_engine_sc/build/main ../resources/ebpf/userspace_app diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000000..d642b20dc8 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,66 @@ +package config + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "os" + v1 "sniffer/internal/config/v1" +) + +const ( + FALCO_EBPF_ENGINE = "falco" + CILIUM_EBPF_ENGINE = "cilium" +) + +var c *Config + +type Config struct { + data v1.ConfigData +} + +func (cfg *Config) getConfigFilePath() (string, bool) { + return os.LookupEnv("SNIFFER_CONFIG") +} + +func (cfg *Config) GetConfigurationData() (io.Reader, error) { + config := Config{} + c = &config + cfgPath, exist := cfg.getConfigFilePath() + if !exist { + return nil, fmt.Errorf("failed to find configuration file path") + } + data, err := os.ReadFile(cfgPath) + if err != nil { + return nil, fmt.Errorf("failed to read configuration file with error %v", err.Error()) + } + + return bytes.NewReader(data), nil +} + +func (cfg *Config) ParseConfiguration(data io.Reader) error { + configData := v1.ConfigData{} + + buf := new(bytes.Buffer) + _, err := buf.ReadFrom(data) + if err != nil { + return err + } + b := buf.Bytes() + err = json.Unmarshal(b, &configData) + if err != nil { + return err + } + cfg.data = configData + + return nil +} + +func IsFalcoEbpfEngine() bool { + return c.data.IsFalcoEbpfEngine() +} + +func GetSyscallFilter() []string { + return c.data.GetFalcoSyscallFilter() +} diff --git a/internal/config/config_data_interface.go b/internal/config/config_data_interface.go new file mode 100644 index 0000000000..46ad794ef1 --- /dev/null +++ b/internal/config/config_data_interface.go @@ -0,0 +1,6 @@ +package config + +type ConfigDataInterface interface { + IsFalcoEbpfEngine() bool + GetFalcoSyscallFilter() []string +} diff --git a/internal/config/config_interface.go b/internal/config/config_interface.go index 95937a7fee..92171f8f57 100644 --- a/internal/config/config_interface.go +++ b/internal/config/config_interface.go @@ -3,7 +3,6 @@ package config import "io" type ConfigClient interface { - // global configuration GetConfigurationData() (io.Reader, error) ParseConfiguration(data io.Reader) error } diff --git a/internal/config/config_test.go b/internal/config/config_test.go new file mode 100644 index 0000000000..c31eaa072b --- /dev/null +++ b/internal/config/config_test.go @@ -0,0 +1,27 @@ +package config + +import ( + "os" + "testing" +) + +func TestConfig(t *testing.T) { + err := os.Setenv("SNIFFER_CONFIG", "../../configuration/ConfigurationFile.json") + if err != nil { + t.Fatalf("failed to set env SNIFFER_CONFIG with err %v", err) + } + + cfg := Config{} + configData, err := cfg.GetConfigurationData() + if err != nil { + t.Fatalf("GetConfigurationData failed with err %v", err) + } + err = cfg.ParseConfiguration(configData) + if err != nil { + t.Fatalf("ParseConfiguration failed with err %v", err) + } + + if cfg.data.IsFalcoEbpfEngine() == false { + t.Fatalf("IsFalcoEbpfEngine need to be falco") + } +} diff --git a/internal/config/v1/config_data.go b/internal/config/v1/config_data.go new file mode 100644 index 0000000000..5cba55e565 --- /dev/null +++ b/internal/config/v1/config_data.go @@ -0,0 +1,101 @@ +package config + +var falcoSyscallFilter []string + +const ( + FALCO_EBPF_ENGINE_TYPE = "falco" + KUBESCAPE_EBPF_ENGINE_TYPE = "kubescape" +) + +const ( + SNIFFER_SERVICE_RELEVANT_CVES = "relevantCVEs" +) + +// all the struct and arguments names must be visible outside from the package since the json parser package need to parse them + +type FalcoEbpfEngineData struct { + KernelObjPath string `json:"kernelObjPath"` + EbpfEngineLoaderPath string `json:"ebpfEngineLoaderPath"` +} + +type EbpfEngine struct { + EbpfEngineType string `json:"type"` + Data interface{} `json:"data"` +} + +type NodeData struct { + Name string `json:"name"` +} + +type Features struct { + Name string `json:"name"` +} + +type ContainerSniffing struct { + SniffingMaxTime string `json:"sniffingMaxTime"` +} + +type DataStorage struct { + URL string `json:"URL"` +} + +type OutputDataStorageData struct { + DataStorage `json:"dataStorage"` +} + +type OutputDataStorage struct { + OutputDataStorageType string `json:"type"` + Data interface{} `json:"data"` + UpdateDataPeriod string `json:"updateDataPeriod"` +} + +type SnifferData struct { + EbpfEngine `json:"ebpfEngine"` + NodeData `json:"node"` + FeatureList []Features `json:"features"` + ContainerSniffing `json:"containerSniffing"` + OutputDataStorage `json:"outputDataStorage"` +} + +type Services struct { + ServiceType string `json:"type"` + Data interface{} `json:"data"` +} + +type ConfigData struct { + ServicesList []Services `json:"services"` +} + +func (c *ConfigData) IsFalcoEbpfEngine() bool { + for i := range c.ServicesList { + switch v := c.ServicesList[i].Data.(type) { + case map[string]interface{}: + return v["ebpfEngine"].(map[string]interface{})["type"] == FALCO_EBPF_ENGINE_TYPE + default: + return false + } + } + return false +} + +func (c *ConfigData) setFalcoSyscallFilter() { + if c.IsFalcoEbpfEngine() { + for i := range c.ServicesList { + switch v := c.ServicesList[i].Data.(type) { + case SnifferData: + for j := range v.FeatureList { + if v.FeatureList[j].Name == SNIFFER_SERVICE_RELEVANT_CVES { + falcoSyscallFilter = append(falcoSyscallFilter, []string{"open", "openat", "execve", "execveat"}...) + } + } + } + } + } +} + +func (c *ConfigData) GetFalcoSyscallFilter() []string { + if len(falcoSyscallFilter) == 0 { + c.setFalcoSyscallFilter() + } + return falcoSyscallFilter +} diff --git a/main.go b/main.go index da29a2cadf..6f6e5b75f4 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,22 @@ package main +import ( + "fmt" + "sniffer/internal/config" + + "github.com/kubescape/go-logger" + "github.com/kubescape/go-logger/helpers" +) + func main() { + cfg := config.Config{} + configData, err := cfg.GetConfigurationData() + if err != nil { + logger.L().Fatal("", helpers.String("error during getting configuration data: ", fmt.Sprintf("%v", err))) + } + err = cfg.ParseConfiguration(configData) + if err != nil { + logger.L().Fatal("", helpers.String("error during parsing configuration: ", fmt.Sprintf("%v", err))) + } + }