diff --git a/README.md b/README.md index 9a6eb0416..b5852f5d1 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ It works as a single endpoint for as many as you want `Falco` instances : - [**GCP Cloud Run**](https://cloud.google.com/run) - [**GCP Cloud Functions**](https://cloud.google.com/functions) - [**Fission**](https://fission.io) -- [**KNative**](https://knative.dev) +- [**KNative (CloudEvents)**](https://knative.dev) - [**Kubeless**](https://kubeless.io/) - [**OpenFaaS**](https://www.openfaas.com) - [**Tekton**](https://tekton.dev) @@ -520,6 +520,12 @@ gotify: # format: "markdown" # Format of the messages (plaintext, markdown, json) (default: markdown) # 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) + +tekton: + # eventListener: "" # EventListener address, if not empty, Tekton output is enabled + # minimumpriority: "" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) + # mutualtls: false # if true, checkcert flag will be ignored (server cert will always be checked) + # checkcert: true # check if ssl certificate of the output is valid (default: true) ``` Usage : @@ -962,6 +968,12 @@ care of lower/uppercases**) : `yaml: a.b --> envvar: A_B` : - **GOTIFY_FORMAT**: Format of the messages (plaintext, markdown, json) (default: markdown) - **GOTIFY_CHECKCERT**: check if ssl certificate of the output is valid (default: true) - **GOTIFY_MINIMUMPRIORITY**: minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) +- **TEKTON_EVENTLISTENER** : EventListener address, if not empty, Tekton output is enabled +- **TEKTON_MINIMUMPRIORITY** : minimum priority of event for using this output, +order is +`emergency|alert|critical|error|warning|notice|informational|debug or "" (default)` +- **TEKTON_CHECKCERT** : check if ssl certificate of the output is valid (default: +`true`) #### Slack/Rocketchat/Mattermost/Googlechat Message Formatting diff --git a/config.go b/config.go index 885c066c8..d92903cd9 100644 --- a/config.go +++ b/config.go @@ -363,6 +363,10 @@ func getConfig() *types.Configuration { v.SetDefault("Gotify.CheckCert", true) v.SetDefault("Gotify.MinimumPriority", "") + v.SetDefault("Tekton.EventListener", "") + v.SetDefault("Tekton.MinimumPriority", "") + v.SetDefault("Tekton.CheckCert", true) + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.AutomaticEnv() if *configFile != "" { diff --git a/config_example.yaml b/config_example.yaml index a52c46d3a..fed443525 100644 --- a/config_example.yaml +++ b/config_example.yaml @@ -350,4 +350,9 @@ gotify: # token: "" # API Token # format: "markdown" # Format of the messages (plaintext, markdown, json) (default: markdown) # 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 + # minimumpriority: "" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) + +tekton: + # eventListener: "" # EventListener address, if not empty, Tekton output is enabled + # minimumpriority: "" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) + # checkcert: true # check if ssl certificate of the output is valid (default: true) \ No newline at end of file diff --git a/handlers.go b/handlers.go index c6d4958bc..1c77d8f6d 100644 --- a/handlers.go +++ b/handlers.go @@ -298,6 +298,10 @@ func forwardEvent(falcopayload types.FalcoPayload) { go openfaasClient.OpenfaasCall(falcopayload) } + if config.Tekton.EventListener != "" && (falcopayload.Priority >= types.Priority(config.Tekton.MinimumPriority) || falcopayload.Rule == testRule) { + go tektonClient.TektonPost(falcopayload) + } + if config.Rabbitmq.URL != "" && config.Rabbitmq.Queue != "" && (falcopayload.Priority >= types.Priority(config.Openfaas.MinimumPriority) || falcopayload.Rule == testRule) { go rabbitmqClient.Publish(falcopayload) } diff --git a/main.go b/main.go index ef02e1c05..d5d3765af 100644 --- a/main.go +++ b/main.go @@ -47,6 +47,7 @@ var ( gcpCloudRunClient *outputs.Client kubelessClient *outputs.Client openfaasClient *outputs.Client + tektonClient *outputs.Client webUIClient *outputs.Client policyReportClient *outputs.Client rabbitmqClient *outputs.Client @@ -462,6 +463,7 @@ func init() { outputs.EnabledOutputs = append(outputs.EnabledOutputs, "WebUI") } } + if config.PolicyReport.Enabled { var err error policyReportClient, err = outputs.NewPolicyReportClient(config, stats, promStats, statsdClient, dogstatsdClient) @@ -471,6 +473,7 @@ func init() { outputs.EnabledOutputs = append(outputs.EnabledOutputs, "PolicyReport") } } + if config.Openfaas.FunctionName != "" { var err error openfaasClient, err = outputs.NewOpenfaasClient(config, stats, promStats, statsdClient, dogstatsdClient) @@ -481,6 +484,16 @@ func init() { } } + if config.Tekton.EventListener != "" { + var err error + tektonClient, err = outputs.NewClient("Tekton", config.Tekton.EventListener, false, config.Tekton.CheckCert, config, stats, promStats, statsdClient, dogstatsdClient) + if err != nil { + log.Printf("[ERROR] : Tekton - %v\n", err) + } else { + outputs.EnabledOutputs = append(outputs.EnabledOutputs, "Tekton") + } + } + if config.Rabbitmq.URL != "" && config.Rabbitmq.Queue != "" { var err error rabbitmqClient, err = outputs.NewRabbitmqClient(config, stats, promStats, statsdClient, dogstatsdClient) diff --git a/outputs/tekton.go b/outputs/tekton.go new file mode 100644 index 000000000..45c1565d1 --- /dev/null +++ b/outputs/tekton.go @@ -0,0 +1,26 @@ +package outputs + +import ( + "log" + + "github.com/falcosecurity/falcosidekick/types" +) + +// TektonPost posts event to EventListner +func (c *Client) TektonPost(falcopayload types.FalcoPayload) { + c.Stats.Tekton.Add(Total, 1) + + err := c.Post(falcopayload) + if err != nil { + go c.CountMetric(Outputs, 1, []string{"output:tekton", "status:error"}) + c.Stats.Tekton.Add(Error, 1) + c.PromStats.Outputs.With(map[string]string{"destination": "tekton", "status": Error}).Inc() + log.Printf("[ERROR] : Tekton - %v\n", err.Error()) + return + } + + // Setting the success status + go c.CountMetric(Outputs, 1, []string{"output:tekton", "status:ok"}) + c.Stats.Tekton.Add(OK, 1) + c.PromStats.Outputs.With(map[string]string{"destination": "tekton", "status": OK}).Inc() +} diff --git a/outputs/webhook.go b/outputs/webhook.go index 58f843add..f6fd5d094 100644 --- a/outputs/webhook.go +++ b/outputs/webhook.go @@ -6,7 +6,7 @@ import ( "github.com/falcosecurity/falcosidekick/types" ) -// WebhookPost posts event to Slack +// WebhookPost posts event to an URL func (c *Client) WebhookPost(falcopayload types.FalcoPayload) { c.Stats.Webhook.Add(Total, 1) diff --git a/stats.go b/stats.go index 8b3ff555f..adc024ca4 100644 --- a/stats.go +++ b/stats.go @@ -58,6 +58,7 @@ func getInitStats() *types.Statistics { Pagerduty: getOutputNewMap("pagerduty"), Kubeless: getOutputNewMap("kubeless"), Openfaas: getOutputNewMap("openfaas"), + Tekton: getOutputNewMap("tekton"), WebUI: getOutputNewMap("webui"), Rabbitmq: getOutputNewMap("rabbitmq"), Wavefront: getOutputNewMap("wavefront"), diff --git a/types/types.go b/types/types.go index 2c222a44b..a378ecc25 100644 --- a/types/types.go +++ b/types/types.go @@ -63,6 +63,7 @@ type Configuration struct { Pagerduty PagerdutyConfig Kubeless kubelessConfig Openfaas openfaasConfig + Tekton tektonConfig WebUI WebUIOutputConfig PolicyReport PolicyReportConfig Rabbitmq RabbitmqConfig @@ -438,6 +439,13 @@ type openfaasConfig struct { MutualTLS bool } +type tektonConfig struct { + EventListener string + MinimumPriority string + CheckCert bool + MutualTLS bool +} + // WebUIOutputConfig represents parameters for WebUI type WebUIOutputConfig struct { URL string @@ -587,6 +595,7 @@ type Statistics struct { CloudEvents *expvar.Map Kubeless *expvar.Map Openfaas *expvar.Map + Tekton *expvar.Map WebUI *expvar.Map Rabbitmq *expvar.Map Wavefront *expvar.Map