From c54d2a010b9eaa0c71a94e8fe796ed6af249a56b Mon Sep 17 00:00:00 2001 From: Thomas Labarussias Date: Tue, 29 Nov 2022 17:28:06 +0100 Subject: [PATCH] add CEF format for syslog output Signed-off-by: Thomas Labarussias --- README.md | 6 +++-- config.go | 1 + config_example.yaml | 7 ++++++ outputs/syslog.go | 59 ++++++++++++++++++++++++++++++++++++++++++--- types/types.go | 1 + 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1ff2e2ac5..cc5f9ebeb 100644 --- a/README.md +++ b/README.md @@ -497,7 +497,8 @@ yandex: syslog: # host: "" # Syslog host, if not empty, Syslog output is enabled # port: "" # Syslog endpoint port number - # protocol: "" # Syslog transport protocol. It can be either "tcp" or "udp" + # protocol: "" # Syslog transport protocol. It can be either "tcp" or "udp" (default: tcp) + # format: "" # Syslog payload format. It can be either "json" or "cef" (default: json) # minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) mqtt: @@ -965,7 +966,8 @@ care of lower/uppercases**) : `yaml: a.b --> envvar: A_B` : - **YANDEX_DATASTREAMS_MINIMUMPRIORITY**: # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug - **SYSLOG_HOST**: Syslog Host, if not empty, Syslog output is enabled - **SYSLOG_PORT**: Syslog endpoint port number -- **SYSLOG_PROTOCOL**: Syslog transport protocol. It can be either "tcp" or "udp" +- **SYSLOG_PROTOCOL**: Syslog transport protocol. It can be either "tcp" or "udp" (default: tcp) +- **SYSLOG_FORMAT**: Syslog payload format. It can be either "json" or "cef" (default: json) - **SYSLOG_MINIMUMPRIORITY**: minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default: "debug") - **POLICYREPORT_ENABLED**: if true policyreport output is enabled (default: `false`) - **POLICYREPORT_KUBECONFIG**: Kubeconfig file to use (only if falcosidekick is running outside the cluster) diff --git a/config.go b/config.go index 66e5ec738..6a2235223 100644 --- a/config.go +++ b/config.go @@ -341,6 +341,7 @@ func getConfig() *types.Configuration { v.SetDefault("Syslog.Host", "") v.SetDefault("Syslog.Port", "") v.SetDefault("Syslog.Protocol", "") + v.SetDefault("Syslog.Format", "json") v.SetDefault("Syslog.MinimumPriority", "") v.SetDefault("MQTT.Broker", "") diff --git a/config_example.yaml b/config_example.yaml index 1ce4c34b9..8637977c4 100644 --- a/config_example.yaml +++ b/config_example.yaml @@ -329,6 +329,13 @@ yandex: # streamname: "" # stream name in format /${region}/${folder_id}/${ydb_id}/${stream_name} # minimumpriority: "" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug +syslog: + # host: "" # Syslog host, if not empty, Syslog output is enabled + # port: "" # Syslog endpoint port number + # protocol: "" # Syslog transport protocol. It can be either "tcp" or "udp" (default: tcp) + # format: "" # Syslog payload format. It can be either "json" or "cef" (default: json) + # minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) + mqtt: broker: "" # Broker address, can start with tcp:// or ssl://, if not empty, MQTT output is enabled # topic: "falco/events" # Topic for messages (default: falco/events) diff --git a/outputs/syslog.go b/outputs/syslog.go index 9f86a68d2..35d9e3669 100644 --- a/outputs/syslog.go +++ b/outputs/syslog.go @@ -3,11 +3,13 @@ package outputs import ( "encoding/json" "fmt" - "github.com/DataDog/datadog-go/statsd" - "github.com/falcosecurity/falcosidekick/types" "log" "log/syslog" "strings" + "time" + + "github.com/DataDog/datadog-go/statsd" + "github.com/falcosecurity/falcosidekick/types" ) func NewSyslogClient(config *types.Configuration, stats *types.Statistics, promStats *types.PromStatistics, statsdClient, dogstatsdClient *statsd.Client) (*Client, error) { @@ -30,6 +32,29 @@ func isValidProtocolString(protocol string) bool { return protocol == TCP || protocol == UDP } +func getCEFSeverity(priority types.PriorityType) string { + switch priority { + case types.Debug: + return "0" + case types.Informational: + return "3" + case types.Notice: + return "4" + case types.Warning: + return "6" + case types.Error: + return "7" + case types.Critical: + return "8" + case types.Alert: + return "9" + case types.Emergency: + return "10" + default: + return "Uknown" + } +} + func (c *Client) SyslogPost(falcopayload types.FalcoPayload) { c.Stats.Syslog.Add(Total, 1) endpoint := fmt.Sprintf("%s:%s", c.Config.Syslog.Host, c.Config.Syslog.Port) @@ -63,8 +88,34 @@ func (c *Client) SyslogPost(falcopayload types.FalcoPayload) { return } - b, _ := json.Marshal(falcopayload) - _, err = sysLog.Write(b) + var payload []byte + + if c.Config.Syslog.Format == "cef" { + s := fmt.Sprintf( + "CEF:0|Falcosecurity|Falco|1.0|Falco Event|%v|%v|uuid=%v start=%v msg=%v source=%v", + falcopayload.Rule, + getCEFSeverity(falcopayload.Priority), + falcopayload.UUID, + falcopayload.Time.Format(time.RFC3339), + falcopayload.Output, + falcopayload.Source, + ) + if falcopayload.Hostname != "" { + s += " hostname=" + falcopayload.Hostname + } + s += " outputfields=" + for i, j := range falcopayload.OutputFields { + s += fmt.Sprintf("%v:%v ", i, j) + } + if len(falcopayload.Tags) != 0 { + s += "tags=" + strings.Join(falcopayload.Tags, ",") + } + payload = []byte(strings.TrimSuffix(s, " ")) + } else { + payload, _ = json.Marshal(falcopayload) + } + + _, err = sysLog.Write(payload) if err != nil { go c.CountMetric(Outputs, 1, []string{"output:syslog", "status:error"}) c.Stats.Syslog.Add(Error, 1) diff --git a/types/types.go b/types/types.go index 896b82a9b..af53d2f02 100644 --- a/types/types.go +++ b/types/types.go @@ -529,6 +529,7 @@ type SyslogConfig struct { Host string Port string Protocol string + Format string MinimumPriority string }