diff --git a/README.md b/README.md index 26d81507cf..0c4d8815da 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ Currently available outputs are : - [**PagerDuty**](https://pagerduty.com/) - [**Kubeless**](https://kubeless.io/) - [**OpenFaaS**](https://www.openfaas.com) +- [**Wavefront**](https://www.wavefront.com) - [**WebUI**](https://github.com/falcosecurity/falcosidekick-ui) (a Web UI for displaying latest events in real time) ## Usage @@ -315,6 +316,12 @@ openfaas: kubeconfig: "~/.kube/config" # Kubeconfig file to use (only if falcosidekick is running outside the cluster) # minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) +wavefront: + endpointtype: "direct" # Wavefront endpoint type, must be 'direct' or 'proxy'. If not empty, with endpointhost, Wavefront output is enabled + endpointhost: "bla1.wavefront.com" # Wavefront endpoint address (only the host). If not empty, with endpointhost, Wavefront output is enabled + endpointtoken: "abcd-12345-cabeca-987654321" # Wavefront token. Must be used only when endpointtype is 'direct' + metricname: "falco.alert" # Metric to be created in Wavefront. Defaults to falco.alert + webui: url: "" # WebUI URL, if not empty, WebUI output is enabled ``` @@ -590,6 +597,13 @@ care of lower/uppercases**) : `yaml: a.b --> envvar: A_B` : - **RABBITMQ_QUEUE**: # Rabbitmq Queue name - **RABBITMQ_MINIMUMPRIORITY**: "debug" # minimum priority of event for using this output, order is +- **WAVEFRONT_ENDPOINTTYPE**: Wavefront endpoint type: direct or proxy +- **WAVEFRONT_ENDPOINTHOST**: Wavefront endpoint host +- **WAVEFRONT_ENDPOINTTOKEN**: Wavefront API token to be used when the type is 'direct' +- **WAVEFRONT_ENDPOINTMETRICPORT**: Wavefront endpoint port when type is 'proxy' +- **WAVEFRONT_METRICNAME**: "falco.alert" # Metric name to be created/used in Wavefront +- **WAVEFRONT_MINIMUMPRIORITY**: "debug" # minimum priority of event for using + this output, order is #### Slack/Rocketchat/Mattermost/Googlechat Message Formatting The `SLACK_MESSAGEFORMAT` environment variable and `slack.messageformat` YAML diff --git a/config.go b/config.go index 4068135ba3..7278230dcd 100644 --- a/config.go +++ b/config.go @@ -157,6 +157,15 @@ func getConfig() *types.Configuration { v.SetDefault("Rabbitmq.Queue", "") v.SetDefault("Rabbitmq.MinimumPriority", "") + v.SetDefault("Wavefront.EndpointType", "") + v.SetDefault("Wavefront.EndpointHost", "") + v.SetDefault("Wavefront.EndpointToken", "") + v.SetDefault("Wavefront.MetricName", "falco.alert") + v.SetDefault("Wavefront.MetricPort", 2878) + v.SetDefault("Wavefront.MinimumPriority", "") + v.SetDefault("Wavefront.FlushIntervalSecods", 1) + v.SetDefault("Wavefront.BatchSize", 10000) + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.AutomaticEnv() if *configFile != "" { @@ -245,6 +254,7 @@ func getConfig() *types.Configuration { c.Kubeless.MinimumPriority = checkPriority(c.Kubeless.MinimumPriority) c.Openfaas.MinimumPriority = checkPriority(c.Openfaas.MinimumPriority) c.Rabbitmq.MinimumPriority = checkPriority(c.Rabbitmq.MinimumPriority) + c.Wavefront.MinimumPriority = checkPriority(c.Wavefront.MinimumPriority) c.Slack.MessageFormatTemplate = getMessageFormatTemplate("Slack", c.Slack.MessageFormat) c.Rocketchat.MessageFormatTemplate = getMessageFormatTemplate("Rocketchat", c.Rocketchat.MessageFormat) diff --git a/config_example.yaml b/config_example.yaml index 7ca7afb500..9dbeab6c47 100644 --- a/config_example.yaml +++ b/config_example.yaml @@ -186,3 +186,13 @@ rabbitmq: queue: "" # Rabbitmq Queue name minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) +wavefront: + endpointtype: "" # Wavefront endpoint type, must be 'direct' or 'proxy'. If not empty, with endpointhost, Wavefront output is enabled + endpointhost: "" # Wavefront endpoint address (only the host). If not empty, with endpointhost, Wavefront output is enabled + endpointtoken: "" # Wavefront token. Must be used only when endpointtype is 'direct' + # endpointmetricport: 2878 # Port to send metrics. Only used when endpointtype is 'proxy'. Defaults to 2878 + # metricname: "falco.alert" # Metric to be created in Wavefront. Defaults to falco.alert + # minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) + # batchsize: 10000 # Wavefront batch size. If empty uses the default 10000. Only used when endpointtype is 'direct' + # flushintervalseconds: 1 # Wavefront flush interval in seconds. Defaults to 1 + diff --git a/go.mod b/go.mod index 9a8032b8a1..86d783b4b0 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/spf13/viper v1.7.1 github.com/streadway/amqp v1.0.0 github.com/stretchr/testify v1.7.0 + github.com/wavefronthq/wavefront-sdk-go v0.9.8 // indirect golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93 google.golang.org/api v0.40.0 gopkg.in/alecthomas/kingpin.v2 v2.2.6 diff --git a/go.sum b/go.sum index f1f7616d9c..ebf7dfc9b2 100644 --- a/go.sum +++ b/go.sum @@ -107,6 +107,7 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -135,6 +136,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6Lpu7OAUPR60cds= +github.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -200,6 +203,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -240,6 +244,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -400,6 +405,7 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -417,6 +423,7 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353/go.mod h1:N0SVk0uhy+E1PZ3C9ctsPRlvOPAFPkCNlcPBDkt0N3U= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= @@ -620,6 +627,8 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/wavefronthq/wavefront-sdk-go v0.9.8 h1:6U1HW/sovO1ASbjU8f7iEZEKphDEehaDhdZ5nabb550= +github.com/wavefronthq/wavefront-sdk-go v0.9.8/go.mod h1:JTGsu+KKgxx+GitC65VVdftN2iep1nVpQi/8EGR6v4Y= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= @@ -671,7 +680,10 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= @@ -681,6 +693,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -839,10 +852,12 @@ golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -904,6 +919,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.7.0/go.mod h1:L02bwd0sqlsvRv41G7wGWFCsVNZFv/k1xzGIxeANHGM= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1061,6 +1080,7 @@ k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAG k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= diff --git a/handlers.go b/handlers.go index c2bfcc015f..7c45c5373b 100644 --- a/handlers.go +++ b/handlers.go @@ -237,6 +237,10 @@ func forwardEvent(falcopayload types.FalcoPayload) { go rabbitmqClient.Publish(falcopayload) } + if config.Wavefront.EndpointHost != "" && config.Wavefront.EndpointType != "" && (falcopayload.Priority >= types.Priority(config.Wavefront.MinimumPriority) || falcopayload.Rule == testRule) { + go wavefrontClient.WavefrontPost(falcopayload) + } + if config.WebUI.URL != "" { go webUIClient.WebUIPost(falcopayload) } diff --git a/main.go b/main.go index 624af26617..082431126d 100644 --- a/main.go +++ b/main.go @@ -43,6 +43,7 @@ var ( openfaasClient *outputs.Client webUIClient *outputs.Client rabbitmqClient *outputs.Client + wavefrontClient *outputs.Client statsdClient, dogstatsdClient *statsd.Client config *types.Configuration @@ -396,6 +397,17 @@ func init() { } } + if config.Wavefront.EndpointType != "" && config.Wavefront.EndpointHost != "" { + var err error + wavefrontClient, err = outputs.NewWavefrontClient(config, stats, promStats, statsdClient, dogstatsdClient) + if err != nil { + log.Printf("[ERROR] : Wavefront - %v\n", err) + config.Wavefront.EndpointHost = "" + } else { + outputs.EnabledOutputs = append(outputs.EnabledOutputs, "Wavefront") + } + } + log.Printf("[INFO] : Enabled Outputs : %s\n", outputs.EnabledOutputs) } diff --git a/outputs/client.go b/outputs/client.go index 40b409e944..4ab89a9bf8 100644 --- a/outputs/client.go +++ b/outputs/client.go @@ -6,7 +6,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/streadway/amqp" "io/ioutil" "log" "net/http" @@ -14,6 +13,9 @@ import ( "regexp" "strings" + "github.com/streadway/amqp" + wavefront "github.com/wavefronthq/wavefront-sdk-go/senders" + "cloud.google.com/go/pubsub" "cloud.google.com/go/storage" "github.com/DataDog/datadog-go/statsd" @@ -67,6 +69,7 @@ type Client struct { CloudEventsClient cloudevents.Client KubernetesClient kubernetes.Interface RabbitmqClient *amqp.Channel + WavefrontSender *wavefront.Sender } // NewClient returns a new output.Client for accessing the different API. diff --git a/outputs/wavefront.go b/outputs/wavefront.go new file mode 100644 index 0000000000..0877b12476 --- /dev/null +++ b/outputs/wavefront.go @@ -0,0 +1,103 @@ +package outputs + +import ( + "fmt" + "log" + + "github.com/DataDog/datadog-go/statsd" + "github.com/falcosecurity/falcosidekick/types" + + wavefront "github.com/wavefronthq/wavefront-sdk-go/senders" +) + +// NewWavefrontClient returns a new output.Client for accessing the Wavefront API. +func NewWavefrontClient(config *types.Configuration, stats *types.Statistics, promStats *types.PromStatistics, statsdClient, dogstatsdClient *statsd.Client) (*Client, error) { + + var sender wavefront.Sender + var err error + + batchSize := config.Wavefront.BatchSize + if batchSize < 1 { + batchSize = 10000 // Defaults to 10000 + } + + flushInterval := config.Wavefront.FlushIntervalSeconds + if flushInterval < 1 { + flushInterval = 1 // Defaults to 1s + } + + switch config.Wavefront.EndpointType { + case "direct": + server := fmt.Sprintf("https://%s", config.Wavefront.EndpointHost) + directCfg := &wavefront.DirectConfiguration{ + Server: server, + Token: config.Wavefront.EndpointToken, + FlushIntervalSeconds: flushInterval, + BatchSize: batchSize, + } + sender, err = wavefront.NewDirectSender(directCfg) + case "proxy": + proxyCfg := &wavefront.ProxyConfiguration{ + Host: config.Wavefront.EndpointHost, + MetricsPort: config.Wavefront.EndpointMetricPort, + FlushIntervalSeconds: flushInterval, + } + sender, err = wavefront.NewProxySender(proxyCfg) + default: + return nil, fmt.Errorf("failed to configure wavefront sender: invalid type %s", config.Wavefront.EndpointType) + } + + if err != nil { + return nil, fmt.Errorf("failed to configure wavefront %s sender: %s", config.Wavefront.EndpointType, err) + } + + return &Client{ + OutputType: "Wavefront", + Config: config, + WavefrontSender: &sender, + Stats: stats, + PromStats: promStats, + StatsdClient: statsdClient, + DogstatsdClient: dogstatsdClient, + }, nil + +} + +// WavefrontPost sends metrics to WaveFront. +func (c *Client) WavefrontPost(falcopayload types.FalcoPayload) { + + tags := make(map[string]string) + tags["severity"] = falcopayload.Priority.String() + tags["rule"] = falcopayload.Rule + + for tag, value := range falcopayload.OutputFields { + switch v := value.(type) { + case string: + tags[tag] = v + default: + continue + } + } + + c.Stats.Wavefront.Add(Total, 1) + + if c.WavefrontSender != nil { + sender := *c.WavefrontSender + // TODO: configurable metric name + if err := sender.SendMetric(c.Config.Wavefront.MetricName, 1, falcopayload.Time.UnixNano(), "falco-exporter", tags); err != nil { + c.Stats.Wavefront.Add(Error, 1) + c.PromStats.Outputs.With(map[string]string{"destination": "wavefront", "status": Error}).Inc() + log.Printf("[ERROR] : Wavefront - Unable to send event %s: %s\n", falcopayload.Rule, err) + return + } + if err := sender.Flush(); err != nil { + c.Stats.Wavefront.Add(Error, 1) + c.PromStats.Outputs.With(map[string]string{"destination": "wavefront", "status": Error}).Inc() + log.Printf("[ERROR] : Wavefront - Unable to flush event %s: %s\n", falcopayload.Rule, err) + return + } + c.Stats.Wavefront.Add(OK, 1) + c.PromStats.Outputs.With(map[string]string{"destination": "wavefront", "status": OK}).Inc() + log.Printf("[INFO] : Wavefront - Send Event OK %s\n", falcopayload.Rule) + } +} diff --git a/stats.go b/stats.go index 3bfb80cc3d..e8033dae48 100644 --- a/stats.go +++ b/stats.go @@ -55,6 +55,7 @@ func getInitStats() *types.Statistics { Openfaas: getOutputNewMap("openfaas"), WebUI: getOutputNewMap("webui"), Rabbitmq: getOutputNewMap("rabbitmq"), + Wavefront: getOutputNewMap("wavefront"), } stats.Falco.Add(outputs.Emergency, 0) stats.Falco.Add(outputs.Alert, 0) diff --git a/types/types.go b/types/types.go index 8d9267f93b..586b457ba5 100644 --- a/types/types.go +++ b/types/types.go @@ -53,6 +53,7 @@ type Configuration struct { Openfaas openfaasConfig WebUI WebUIOutputConfig Rabbitmq RabbitmqConfig + Wavefront WavefrontOutputConfig } // SlackOutputConfig represents parameters for Slack @@ -91,6 +92,17 @@ type MattermostOutputConfig struct { MessageFormatTemplate *template.Template } +type WavefrontOutputConfig struct { + EndpointType string // direct or proxy + EndpointHost string // Endpoint hostname (only IP or hostname) + EndpointToken string // Token for API access. Only for direct mode + EndpointMetricPort int // Port to send metrics. Only for proxy mode + MetricName string // The Name of the metric + FlushIntervalSeconds int // Time between flushes. + BatchSize int // BatchSize to send. Only for direct mode + MinimumPriority string +} + type teamsOutputConfig struct { WebhookURL string ActivityImage string @@ -343,6 +355,7 @@ type Statistics struct { Openfaas *expvar.Map WebUI *expvar.Map Rabbitmq *expvar.Map + Wavefront *expvar.Map } // PromStatistics is a struct to store prometheus metrics