Skip to content

Commit

Permalink
update all outputs for dealing with tags and source
Browse files Browse the repository at this point in the history
Signed-off-by: Issif <issif+github@gadz.org>
  • Loading branch information
Issif authored and poiana committed May 11, 2022
1 parent c39c65c commit df701e0
Show file tree
Hide file tree
Showing 45 changed files with 322 additions and 128 deletions.
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.circleci
.git
.github
.golangci.yml
_config.yml
Expand Down
5 changes: 1 addition & 4 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@ linters:
- deadcode
- goconst
- gofmt
- golint
- gosec
- govet
- ineffassign
- interfacer
- maligned
- misspell
- nakedret
- prealloc
Expand All @@ -25,4 +22,4 @@ linters:
include:
- EXC0002 # include "missing comments" issues from golint
max-issues-per-linter: 0
max-same-issues: 0
max-same-issues: 0
14 changes: 13 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
ARG BUILDER_IMAGE=golang:1.17-buster
ARG BASE_IMAGE=alpine:3.15

FROM ${BUILDER_IMAGE} AS build-stage

ENV CGO_ENABLED=0

WORKDIR /src/
COPY . .

RUN go mod download
RUN make falcosidekick

# Final Docker image
FROM ${BASE_IMAGE} AS final-stage
LABEL MAINTAINER "Thomas Labarussias <issif+falcosidekick@gadz.org>"
Expand All @@ -13,7 +25,7 @@ USER 1234

WORKDIR ${HOME}/app
COPY LICENSE .
COPY falcosidekick .
COPY --from=build-stage /src/falcosidekick .

EXPOSE 2801

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/bin)
GO_INSTALL = ./hack/go_install.sh

# Binaries.
GOLANGCI_LINT_VER := v1.43.0
GOLANGCI_LINT_VER := v1.44.2
GOLANGCI_LINT_BIN := golangci-lint
GOLANGCI_LINT := $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ permissions to access the resources you selected to use, like `SQS`, `Lambda`,
Run you daemon and try (from Falco's documentation) :

```bash
curl "http://localhost:2801/" -d'{"output":"16:31:56.746609046: Error File below a known binary directory opened for writing (user=root command=touch /bin/hack file=/bin/hack)","priority":"Error","rule":"Write below binary dir","time":"2019-05-17T15:31:56.746609046Z", "output_fields": {"evt.time":1507591916746609046,"fd.name":"/bin/hack","proc.cmdline":"touch /bin/hack","user.name":"root"}}'
curl -XPOST "http://localhost:2801/" -d'{"output":"16:31:56.746609046: Error File below a known binary directory opened for writing (user=root command=touch /bin/hack file=/bin/hack)","priority":"Error","rule":"Write below binary dir","time":"2019-05-17T15:31:56.746609046Z", "output_fields": {"evt.time":1507591916746609046,"fd.name":"/bin/hack","proc.cmdline":"touch /bin/hack","user.name":"root"}}'
```

You should get :
Expand Down
60 changes: 60 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
version: "3"
services:
smtp:
image: mailhog/mailhog:latest
ports:
- "1025:1025"
- "8025:8025"
profiles: [smtp]

elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.1.0
ports:
- "9200:9200"
- "9300:9300"
environment: #credentials: elastic/elastic
- ELASTIC_PASSWORD=elastic
- discovery.type=single-node
- xpack.security.enabled=false
- xpack.security.transport.ssl.enabled=false
profiles: [elasticsearch]

nats:
image: nats:latest
ports:
- "4222:4222"
- "8222:8222"
command: "--http_port 8222"
hostname: nats
profiles: [nats]

loki:
image: grafana/loki:latest
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
profiles: [loki]
grafana: #credentials: admin/admin
image: grafana/grafana:latest
ports:
- "3000:3000"
depends_on: [loki]
profiles: [loki]

influxdb: #credentials: admin/adminadmin
image: influxdb:latest
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=admin
- DOCKER_INFLUXDB_INIT_PASSWORD=adminadmin
- DOCKER_INFLUXDB_INIT_ORG=falco
- DOCKER_INFLUXDB_INIT_BUCKET=falco
ports:
- "8086:8086"
profiles: [influxdb]

alertmanager:
image: prom/alertmanager:latest
ports:
- "9093:9093"
profiles: [alertmanager]
9 changes: 6 additions & 3 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func healthHandler(w http.ResponseWriter, r *http.Request) {

// testHandler sends a test event to all enabled outputs.
func testHandler(w http.ResponseWriter, r *http.Request) {
r.Body = ioutil.NopCloser(bytes.NewReader([]byte(`{"output":"This is a test from falcosidekick","priority":"Debug","rule":"Test rule", "time":"` + time.Now().UTC().Format(time.RFC3339) + `","output_fields": {"proc.name":"falcosidekick","user.name":"falcosidekick"}}`)))
r.Body = ioutil.NopCloser(bytes.NewReader([]byte(`{"output":"This is a test from falcosidekick","priority":"Debug","rule":"Test rule", "time":"` + time.Now().UTC().Format(time.RFC3339) + `","output_fields": {"proc.name":"falcosidekick","user.name":"falcosidekick"}, "tags":["test","example"]}`)))
mainHandler(w, r)
}

Expand All @@ -84,7 +84,6 @@ func newFalcoPayload(payload io.Reader) (types.FalcoPayload, error) {
return types.FalcoPayload{}, err
}

// falcopayload.OutputFields = make(map[string]interface{})
if len(config.Customfields) > 0 {
if falcopayload.OutputFields == nil {
falcopayload.OutputFields = make(map[string]interface{})
Expand All @@ -94,6 +93,10 @@ func newFalcoPayload(payload io.Reader) (types.FalcoPayload, error) {
}
}

if falcopayload.Source == "" {
falcopayload.Source = "syscalls"
}

var kn, kp string
for i, j := range falcopayload.OutputFields {
if i == "k8s.ns.name" {
Expand All @@ -112,7 +115,7 @@ func newFalcoPayload(payload io.Reader) (types.FalcoPayload, error) {
}
promStats.Falco.With(promLabels).Inc()

if config.Debug == true {
if config.Debug {
body, _ := json.Marshal(falcopayload)
log.Printf("[DEBUG] : Falco's payload : %v", string(body))
}
Expand Down
5 changes: 4 additions & 1 deletion outputs/alertmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ func newAlertmanagerPayload(falcopayload types.FalcoPayload) []alertmanagerPaylo
}
amPayload.Labels["source"] = "falco"
amPayload.Labels["rule"] = falcopayload.Rule
amPayload.Labels["priority"] = falcopayload.Priority.String()
amPayload.Labels["eventsource"] = falcopayload.Source
if len(falcopayload.Tags) != 0 {
amPayload.Labels["tags"] = strings.Join(falcopayload.Tags, ",")
}

amPayload.Annotations["info"] = falcopayload.Output
amPayload.Annotations["summary"] = falcopayload.Rule
Expand Down
2 changes: 1 addition & 1 deletion outputs/alertmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func TestNewAlertmanagerPayloadO(t *testing.T) {
expectedOutput := `[{"labels":{"proc_name":"falcosidekick","priority":"Debug","proc_tty":"1234","rule":"Test rule","source":"falco"},"annotations":{"info":"This is a test from falcosidekick","summary":"Test rule"}}]`
expectedOutput := `[{"labels":{"proc_name":"falcosidekick","proc_tty":"1234","eventsource":"syscalls","rule":"Test rule","source":"falco","tags":"test,example"},"annotations":{"info":"This is a test from falcosidekick","summary":"Test rule"}}]`

var f types.FalcoPayload
d := json.NewDecoder(strings.NewReader(falcoTestInput))
Expand Down
72 changes: 24 additions & 48 deletions outputs/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ import (
"log"
"net/url"
"os"
"strings"
"time"

"github.com/DataDog/datadog-go/statsd"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
"github.com/aws/aws-sdk-go/service/kinesis"
Expand All @@ -38,56 +37,22 @@ func NewAWSClient(config *types.Configuration, stats *types.Statistics, promStat
err3 := os.Setenv("AWS_DEFAULT_REGION", config.AWS.Region)
if err1 != nil || err2 != nil || err3 != nil {
log.Printf("[ERROR] : AWS - Error setting AWS env vars")
return nil, errors.New("Error setting AWS env vars")
return nil, errors.New("error setting AWS env vars")
}
}

var sess *session.Session
var err error

// if we are not using regional endpoints, the provider is configured manually
// in almost all cases this should be set as per https://github.com/aws/amazon-eks-pod-identity-webhook#aws_sts_regional_endpoints-injection

roleArn := os.Getenv("AWS_ROLE_ARN")
tokenPath := os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")

if os.Getenv("AWS_STS_REGIONAL_ENDPOINTS") != "regional" && roleArn != "" && tokenPath != "" {
// create a temporary session to ensure the AssumeRoleWithWebIdentity operation can succeed
tmp, err := session.NewSession(&aws.Config{
Region: aws.String(config.AWS.Region),
Credentials: credentials.AnonymousCredentials,
},
)
if err != nil {
log.Printf("[ERROR] : AWS - %v\n", "Error setting temporary session to configure WebIdentityRoleProvider")
return nil, errors.New("Error setting temporary session to configure WebIdentityRoleProvider")
}

provider := stscreds.NewWebIdentityRoleProvider(
sts.New(tmp),
os.Getenv("AWS_ROLE_ARN"),
os.Getenv("AWS_ROLE_SESSION_NAME")+time.Now().Format("20060102150405"),
os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE"),
)

sess, err = session.NewSessionWithOptions(session.Options{
Config: aws.Config{Credentials: credentials.NewCredentials(provider)},
})
if err != nil {
log.Printf("[ERROR] : AWS - %v\n", "Error configuring IAM role for Service Account")
return nil, errors.New("Error configuring IAM role for Service Account")
}
} else {
// ensures default authentication flow is followed, env -> shared config -> EC2 instance metadata
sess = session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
sess, err := session.NewSession(&aws.Config{
Region: aws.String(config.AWS.Region)},
)
if err != nil {
log.Printf("[ERROR] : AWS - %v\n", "Error while creating AWS Session")
return nil, errors.New("error while creating AWS Session")
}

_, err = sts.New(sess).GetCallerIdentity(&sts.GetCallerIdentityInput{})
if err != nil {
log.Printf("[ERROR] : AWS - %v\n", "Error while getting AWS Token")
return nil, errors.New("Error while getting AWS Token")
return nil, errors.New("error while getting AWS Token")
}

var endpointURL *url.URL
Expand Down Expand Up @@ -133,7 +98,7 @@ func (c *Client) InvokeLambda(falcopayload types.FalcoPayload) {
return
}

if c.Config.Debug == true {
if c.Config.Debug {
r, _ := base64.StdEncoding.DecodeString(*resp.LogResult)
log.Printf("[DEBUG] : %v Lambda result : %v\n", c.OutputType, string(r))
}
Expand Down Expand Up @@ -166,7 +131,7 @@ func (c *Client) SendMessage(falcopayload types.FalcoPayload) {
return
}

if c.Config.Debug == true {
if c.Config.Debug {
log.Printf("[DEBUG] : %v SQS - MD5OfMessageBody : %v\n", c.OutputType, *resp.MD5OfMessageBody)
}

Expand Down Expand Up @@ -216,7 +181,7 @@ func (c *Client) PublishTopic(falcopayload types.FalcoPayload) {

var msg *sns.PublishInput

if c.Config.AWS.SNS.RawJSON == true {
if c.Config.AWS.SNS.RawJSON {
f, _ := json.Marshal(falcopayload)
msg = &sns.PublishInput{
Message: aws.String(string(f)),
Expand All @@ -234,10 +199,21 @@ func (c *Client) PublishTopic(falcopayload types.FalcoPayload) {
DataType: aws.String("String"),
StringValue: aws.String(falcopayload.Rule),
},
"source": {
DataType: aws.String("String"),
StringValue: aws.String(falcopayload.Source),
},
},
TopicArn: aws.String(c.Config.AWS.SNS.TopicArn),
}

if len(falcopayload.Tags) != 0 {
msg.MessageAttributes["tags"] = &sns.MessageAttributeValue{
DataType: aws.String("String"),
StringValue: aws.String(strings.Join(falcopayload.Tags, ",")),
}
}

for i, j := range falcopayload.OutputFields {
switch v := j.(type) {
case string:
Expand All @@ -251,7 +227,7 @@ func (c *Client) PublishTopic(falcopayload types.FalcoPayload) {
}
}

if c.Config.Debug == true {
if c.Config.Debug {
p, _ := json.Marshal(msg)
log.Printf("[DEBUG] : %v SNS - Message : %v\n", c.OutputType, string(p))
}
Expand Down
19 changes: 10 additions & 9 deletions outputs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,25 @@ import (
)

// ErrHeaderMissing = 400
var ErrHeaderMissing = errors.New("Header missing")
var ErrHeaderMissing = errors.New("header missing")

// ErrClientAuthenticationError = 401
var ErrClientAuthenticationError = errors.New("Authentication Error")
var ErrClientAuthenticationError = errors.New("authentication Error")

// ErrForbidden = 403
var ErrForbidden = errors.New("Access Denied")
var ErrForbidden = errors.New("access Denied")

// ErrNotFound = 404
var ErrNotFound = errors.New("Resource not found")
var ErrNotFound = errors.New("resource not found")

// ErrUnprocessableEntityError = 422
var ErrUnprocessableEntityError = errors.New("Bad Request")
var ErrUnprocessableEntityError = errors.New("bad Request")

// ErrTooManyRequest = 429
var ErrTooManyRequest = errors.New("Exceeding post rate limit")
var ErrTooManyRequest = errors.New("exceeding post rate limit")

// ErrClientCreation is returned if client can't be created
var ErrClientCreation = errors.New("Client creation Error")
var ErrClientCreation = errors.New("client creation Error")

// EnabledOutputs list all enabled outputs
var EnabledOutputs []string
Expand Down Expand Up @@ -126,6 +126,7 @@ func (c *Client) Post(payload interface{}) error {
// defer + recover to catch panic if output doesn't respond
defer func() {
if err := recover(); err != nil {
log.Printf("[ERROR] : %v - %s", c.OutputType, err)
}
}()

Expand All @@ -139,7 +140,7 @@ func (c *Client) Post(payload interface{}) error {
}
}

if c.Config.Debug == true {
if c.Config.Debug {
log.Printf("[DEBUG] : %v payload : %v\n", c.OutputType, body)
}

Expand All @@ -166,7 +167,7 @@ func (c *Client) Post(payload interface{}) error {
}
} else {
// With MutualTLS enabled, the check cert flag is ignored
if c.CheckCert == false {
if c.CheckCert {
// #nosec G402 This is only set as a result of explicit configuration
customTransport.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
Expand Down
2 changes: 1 addition & 1 deletion outputs/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"github.com/falcosecurity/falcosidekick/types"
)

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 falcoTestInput = `{"output":"This is a test from falcosidekick","priority":"Debug","rule":"Test rule", "time":"2001-01-01T01:10:00Z","source":"syscalls","output_fields": {"proc.name":"falcosidekick", "proc.tty": 1234}, "tags":["test","example"]}`

func TestNewClient(t *testing.T) {
u, _ := url.Parse("http://localhost")
Expand Down

0 comments on commit df701e0

Please sign in to comment.