From ae6bbbc7d6b15c6e81076ac50adf19f46efe6edf Mon Sep 17 00:00:00 2001 From: Thomas Labarussias Date: Wed, 31 Aug 2022 19:50:49 +0200 Subject: [PATCH] add Zincsearch output Signed-off-by: Thomas Labarussias --- README.md | 15 +++++++++++++++ config.go | 7 +++++++ config_example.yaml | 10 +++++++++- handlers.go | 4 ++++ main.go | 11 +++++++++++ outputs/zincsearch.go | 37 +++++++++++++++++++++++++++++++++++++ stats.go | 1 + types/types.go | 12 ++++++++++++ 8 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 outputs/zincsearch.go diff --git a/README.md b/README.md index 19f2d9bfd..b29a51d8e 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ It works as a single endpoint for as many as you want `Falco` instances : - [**AWS CloudWatchLogs**](https://aws.amazon.com/cloudwatch/features/) - [**Grafana**](https://grafana.com/) (annotations) - **Syslog** +- [**Zincsearch**](https://docs.zincsearch.com/) ### Object Storage @@ -500,6 +501,14 @@ mqtt: # password: "" # Password if the authentication is enabled in the broker # checkcert: true # check if ssl certificate of the output is valid (default: true) # minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) + +zincsearch: + # hostport: "" # http://{domain or ip}:{port}, if not empty, ZincSearch output is enabled + # index: "falco" # index (default: falco) + # username: "" # use this username to authenticate to ZincSearch (default: "") + # password: "" # use this password to authenticate to ZincSearch (default: "") + # checkcert: true # check if ssl certificate of the output is valid (default: true) + # minimumpriority: "" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) ``` Usage : @@ -932,6 +941,12 @@ care of lower/uppercases**) : `yaml: a.b --> envvar: A_B` : - **MQTT_PASSWORD**: password if the authentication is enabled in the broker - **MQTT_CHECKCERT**: check if ssl certificate of the output is valid (default: `true`) - **MQTT_PRUNEBYPRIORITY**: if true; the events with lowest severity are pruned first, in FIFO order (default: `false`) +- **ZINC_HOSTPORT**: http://{domain or ip}:{port}, if not empty, ZincSearch output is enabled +- **ZINC_INDEX**: index (default: falco) +- **ZINC_USERNAME**: this username to authenticate to ZincSearch (default: "") +- **ZINC_PASSWORD**: use this password to authenticate to ZincSearch (default: "") +- **ZINC_CHECKCERT**: if ssl certificate of the output is valid (default: true) +- **ZINC_MINIMUMPRIORITY**: minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug #### Slack/Rocketchat/Mattermost/Googlechat Message Formatting diff --git a/config.go b/config.go index 2be6f866a..b07f83a92 100644 --- a/config.go +++ b/config.go @@ -349,6 +349,13 @@ func getConfig() *types.Configuration { v.SetDefault("MQTT.CheckCert", true) v.SetDefault("MQTT.MinimumPriority", "") + v.SetDefault("Zincsearch.HostPort", "") + v.SetDefault("Zincsearch.Index", "falco") + v.SetDefault("Zincsearch.Username", "") + v.SetDefault("Zincsearch.Password", "") + v.SetDefault("Zincsearch.CheckCert", true) + v.SetDefault("Zincsearch.MinimumPriority", "") + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.AutomaticEnv() if *configFile != "" { diff --git a/config_example.yaml b/config_example.yaml index 80d33266e..87ded49bb 100644 --- a/config_example.yaml +++ b/config_example.yaml @@ -334,4 +334,12 @@ mqtt: # user: "" # User if the authentication is enabled in the broker # password: "" # Password if the authentication is enabled in the broker # checkcert: true # check if ssl certificate of the output is valid (default: true) - # minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) \ No newline at end of file + # minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) + +zincsearch: + # hostport: "" # http://{domain or ip}:{port}, if not empty, ZincSearch output is enabled + # index: "falco" # index (default: falco) + # username: "" # use this username to authenticate to ZincSearch (default: "") + # password: "" # use this password to authenticate to ZincSearch (default: "") + # checkcert: true # check if ssl certificate of the output is valid (default: true) + # minimumpriority: "" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) \ No newline at end of file diff --git a/handlers.go b/handlers.go index db1649382..7877d2753 100644 --- a/handlers.go +++ b/handlers.go @@ -336,4 +336,8 @@ func forwardEvent(falcopayload types.FalcoPayload) { if config.MQTT.Broker != "" && (falcopayload.Priority >= types.Priority(config.MQTT.MinimumPriority) || falcopayload.Rule == testRule) { go mqttClient.MQTTPublish(falcopayload) } + + if config.Zincsearch.HostPort != "" && (falcopayload.Priority >= types.Priority(config.Zincsearch.MinimumPriority) || falcopayload.Rule == testRule) { + go zincsearchClient.ZincsearchPost(falcopayload) + } } diff --git a/main.go b/main.go index 33c4be186..1648fdfed 100644 --- a/main.go +++ b/main.go @@ -56,6 +56,7 @@ var ( yandexClient *outputs.Client syslogClient *outputs.Client mqttClient *outputs.Client + zincsearchClient *outputs.Client statsdClient, dogstatsdClient *statsd.Client config *types.Configuration @@ -570,6 +571,16 @@ func init() { } } + if config.Zincsearch.HostPort != "" { + var err error + zincsearchClient, err = outputs.NewClient("Zincsearch", config.Zincsearch.HostPort+"/api/"+config.Zincsearch.Index+"/_doc", false, config.Zincsearch.CheckCert, config, stats, promStats, statsdClient, dogstatsdClient) + if err != nil { + config.Zincsearch.HostPort = "" + } else { + outputs.EnabledOutputs = append(outputs.EnabledOutputs, "Zincsearch") + } + } + log.Printf("[INFO] : Falco Sidekick version: %s\n", GetVersionInfo().GitVersion) log.Printf("[INFO] : Enabled Outputs : %s\n", outputs.EnabledOutputs) diff --git a/outputs/zincsearch.go b/outputs/zincsearch.go new file mode 100644 index 000000000..249b7b761 --- /dev/null +++ b/outputs/zincsearch.go @@ -0,0 +1,37 @@ +package outputs + +import ( + "fmt" + "log" + + "github.com/falcosecurity/falcosidekick/types" +) + +// ZincsearchPost posts event to Zincsearch +func (c *Client) ZincsearchPost(falcopayload types.FalcoPayload) { + c.Stats.Zincsearch.Add(Total, 1) + + if c.Config.Zincsearch.Username != "" && c.Config.Zincsearch.Password != "" { + c.BasicAuth(c.Config.Zincsearch.Username, c.Config.Zincsearch.Password) + } + + fmt.Println(c.EndpointURL) + err := c.Post(falcopayload) + if err != nil { + c.setZincsearchErrorMetrics() + log.Printf("[ERROR] : Zincsearch - %v\n", err) + return + } + + // Setting the success status + go c.CountMetric(Outputs, 1, []string{"output:zincsearch", "status:ok"}) + c.Stats.Zincsearch.Add(OK, 1) + c.PromStats.Outputs.With(map[string]string{"destination": "zincsearch", "status": OK}).Inc() +} + +// setZincsearchErrorMetrics set the error stats +func (c *Client) setZincsearchErrorMetrics() { + go c.CountMetric(Outputs, 1, []string{"output:zincsearch", "status:error"}) + c.Stats.Zincsearch.Add(Error, 1) + c.PromStats.Outputs.With(map[string]string{"destination": "zincsearch", "status": Error}).Inc() +} diff --git a/stats.go b/stats.go index 6914e2139..be79f755b 100644 --- a/stats.go +++ b/stats.go @@ -69,6 +69,7 @@ func getInitStats() *types.Statistics { MQTT: getOutputNewMap("mqtt"), PolicyReport: getOutputNewMap("policyreport"), NodeRed: getOutputNewMap("nodered"), + Zincsearch: getOutputNewMap("zincsearch"), } stats.Falco.Add(outputs.Emergency, 0) stats.Falco.Add(outputs.Alert, 0) diff --git a/types/types.go b/types/types.go index aec5947f1..e3a9035e6 100644 --- a/types/types.go +++ b/types/types.go @@ -73,6 +73,7 @@ type Configuration struct { Syslog SyslogConfig NodeRed NodeRedOutputConfig MQTT MQTTConfig + Zincsearch zincsearchOutputConfig } // SlackOutputConfig represents parameters for Slack @@ -524,6 +525,16 @@ type fissionConfig struct { MutualTLS bool } +// zincsearchOutputConfig represents config parameters for Zincsearch +type zincsearchOutputConfig struct { + HostPort string + Index string + Username string + Password string + CheckCert bool + MinimumPriority string +} + // Statistics is a struct to store stastics type Statistics struct { Requests *expvar.Map @@ -577,6 +588,7 @@ type Statistics struct { PolicyReport *expvar.Map NodeRed *expvar.Map MQTT *expvar.Map + Zincsearch *expvar.Map } // PromStatistics is a struct to store prometheus metrics