diff --git a/README.md b/README.md index 93b7b4348..f518e68bb 100644 --- a/README.md +++ b/README.md @@ -291,11 +291,8 @@ kafka: # minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) pagerduty: - # apikey: # Pagerduty API Key, if not empty, Pagerduty output is enabled - service: "" # Service to create an incident (mandatory) - assignee: "" # A list of comma separated users to assign. Cannot be provided if pagerduty.escalationpolicy is already specified. - escalationpolicy: "" # Escalation policy to assign. Cannot be provided if pagerduty.escalationpolicy is already specified - # minimumpriority: "debug" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) + routingKey: "" # Pagerduty Routing Key, if not empty, Pagerduty output is enabled + minimumpriority: "" # minimum priority of event for using this output, order is emergency|alert|critical|error|warning|notice|informational|debug or "" (default) kubeless: function: "" # Name of Kubeless function, if not empty, Kubeless is enabled diff --git a/config.go b/config.go index 33db3176d..83e69730b 100644 --- a/config.go +++ b/config.go @@ -135,10 +135,7 @@ func getConfig() *types.Configuration { v.SetDefault("Kafka.Topic", "") v.SetDefault("Kafka.Partition", 0) v.SetDefault("Kafka.MinimumPriority", "") - v.SetDefault("Pagerduty.APIKey", "") - v.SetDefault("Pagerduty.Service", "") - v.SetDefault("Pagerduty.Assignee", []string{}) - v.SetDefault("Pagerduty.EscalationPolicy", "") + v.SetDefault("Pagerduty.RoutingKey", "") v.SetDefault("Pagerduty.MinimumPriority", "") v.SetDefault("Kubeless.Namespace", "") v.SetDefault("Kubeless.Function", "") diff --git a/handlers.go b/handlers.go index 3fb86c38b..5cb8ce2b5 100644 --- a/handlers.go +++ b/handlers.go @@ -217,8 +217,8 @@ func forwardEvent(falcopayload types.FalcoPayload) { go kafkaClient.KafkaProduce(falcopayload) } - if config.Pagerduty.APIKey != "" && config.Pagerduty.Service != "" && (falcopayload.Priority >= types.Priority(config.Pagerduty.MinimumPriority) || falcopayload.Rule == testRule) { - go pagerdutyClient.PagerdutyCreateIncident(falcopayload) + if config.Pagerduty.RoutingKey != "" && (falcopayload.Priority >= types.Priority(config.Pagerduty.MinimumPriority) || falcopayload.Rule == testRule) { + go pagerdutyClient.PagerdutyPost(falcopayload) } if config.Kubeless.Namespace != "" && config.Kubeless.Function != "" && (falcopayload.Priority >= types.Priority(config.Kubeless.MinimumPriority) || falcopayload.Rule == testRule) { diff --git a/main.go b/main.go index af3da3f5c..6bcbd1dab 100644 --- a/main.go +++ b/main.go @@ -332,14 +332,17 @@ func init() { } } - if config.Pagerduty.APIKey != "" && config.Pagerduty.Service != "" { + if config.Pagerduty.RoutingKey != "" { var err error - pagerdutyClient, err = outputs.NewPagerdutyClient(config, stats, promStats, statsdClient, dogstatsdClient) + var url = "https://events.pagerduty.com/v2/enqueue" + var outputName = "Pagerduty" + + pagerdutyClient, err = outputs.NewClient(outputName, url, config, stats, promStats, statsdClient, dogstatsdClient) + if err != nil { - config.Pagerduty.APIKey = "" - config.Pagerduty.Service = "" + config.Pagerduty.RoutingKey = "" } else { - outputs.EnabledOutputs = append(outputs.EnabledOutputs, "Pagerduty") + outputs.EnabledOutputs = append(outputs.EnabledOutputs, outputName) } } diff --git a/outputs/client.go b/outputs/client.go index e499db637..380f1e574 100644 --- a/outputs/client.go +++ b/outputs/client.go @@ -15,7 +15,6 @@ import ( "cloud.google.com/go/pubsub" "github.com/DataDog/datadog-go/statsd" - "github.com/PagerDuty/go-pagerduty" "github.com/aws/aws-sdk-go/aws/session" cloudevents "github.com/cloudevents/sdk-go/v2" "github.com/google/uuid" @@ -61,7 +60,6 @@ type Client struct { DogstatsdClient *statsd.Client GCPTopicClient *pubsub.Topic KafkaProducer *kafka.Conn - PagerdutyClient *pagerduty.Client CloudEventsClient cloudevents.Client KubernetesClient kubernetes.Interface } diff --git a/outputs/pagerduty.go b/outputs/pagerduty.go index 806b2c0d4..7dea632cc 100644 --- a/outputs/pagerduty.go +++ b/outputs/pagerduty.go @@ -1,65 +1,20 @@ package outputs import ( - "fmt" "log" + "time" - "github.com/DataDog/datadog-go/statsd" "github.com/PagerDuty/go-pagerduty" "github.com/falcosecurity/falcosidekick/types" ) -// NewPagerdutyClient returns a new output.Client for accessing the Pagerduty API. -func NewPagerdutyClient(config *types.Configuration, stats *types.Statistics, promStats *types.PromStatistics, statsdClient, dogstatsdClient *statsd.Client) (*Client, error) { - if len(config.Pagerduty.Assignee) > 0 && config.Pagerduty.EscalationPolicy != "" { - return nil, fmt.Errorf("assignee and escalation policy cannot be both configured") - } - - return &Client{ - OutputType: "PagerDuty", - Config: config, - Stats: stats, - PromStats: promStats, - StatsdClient: statsdClient, - DogstatsdClient: dogstatsdClient, - PagerdutyClient: pagerduty.NewClient(config.Pagerduty.APIKey), - }, nil -} - -// PagerdutyCreateIncident posts incident to Pagerduty -func (c *Client) PagerdutyCreateIncident(falcopayload types.FalcoPayload) { +// PagerdutyPost posts alert event to Pagerduty +func (c *Client) PagerdutyPost(falcopayload types.FalcoPayload) { c.Stats.Pagerduty.Add(Total, 1) - opts := &pagerduty.CreateIncidentOptions{ - Type: "incident", - Title: falcopayload.Output, - Service: &pagerduty.APIReference{ - ID: c.Config.Pagerduty.Service, - Type: "service_reference", - }, - } - - if len(c.Config.Pagerduty.Assignee) > 0 { - assignments := make([]pagerduty.Assignee, len(c.Config.Pagerduty.Assignee)) - for i, a := range c.Config.Pagerduty.Assignee { - assignments[i] = pagerduty.Assignee{ - Assignee: pagerduty.APIObject{ - ID: a, - Type: "user_reference", - }, - } - } - opts.Assignments = assignments - } - - if policy := c.Config.Pagerduty.EscalationPolicy; policy != "" { - opts.EscalationPolicy = &pagerduty.APIReference{ - ID: policy, - Type: "escalation_policy_reference", - } - } + event := createPagerdutyEvent(falcopayload, c.Config.Pagerduty) - if _, err := c.PagerdutyClient.CreateIncident("falcosidekick", opts); err != nil { + if _, err := pagerduty.ManageEvent(event); err != nil { go c.CountMetric(Outputs, 1, []string{"output:pagerduty", "status:error"}) c.Stats.Pagerduty.Add(Error, 1) c.PromStats.Outputs.With(map[string]string{"destination": "pagerduty", "status": Error}).Inc() @@ -72,3 +27,18 @@ func (c *Client) PagerdutyCreateIncident(falcopayload types.FalcoPayload) { c.PromStats.Outputs.With(map[string]string{"destination": "pagerduty", "status": OK}).Inc() log.Printf("[INFO] : Pagerduty - Create Incident OK\n") } + +func createPagerdutyEvent(falcopayload types.FalcoPayload, config types.PagerdutyConfig) pagerduty.V2Event { + event := pagerduty.V2Event{ + RoutingKey: config.RoutingKey, + Action: "trigger", + Payload: &pagerduty.V2Payload{ + Source: "falco", + Summary: falcopayload.Output, + Severity: "critical", + Timestamp: falcopayload.Time.Format(time.RFC3339), + Details: falcopayload.OutputFields, + }, + } + return event +} diff --git a/outputs/pagerduty_test.go b/outputs/pagerduty_test.go new file mode 100644 index 000000000..be96be050 --- /dev/null +++ b/outputs/pagerduty_test.go @@ -0,0 +1,38 @@ +package outputs + +import ( + "encoding/json" + "github.com/PagerDuty/go-pagerduty" + "github.com/falcosecurity/falcosidekick/types" + "github.com/stretchr/testify/require" + "testing" +) + +func TestPagerdutyPayload(t *testing.T) { + var falcoTestInput = `{"output":"This is a test from falcosidekick","priority":"Debug","rule":"Test rule","time":"2001-01-01T01:10:00Z","output_fields": {"proc.name":"falcosidekick", "proc.tty": 1234}}` + + var excpectedOutput = pagerduty.V2Event{ + RoutingKey: "", + Action: "trigger", + Payload: &pagerduty.V2Payload{ + Summary: "This is a test from falcosidekick", + Source: "falco", + Severity: "critical", + Timestamp: "2001-01-01T01:10:00Z", + Component: "", + Group: "", + Class: "", + Details: map[string]interface{}{ + "proc.name": "falcosidekick", + "proc.tty": float64(1234), + }, + }, + } + + var f types.FalcoPayload + json.Unmarshal([]byte(falcoTestInput), &f) + + event := createPagerdutyEvent(f, types.PagerdutyConfig{}) + + require.Equal(t, excpectedOutput, event) +} diff --git a/types/types.go b/types/types.go index ff403aa85..8054fe48d 100644 --- a/types/types.go +++ b/types/types.go @@ -48,7 +48,7 @@ type Configuration struct { GCP gcpOutputConfig Googlechat GooglechatConfig Kafka kafkaConfig - Pagerduty pagerdutyConfig + Pagerduty PagerdutyConfig Kubeless kubelessConfig WebUI WebUIOutputConfig } @@ -261,12 +261,9 @@ type kafkaConfig struct { MinimumPriority string } -type pagerdutyConfig struct { - APIKey string - Service string - Assignee []string - EscalationPolicy string - MinimumPriority string +type PagerdutyConfig struct { + RoutingKey string + MinimumPriority string } type kubelessConfig struct {