Skip to content

Commit

Permalink
add node-red output
Browse files Browse the repository at this point in the history
Signed-off-by: Issif <[email protected]>
  • Loading branch information
Issif committed Jun 22, 2022
1 parent 503b96a commit cc3a429
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 0 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ It works as a single endpoint for as many as you want `Falco` instances :
### Web

- **Webhook**
- [**Node-RED**](https://nodered.org/)
- [**WebUI**](https://github.com/falcosecurity/falcosidekick-ui) (a Web UI for displaying latest events in real time)

### Other
Expand Down Expand Up @@ -328,6 +329,15 @@ webhook:
# 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)

nodered:
# address: "" # Webhook address, if not empty, Webhook output is enabled
# user: "" # User if Basic Auth is enabled for 'http in' node in Node-RED
# password: "" # Password if Basic Auth is enabled for 'http in' node in Node-RED
# customHeaders: # Custom headers to add in POST, useful for Authentication
# key: value
# 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)

azure:
eventHub:
name: "" # Name of the Hub, if not empty, EventHub is enabled
Expand Down Expand Up @@ -711,6 +721,19 @@ care of lower/uppercases**) : `yaml: a.b --> envvar: A_B` :
`false`)
- **WEBHOOK_CHECKCERT** : check if ssl certificate of the output is valid (default:
`true`)
- **NODERED_ADDRESS** : Node-RED address, if not empty, Node-RED output is
_enabled_
- **NODERED_USER** : User if Basic Auth is enabled for 'http in' node
in Node-RED
- **NODERED_PASSWORD** : Password if Basic Auth is enabled for 'http in' node
in Node-RED
- **NODERED_CUSTOMHEADERS** : a list of comma separated custom headers to add,
syntax is "key:value,key:value"
- **NODERED_MINIMUMPRIORITY** : minimum priority of event for using this output,
order is
`emergency|alert|critical|error|warning|notice|informational|debug or "" (default)`
- **NODERED_CHECKCERT** : check if ssl certificate of the output is valid (default:
`true`)
- **CLOUDEVENTS_ADDRESS** : CloudEvents consumer address, if not empty,
CloudEvents output is _enabled_
- **CLOUDEVENTS_EXTENSIONS** : a list of comma separated extensions to add,
Expand Down
6 changes: 6 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ func getConfig() *types.Configuration {
v.SetDefault("Webhook.MutualTls", false)
v.SetDefault("Webhook.CheckCert", true)

v.SetDefault("NodeRed.Address", "")
v.SetDefault("NodeRed.User", "")
v.SetDefault("NodeRed.Password", "")
v.SetDefault("NodeRed.MinimumPriority", "")
v.SetDefault("NodeRed.CheckCert", true)

v.SetDefault("CloudEvents.Address", "")
v.SetDefault("CloudEvents.MinimumPriority", "")
v.SetDefault("CloudEvents.MutualTls", false)
Expand Down
9 changes: 9 additions & 0 deletions config_example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,15 @@ webhook:
# 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)

nodered:
# address: "" # Node-RED address, if not empty, Node-RED output is enabled
# user: "" # User if Basic Auth is enabled for 'http in' node in Node-RED
# password: "" # Password if Basic Auth is enabled for 'http in' node in Node-RED
# customHeaders: # Custom headers to add in POST, useful for Authentication
# key: value
# 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)

cloudevents:
# address: "" # CloudEvents consumer http address, if not empty, CloudEvents output is enabled
# extensions: # Extensions to add in the outbound Event, useful for routing
Expand Down
4 changes: 4 additions & 0 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@ func forwardEvent(falcopayload types.FalcoPayload) {
go webhookClient.WebhookPost(falcopayload)
}

if config.NodeRed.Address != "" && (falcopayload.Priority >= types.Priority(config.NodeRed.MinimumPriority) || falcopayload.Rule == testRule) {
go noderedClient.NodeRedPost(falcopayload)
}

if config.CloudEvents.Address != "" && (falcopayload.Priority >= types.Priority(config.CloudEvents.MinimumPriority) || falcopayload.Rule == testRule) {
go cloudeventsClient.CloudEventsSend(falcopayload)
}
Expand Down
11 changes: 11 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var (
smtpClient *outputs.Client
opsgenieClient *outputs.Client
webhookClient *outputs.Client
noderedClient *outputs.Client
cloudeventsClient *outputs.Client
azureClient *outputs.Client
gcpClient *outputs.Client
Expand Down Expand Up @@ -318,6 +319,16 @@ func init() {
}
}

if config.NodeRed.Address != "" {
var err error
noderedClient, err = outputs.NewClient("NodeRed", config.NodeRed.Address, false, config.NodeRed.CheckCert, config, stats, promStats, statsdClient, dogstatsdClient)
if err != nil {
config.NodeRed.Address = ""
} else {
outputs.EnabledOutputs = append(outputs.EnabledOutputs, "NodeRed")
}
}

if config.CloudEvents.Address != "" {
var err error
cloudeventsClient, err = outputs.NewClient("CloudEvents", config.CloudEvents.Address, config.CloudEvents.MutualTLS, config.CloudEvents.CheckCert, config, stats, promStats, statsdClient, dogstatsdClient)
Expand Down
37 changes: 37 additions & 0 deletions outputs/nodered.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package outputs

import (
"encoding/base64"
"log"

"github.com/falcosecurity/falcosidekick/types"
)

// NodeRedPost posts event to Slack
func (c *Client) NodeRedPost(falcopayload types.FalcoPayload) {
c.Stats.NodeRed.Add(Total, 1)

if c.Config.NodeRed.User != "" && c.Config.NodeRed.Password != "" {
c.AddHeader("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(c.Config.NodeRed.User+":"+c.Config.NodeRed.Password)))
}

if len(c.Config.NodeRed.CustomHeaders) != 0 {
for i, j := range c.Config.NodeRed.CustomHeaders {
c.AddHeader(i, j)
}
}

err := c.Post(falcopayload)
if err != nil {
go c.CountMetric(Outputs, 1, []string{"output:nodered", "status:error"})
c.Stats.NodeRed.Add(Error, 1)
c.PromStats.Outputs.With(map[string]string{"destination": "nodered", "status": Error}).Inc()
log.Printf("[ERROR] : NodeRed - %v\n", err.Error())
return
}

// Setting the success status
go c.CountMetric(Outputs, 1, []string{"output:nodered", "status:ok"})
c.Stats.NodeRed.Add(OK, 1)
c.PromStats.Outputs.With(map[string]string{"destination": "nodered", "status": OK}).Inc()
}
1 change: 1 addition & 0 deletions stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func getInitStats() *types.Statistics {
YandexDataStreams: getOutputNewMap("yandexdatastreams"),
Syslog: getOutputNewMap("syslog"),
PolicyReport: getOutputNewMap("policyreport"),
NodeRed: getOutputNewMap("nodered"),
}
stats.Falco.Add(outputs.Emergency, 0)
stats.Falco.Add(outputs.Alert, 0)
Expand Down
12 changes: 12 additions & 0 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type Configuration struct {
Grafana grafanaOutputConfig
Yandex YandexOutputConfig
Syslog SyslogConfig
NodeRed NodeRedOutputConfig
}

// SlackOutputConfig represents parameters for Slack
Expand Down Expand Up @@ -295,6 +296,16 @@ type WebhookOutputConfig struct {
MutualTLS bool
}

// NodeRedOutputConfig represents parameters for Node-RED
type NodeRedOutputConfig struct {
Address string
User string
Password string
CustomHeaders map[string]string
MinimumPriority string
CheckCert bool
}

// CloudEventsOutputConfig represents parameters for CloudEvents
type CloudEventsOutputConfig struct {
Address string
Expand Down Expand Up @@ -522,6 +533,7 @@ type Statistics struct {
Syslog *expvar.Map
Cliq *expvar.Map
PolicyReport *expvar.Map
NodeRed *expvar.Map
}

// PromStatistics is a struct to store prometheus metrics
Expand Down

0 comments on commit cc3a429

Please sign in to comment.