dummy plugin (#1342)

This commit is contained in:
mmetc 2022-03-16 09:30:04 +01:00 committed by GitHub
parent 76e97303a5
commit 81793fe8bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 251 additions and 15 deletions

1
.gitignore vendored
View file

@ -28,3 +28,4 @@ plugins/notifications/http/notification-http
plugins/notifications/slack/notification-slack plugins/notifications/slack/notification-slack
plugins/notifications/splunk/notification-splunk plugins/notifications/splunk/notification-splunk
plugins/notifications/email/notification-email plugins/notifications/email/notification-email
plugins/notifications/dummy/notification-dummy

View file

@ -13,11 +13,13 @@ HTTP_PLUGIN_FOLDER = "./plugins/notifications/http"
SLACK_PLUGIN_FOLDER = "./plugins/notifications/slack" SLACK_PLUGIN_FOLDER = "./plugins/notifications/slack"
SPLUNK_PLUGIN_FOLDER = "./plugins/notifications/splunk" SPLUNK_PLUGIN_FOLDER = "./plugins/notifications/splunk"
EMAIL_PLUGIN_FOLDER = "./plugins/notifications/email" EMAIL_PLUGIN_FOLDER = "./plugins/notifications/email"
DUMMY_PLUGIN_FOLDER = "./plugins/notifications/dummy"
HTTP_PLUGIN_BIN = "notification-http" HTTP_PLUGIN_BIN = "notification-http"
SLACK_PLUGIN_BIN = "notification-slack" SLACK_PLUGIN_BIN = "notification-slack"
SPLUNK_PLUGIN_BIN = "notification-splunk" SPLUNK_PLUGIN_BIN = "notification-splunk"
EMAIL_PLUGIN_BIN = "notification-email" EMAIL_PLUGIN_BIN = "notification-email"
DUMMY_PLUGIN_BIN= "notification-dummy"
HTTP_PLUGIN_CONFIG = "http.yaml" HTTP_PLUGIN_CONFIG = "http.yaml"
SLACK_PLUGIN_CONFIG = "slack.yaml" SLACK_PLUGIN_CONFIG = "slack.yaml"
@ -73,9 +75,9 @@ all: clean test build
static: crowdsec_static cscli_static plugins_static static: crowdsec_static cscli_static plugins_static
.PHONY: plugins .PHONY: plugins
plugins: http-plugin slack-plugin splunk-plugin email-plugin plugins: http-plugin slack-plugin splunk-plugin email-plugin dummy-plugin
plugins_static: http-plugin_static slack-plugin_static splunk-plugin_static email-plugin_static plugins_static: http-plugin_static slack-plugin_static splunk-plugin_static email-plugin_static dummy-plugin_static
goversion: goversion:
@if [ $(GO_MAJOR_VERSION) -gt $(MINIMUM_SUPPORTED_GO_MAJOR_VERSION) ]; then \ @if [ $(GO_MAJOR_VERSION) -gt $(MINIMUM_SUPPORTED_GO_MAJOR_VERSION) ]; then \
@ -101,6 +103,7 @@ clean: testclean
@$(RM) $(SLACK_PLUGIN_FOLDER)/$(SLACK_PLUGIN_BIN) @$(RM) $(SLACK_PLUGIN_FOLDER)/$(SLACK_PLUGIN_BIN)
@$(RM) $(SPLUNK_PLUGIN_FOLDER)/$(SPLUNK_PLUGIN_BIN) @$(RM) $(SPLUNK_PLUGIN_FOLDER)/$(SPLUNK_PLUGIN_BIN)
@$(RM) $(EMAIL_PLUGIN_FOLDER)/$(EMAIL_PLUGIN_BIN) @$(RM) $(EMAIL_PLUGIN_FOLDER)/$(EMAIL_PLUGIN_BIN)
@$(RM) $(DUMMY_PLUGIN_FOLDER)/$(DUMMY_PLUGIN_BIN)
cscli: goversion cscli: goversion
@ -121,6 +124,9 @@ splunk-plugin: goversion
email-plugin: goversion email-plugin: goversion
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(EMAIL_PLUGIN_FOLDER) build --no-print-directory @GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(EMAIL_PLUGIN_FOLDER) build --no-print-directory
dummy-plugin: goversion
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(DUMMY_PLUGIN_FOLDER) build --no-print-directory
cscli_static: goversion cscli_static: goversion
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(CSCLI_FOLDER) static --no-print-directory @GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(CSCLI_FOLDER) static --no-print-directory
@ -139,6 +145,9 @@ splunk-plugin_static:goversion
email-plugin_static:goversion email-plugin_static:goversion
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(EMAIL_PLUGIN_FOLDER) static --no-print-directory @GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(EMAIL_PLUGIN_FOLDER) static --no-print-directory
dummy-plugin_static:goversion
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(DUMMY_PLUGIN_FOLDER) static --no-print-directory
.PHONY: testclean .PHONY: testclean
testclean: bats-clean testclean: bats-clean
@$(RM) pkg/apiserver/ent @$(RM) pkg/apiserver/ent

View file

@ -9,5 +9,5 @@ decisions:
# - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this. # - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this.
# - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this. # - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this.
# - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this. # - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this.
# - email_default # Set the required http parameters in /etc/crowdsec/notifications/email.yaml before enabling this. # - email_default # Set the required email parameters in /etc/crowdsec/notifications/email.yaml before enabling this.
on_success: break on_success: break

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Crowdsec
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,16 @@
# Go parameters
GOCMD=go
GOBUILD=$(GOCMD) build
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
GOGET=$(GOCMD) get
BINARY_NAME=notification-dummy
clean:
@$(RM) "$(BINARY_NAME)"
build: clean
@$(GOBUILD) $(LD_OPTS) -o $(BINARY_NAME) -v
static: clean
$(GOBUILD) $(LD_OPTS_STATIC) -o $(BINARY_NAME) -v -a -tags netgo

View file

@ -0,0 +1,22 @@
type: dummy # Don't change
name: dummy_default # Must match the registered plugin in the profile
# One of "trace", "debug", "info", "warn", "error", "off"
log_level: info
# group_wait: # Time to wait collecting alerts before relaying a message to this plugin, eg "30s"
# group_threshold: # Amount of alerts that triggers a message before <group_wait> has expired, eg "10"
# max_retry: # Number of attempts to relay messages to plugins in case of error
# timeout: # Time to wait for response from the plugin before considering the attempt a failure, eg "10s"
#-------------------------
# plugin-specific options
# The following template receives a list of models.Alert objects
# The output goes in the logs and to a text file, if defined
format: |
{{.|toJson}}
#
# output_file: # notifications will be appended here. optional

View file

@ -0,0 +1,88 @@
package main
import (
"context"
"fmt"
"os"
"github.com/crowdsecurity/crowdsec/pkg/protobufs"
"github.com/hashicorp/go-hclog"
plugin "github.com/hashicorp/go-plugin"
"gopkg.in/yaml.v2"
)
type PluginConfig struct {
Name string `yaml:"name"`
LogLevel *string `yaml:"log_level"`
OutputFile *string `yaml:"output_file"`
}
type DummyPlugin struct {
PluginConfigByName map[string]PluginConfig
}
var logger hclog.Logger = hclog.New(&hclog.LoggerOptions{
Name: "dummy-plugin",
Level: hclog.LevelFromString("INFO"),
Output: os.Stderr,
JSONFormat: true,
})
func (s *DummyPlugin) Notify(ctx context.Context, notification *protobufs.Notification) (*protobufs.Empty, error) {
if _, ok := s.PluginConfigByName[notification.Name]; !ok {
return nil, fmt.Errorf("invalid plugin config name %s", notification.Name)
}
cfg := s.PluginConfigByName[notification.Name]
if cfg.LogLevel != nil && *cfg.LogLevel != "" {
logger.SetLevel(hclog.LevelFromString(*cfg.LogLevel))
}
logger.Info(fmt.Sprintf("received signal for %s config", notification.Name))
logger.Debug(notification.Text)
if cfg.OutputFile != nil && *cfg.OutputFile != "" {
f, err := os.OpenFile(*cfg.OutputFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
logger.Error(fmt.Sprintf("Cannot open notification file: %s", err))
}
if _, err := f.WriteString(notification.Text); err != nil {
f.Close()
logger.Error(fmt.Sprintf("Cannot write notification to file: %s", err))
}
err = f.Close()
if err != nil {
logger.Error(fmt.Sprintf("Cannot close notification file: %s", err))
}
}
fmt.Print(notification.Text)
return &protobufs.Empty{}, nil
}
func (s *DummyPlugin) Configure(ctx context.Context, config *protobufs.Config) (*protobufs.Empty, error) {
d := PluginConfig{}
err := yaml.Unmarshal(config.Config, &d)
s.PluginConfigByName[d.Name] = d
return &protobufs.Empty{}, err
}
func main() {
var handshake = plugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "CROWDSEC_PLUGIN_KEY",
MagicCookieValue: os.Getenv("CROWDSEC_PLUGIN_KEY"),
}
sp := &DummyPlugin{PluginConfigByName: make(map[string]PluginConfig)}
plugin.Serve(&plugin.ServeConfig{
HandshakeConfig: handshake,
Plugins: map[string]plugin.Plugin{
"dummy": &protobufs.NotifierPlugin{
Impl: sp,
},
},
GRPCServer: plugin.DefaultGRPCServer,
Logger: logger,
})
}

View file

@ -47,7 +47,7 @@ PARSER_S02="$PARSER_DIR/s02-enrich"
SCENARIOS_DIR="$CONFIG_DIR/scenarios" SCENARIOS_DIR="$CONFIG_DIR/scenarios"
POSTOVERFLOWS_DIR="$CONFIG_DIR/postoverflows" POSTOVERFLOWS_DIR="$CONFIG_DIR/postoverflows"
HUB_DIR="$CONFIG_DIR/hub" HUB_DIR="$CONFIG_DIR/hub"
PLUGINS="http slack splunk" PLUGINS="http slack splunk email"
PLUGINS_DIR="plugins" PLUGINS_DIR="plugins"
NOTIF_DIR="notifications" NOTIF_DIR="notifications"
@ -70,8 +70,8 @@ create_arbo() {
mkdir -p "$POSTOVERFLOWS_DIR" mkdir -p "$POSTOVERFLOWS_DIR"
mkdir -p "$CSCLI_DIR" mkdir -p "$CSCLI_DIR"
mkdir -p "$HUB_DIR" mkdir -p "$HUB_DIR"
mkdir -p $CONFIG_DIR/$NOTIF_DIR/$plugin mkdir -p "$CONFIG_DIR/$NOTIF_DIR/$plugin"
mkdir -p $BASE/$PLUGINS_DIR mkdir -p "$BASE/$PLUGINS_DIR"
} }
copy_files() { copy_files() {

View file

@ -41,6 +41,7 @@ bats-build: bats-environment bats-check-requirements
@install -m 0755 plugins/notifications/http/notification-http $(PLUGIN_DIR)/ @install -m 0755 plugins/notifications/http/notification-http $(PLUGIN_DIR)/
@install -m 0755 plugins/notifications/slack/notification-slack $(PLUGIN_DIR)/ @install -m 0755 plugins/notifications/slack/notification-slack $(PLUGIN_DIR)/
@install -m 0755 plugins/notifications/splunk/notification-splunk $(PLUGIN_DIR)/ @install -m 0755 plugins/notifications/splunk/notification-splunk $(PLUGIN_DIR)/
@install -m 0755 plugins/notifications/dummy/notification-dummy $(PLUGIN_DIR)/
# Create a reusable package with initial configuration + data # Create a reusable package with initial configuration + data
@$(TEST_DIR)/instance-data make @$(TEST_DIR)/instance-data make
# Generate dynamic tests # Generate dynamic tests

View file

@ -0,0 +1,55 @@
#!/usr/bin/env bats
# vim: ft=bats:list:ts=8:sts=4:sw=4:et:ai:si:
set -u
setup_file() {
load "../lib/setup_file.sh" >&3 2>&1
./instance-data load
tempfile=$(TMPDIR="${BATS_FILE_TMPDIR}" mktemp)
export tempfile
yq "
.group_wait=\"5s\" |
.group_threshold=2 |
.output_file=\"${tempfile}\"
" -i "${CONFIG_DIR}/notifications/dummy.yaml"
yq '
.notifications=["dummy_default"] |
.filters=["Alert.GetScope() == \"Ip\""]
' -i "${CONFIG_DIR}/profiles.yaml"
yq '
.plugin_config.user="" |
.plugin_config.group=""
' -i "${CONFIG_DIR}/config.yaml"
./instance-crowdsec start
}
teardown_file() {
load "../lib/teardown_file.sh" >&3 2>&1
}
setup() {
load "../lib/setup.sh"
}
#----------
@test "$FILE add two bans" {
run -0 cscli decisions add --ip 1.2.3.4 --duration 30s
assert_output --partial 'Decision successfully added'
run -0 cscli decisions add --ip 1.2.3.5 --duration 30s
assert_output --partial 'Decision successfully added'
sleep 2
}
@test "$FILE expected 1 notification" {
run -0 cat "${tempfile}"
assert_output --partial 1.2.3.4
assert_output --partial 1.2.3.5
}

View file

@ -0,0 +1,22 @@
type: dummy # Don't change
name: dummy_default # Must match the registered plugin in the profile
# One of "trace", "debug", "info", "warn", "error", "off"
log_level: info
# group_wait: # Time to wait collecting alerts before relaying a message to this plugin, eg "30s"
# group_threshold: # Amount of alerts that triggers a message before <group_wait> has expired, eg "10"
# max_retry: # Number of attempts to relay messages to plugins in case of error
# timeout: # Time to wait for response from the plugin before considering the attempt a failure, eg "10s"
#-------------------------
# plugin-specific options
# The following template receives a list of models.Alert objects
# The output goes in the logs and to a text file, if defined
format: |
{{.|toJson}}
#
# output_file: # notifications will be appended here. optional

View file

@ -9,5 +9,5 @@ decisions:
# - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this. # - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this.
# - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this. # - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this.
# - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this. # - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this.
# - email_default # Set the required http parameters in /etc/crowdsec/notifications/email.yaml before enabling this. # - email_default # Set the required email parameters in /etc/crowdsec/notifications/email.yaml before enabling this.
on_success: break on_success: break

View file

@ -57,6 +57,7 @@ make_init_data() {
envsubst < "./config-templates/notifications/email.yaml" > "${CONFIG_DIR}/notifications/email.yaml" envsubst < "./config-templates/notifications/email.yaml" > "${CONFIG_DIR}/notifications/email.yaml"
envsubst < "./config-templates/notifications/slack.yaml" > "${CONFIG_DIR}/notifications/slack.yaml" envsubst < "./config-templates/notifications/slack.yaml" > "${CONFIG_DIR}/notifications/slack.yaml"
envsubst < "./config-templates/notifications/splunk.yaml" > "${CONFIG_DIR}/notifications/splunk.yaml" envsubst < "./config-templates/notifications/splunk.yaml" > "${CONFIG_DIR}/notifications/splunk.yaml"
envsubst < "./config-templates/notifications/dummy.yaml" > "${CONFIG_DIR}/notifications/dummy.yaml"
mkdir -p "${CONFIG_DIR}/hub" mkdir -p "${CONFIG_DIR}/hub"
"${BIN_DIR}/cscli" machines add githubciXXXXXXXXXXXXXXXXXXXXXXXX --auto "${BIN_DIR}/cscli" machines add githubciXXXXXXXXXXXXXXXXXXXXXXXX --auto

View file

@ -77,7 +77,7 @@ SPLUNK_PLUGIN_CONFIG="./plugins/notifications/splunk/splunk.yaml"
EMAIL_PLUGIN_CONFIG="./plugins/notifications/email/email.yaml" EMAIL_PLUGIN_CONFIG="./plugins/notifications/email/email.yaml"
BACKUP_DIR=$(mktemp -d) BACKUP_DIR=$(mktemp -d)
rm -rf $BACKUP_DIR rm -rf -- "$BACKUP_DIR"
log_info() { log_info() {
msg=$1 msg=$1
@ -502,7 +502,7 @@ install_plugins(){
cp -n ${SLACK_PLUGIN_CONFIG} /etc/crowdsec/notifications/ cp -n ${SLACK_PLUGIN_CONFIG} /etc/crowdsec/notifications/
cp -n ${SPLUNK_PLUGIN_CONFIG} /etc/crowdsec/notifications/ cp -n ${SPLUNK_PLUGIN_CONFIG} /etc/crowdsec/notifications/
cp -n ${HTTP_PLUGIN_CONFIG} /etc/crowdsec/notifications/ cp -n ${HTTP_PLUGIN_CONFIG} /etc/crowdsec/notifications/
cp -n ${EMAIL_PLUGIN_CONFIG} /etc/crowdsec/notifications cp -n ${EMAIL_PLUGIN_CONFIG} /etc/crowdsec/notifications/
fi fi
} }