Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openfaas output type added #208

Merged
merged 1 commit into from
Mar 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Currently available outputs are :
- [**Apache Kafka**](https://kafka.apache.org/)
- [**PagerDuty**](https://pagerduty.com/)
- [**Kubeless**](https://kubeless.io/)
- [**OpenFaaS**](https://www.openfaas.com)
- [**WebUI**](https://github.com/falcosecurity/falcosidekick-ui) (a Web UI for displaying latest events in real time)

## Usage
Expand Down Expand Up @@ -301,6 +302,15 @@ kubeless:
kubeconfig: "~/.kube/config" # Kubeconfig file to use (only if falcoside 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)

openfaas:
gatewayservice: "" # Service of OpenFaaS Gateway, "gateway" (default)
gatewaynamespace: "" # Namespace of OpenFaaS Gateway, "openfaas" (default)
gatewayport: 8080 # Port of service of OpenFaaS Gateway
functionname: "" # Name of OpenFaaS function, if not empty, OpenFaaS is enabled
functionnamespace: "" # Namespace of OpenFaaS function, "openfaas-fn" (default)
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)

webui:
url: "" # WebUI URL, if not empty, WebUI output is enabled
```
Expand Down Expand Up @@ -557,6 +567,16 @@ care of lower/uppercases**) : `yaml: a.b --> envvar: A_B` :
- **KUBELESS_MINIMUMPRIORITY**: "debug" # minimum priority of event for using
this output, order is
`emergency|alert|critical|error|warning|notice|informational|debug or "" (default)`
- **OPENFAAS_GATEWAYNAMESPACE** : Namespace of OpenFaaS Gateway, "openfaas" (default)
- **OPENFAAS_GATEWAYSERVICE** : Service of OpenFaaS Gateway, "gateway" (default)
- **OPENFAAS_FUNCTIONNAME** : Name of OpenFaaS function, if not empty, OpenFaaS is enabled
- **OPENFAAS_FUNCTIONNAMESPACE** : # Namespace of OpenFaaS function, "openfaas-fn" (default)
- **OPENFAAS_GATEWAYPORT** : Port of service of OpenFaaS Gateway
- **OPENFAAS_KUBECONFIG** : Kubeconfig file to use (only if falcoside is running
outside the cluster)
- **OPENFAAS_MINIMUMPRIORITY** : "debug" # minimum priority of event for using
this output, order is
`emergency|alert|critical|error|warning|notice|informational|debug or "" (default)`
- **WEBUI_URL** : WebUI URL, if not empty, WebUI output is
_enabled_

Expand Down
10 changes: 10 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ func getConfig() *types.Configuration {
v.SetDefault("Kubeless.Port", 8080)
v.SetDefault("Kubeless.Kubeconfig", "")
v.SetDefault("Kubeless.MinimumPriority", "")

v.SetDefault("Openfaas.GatewayNamespace", "openfaas")
v.SetDefault("Openfaas.GatewayService", "gateway")
v.SetDefault("Openfaas.FunctionName", "")
v.SetDefault("Openfaas.FunctionNamespace", "openfaas-fn")
v.SetDefault("Openfaas.GatewayPort", 8080)
v.SetDefault("Openfaas.Kubeconfig", "")
v.SetDefault("Openfaas.MinimumPriority", "")

v.SetDefault("Webui.URL", "")

v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
Expand Down Expand Up @@ -227,6 +236,7 @@ func getConfig() *types.Configuration {
c.Kafka.MinimumPriority = checkPriority(c.Kafka.MinimumPriority)
c.Pagerduty.MinimumPriority = checkPriority(c.Pagerduty.MinimumPriority)
c.Kubeless.MinimumPriority = checkPriority(c.Kubeless.MinimumPriority)
c.Openfaas.MinimumPriority = checkPriority(c.Openfaas.MinimumPriority)

c.Slack.MessageFormatTemplate = getMessageFormatTemplate("Slack", c.Slack.MessageFormat)
c.Rocketchat.MessageFormatTemplate = getMessageFormatTemplate("Rocketchat", c.Rocketchat.MessageFormat)
Expand Down
9 changes: 9 additions & 0 deletions config_example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,5 +166,14 @@ kubeless:
kubeconfig: "~/.kube/config" # Kubeconfig file to use (only if falcoside 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)

openfaas:
gatewayservice: "" # Service of OpenFaaS Gateway, "gateway" (default)
gatewaynamespace: "" # Namespace of OpenFaaS Gateway, "openfaas" (default)
gatewayport: 8080 # Port of service of OpenFaaS Gateway
functionname: "" # Name of OpenFaaS function, if not empty, OpenFaaS is enabled
functionnamespace: "" # Namespace of OpenFaaS function, "openfaas-fn" (default)
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)

webui:
url: "" # WebUI URL, if not empty, WebUI output is enabled
4 changes: 4 additions & 0 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ func forwardEvent(falcopayload types.FalcoPayload) {
go kubelessClient.KubelessCall(falcopayload)
}

if config.Openfaas.FunctionName != "" && (falcopayload.Priority >= types.Priority(config.Openfaas.MinimumPriority) || falcopayload.Rule == testRule) {
go openfaasClient.OpenfaasCall(falcopayload)
}

if config.WebUI.URL != "" {
go webUIClient.WebUIPost(falcopayload)
}
Expand Down
11 changes: 11 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var (
kafkaClient *outputs.Client
pagerdutyClient *outputs.Client
kubelessClient *outputs.Client
openfaasClient *outputs.Client
webUIClient *outputs.Client

statsdClient, dogstatsdClient *statsd.Client
Expand Down Expand Up @@ -369,6 +370,16 @@ func init() {
}
}

if config.Openfaas.FunctionName != "" {
var err error
openfaasClient, err = outputs.NewOpenfaasClient(config, stats, promStats, statsdClient, dogstatsdClient)
if err != nil {
log.Printf("[ERROR] : OpenFaaS - %v\n", err)
} else {
outputs.EnabledOutputs = append(outputs.EnabledOutputs, "OpenFaaS")
}
}

log.Printf("[INFO] : Enabled Outputs : %s\n", outputs.EnabledOutputs)
}

Expand Down
5 changes: 4 additions & 1 deletion outputs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,12 @@ func (c *Client) Post(payload interface{}) error {
switch resp.StatusCode {
case http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNoContent: //200, 201, 202, 204
log.Printf("[INFO] : %v - Post OK (%v)\n", c.OutputType, resp.StatusCode)
body, _ := ioutil.ReadAll(resp.Body)
if c.OutputType == Kubeless {
body, _ := ioutil.ReadAll(resp.Body)
log.Printf("[INFO] : Kubeless - Function Response : %v\n", string(body))
} else if c.OutputType == Openfaas {
log.Printf("[INFO] : %v - Function Response : %v\n", Openfaas,
string(body))
}
return nil
case http.StatusBadRequest: //400
Expand Down
1 change: 1 addition & 0 deletions outputs/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ const (
Orange string = "#ff5400"

Kubeless string = "Kubeless"
Openfaas string = "OpenFaas"
)
84 changes: 84 additions & 0 deletions outputs/openfaas.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package outputs

import (
"context"
"encoding/json"
"log"
"strconv"

"github.com/DataDog/datadog-go/statsd"
"github.com/google/uuid"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"

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

// NewOpenfaasClient returns a new output.Client for accessing Kubernetes.
func NewOpenfaasClient(config *types.Configuration, stats *types.Statistics, promStats *types.PromStatistics, statsdClient, dogstatsdClient *statsd.Client) (*Client, error) {
if config.Openfaas.Kubeconfig != "" {
restConfig, err := clientcmd.BuildConfigFromFlags("", config.Openfaas.Kubeconfig)
if err != nil {
return nil, err
}
clientset, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return nil, err
}
return &Client{
OutputType: Openfaas,
Config: config,
Stats: stats,
PromStats: promStats,
StatsdClient: statsdClient,
DogstatsdClient: dogstatsdClient,
KubernetesClient: clientset,
}, nil
}
return NewClient(
Openfaas,
"http://"+config.Openfaas.GatewayService+"."+config.Openfaas.GatewayNamespace+":"+strconv.Itoa(config.Openfaas.GatewayPort)+"/function/"+config.Openfaas.FunctionName+"."+config.Openfaas.FunctionNamespace,
config,
stats,
promStats,
statsdClient,
dogstatsdClient,
)
}

// OpenfaasCall .
func (c *Client) OpenfaasCall(falcopayload types.FalcoPayload) {
c.Stats.Openfaas.Add(Total, 1)

if c.Config.Openfaas.Kubeconfig != "" {
str, _ := json.Marshal(falcopayload)
req := c.KubernetesClient.CoreV1().RESTClient().Post().AbsPath("/api/v1/namespaces/" + c.Config.Openfaas.GatewayNamespace + "/services/" + c.Config.Openfaas.GatewayService + ":" + strconv.Itoa(c.Config.Openfaas.GatewayPort) + "/proxy" + "/function/" + c.Config.Openfaas.FunctionName + "." + c.Config.Openfaas.FunctionNamespace).Body(str)
req.SetHeader("event-id", uuid.New().String())
req.SetHeader("Content-Type", "application/json")
req.SetHeader("User-Agent", "Falcosidekick")

res := req.Do(context.TODO())
rawbody, err := res.Raw()
if err != nil {
go c.CountMetric(Outputs, 1, []string{"output:openfaas", "status:error"})
c.Stats.Openfaas.Add(Error, 1)
c.PromStats.Outputs.With(map[string]string{"destination": "openfaas", "status": Error}).Inc()
log.Printf("[ERROR] : %v - %v\n", Openfaas, err)
return
}
log.Printf("[INFO] : %v - Function Response : %v\n", Openfaas, string(rawbody))
} else {
err := c.Post(falcopayload)
if err != nil {
go c.CountMetric(Outputs, 1, []string{"output:openfaas", "status:error"})
c.Stats.Openfaas.Add(Error, 1)
c.PromStats.Outputs.With(map[string]string{"destination": "openfaas", "status": Error}).Inc()
log.Printf("[ERROR] : %v - %v\n", Openfaas, err)
return
}
}
log.Printf("[INFO] : %v - Call Function \"%v\" OK\n", Openfaas, c.Config.Openfaas.FunctionName+"."+c.Config.Openfaas.FunctionNamespace)
go c.CountMetric(Outputs, 1, []string{"output:openfaas", "status:ok"})
c.Stats.Openfaas.Add(OK, 1)
c.PromStats.Outputs.With(map[string]string{"destination": "openfaas", "status": OK}).Inc()
}
1 change: 1 addition & 0 deletions stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func getInitStats() *types.Statistics {
Kafka: getOutputNewMap("kafka"),
Pagerduty: getOutputNewMap("pagerduty"),
Kubeless: getOutputNewMap("kubeless"),
Openfaas: getOutputNewMap("openfaas"),
WebUI: getOutputNewMap("webui"),
}
stats.Falco.Add(outputs.Emergency, 0)
Expand Down
12 changes: 12 additions & 0 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type Configuration struct {
Kafka kafkaConfig
Pagerduty PagerdutyConfig
Kubeless kubelessConfig
Openfaas openfaasConfig
WebUI WebUIOutputConfig
}

Expand Down Expand Up @@ -274,6 +275,16 @@ type kubelessConfig struct {
MinimumPriority string
}

type openfaasConfig struct {
GatewayNamespace string
GatewayService string
FunctionName string
FunctionNamespace string
GatewayPort int
Kubeconfig string
MinimumPriority string
}

// WebUIOutputConfig represents parameters for WebUI
type WebUIOutputConfig struct {
URL string
Expand Down Expand Up @@ -314,6 +325,7 @@ type Statistics struct {
Pagerduty *expvar.Map
CloudEvents *expvar.Map
Kubeless *expvar.Map
Openfaas *expvar.Map
WebUI *expvar.Map
}

Expand Down