notification-email: configurable timeouts (#2465)
* configurable timeouts * parse email timeouts as duration string * add helo_host to email.yaml * move html and body tags outside of the loops * added quotes to href=.., and formatting test
This commit is contained in:
parent
b8e6bd8c9a
commit
3cb9dbdb21
7 changed files with 102 additions and 6 deletions
|
@ -15,12 +15,14 @@ timeout: 20s # Time to wait for response from the plugin before conside
|
||||||
# The following template receives a list of models.Alert objects
|
# The following template receives a list of models.Alert objects
|
||||||
# The output goes in the email message body
|
# The output goes in the email message body
|
||||||
format: |
|
format: |
|
||||||
|
<html><body>
|
||||||
{{range . -}}
|
{{range . -}}
|
||||||
{{$alert := . -}}
|
{{$alert := . -}}
|
||||||
{{range .Decisions -}}
|
{{range .Decisions -}}
|
||||||
<html><body><p><a href=https://www.whois.com/whois/{{.Value}}>{{.Value}}</a> will get <b>{{.Type}}</b> for next <b>{{.Duration}}</b> for triggering <b>{{.Scenario}}</b> on machine <b>{{$alert.MachineID}}</b>.</p> <p><a href=https://app.crowdsec.net/cti/{{.Value}}>CrowdSec CTI</a></p></body></html>
|
<p><a href="https://www.whois.com/whois/{{.Value}}">{{.Value}}</a> will get <b>{{.Type}}</b> for next <b>{{.Duration}}</b> for triggering <b>{{.Scenario}}</b> on machine <b>{{$alert.MachineID}}</b>.</p> <p><a href="https://app.crowdsec.net/cti/{{.Value}}">CrowdSec CTI</a></p>
|
||||||
{{end -}}
|
{{end -}}
|
||||||
{{end -}}
|
{{end -}}
|
||||||
|
</body></html>
|
||||||
|
|
||||||
smtp_host: # example: smtp.gmail.com
|
smtp_host: # example: smtp.gmail.com
|
||||||
smtp_username: # Replace with your actual username
|
smtp_username: # Replace with your actual username
|
||||||
|
@ -35,7 +37,15 @@ receiver_emails:
|
||||||
# - email2@gmail.com
|
# - email2@gmail.com
|
||||||
|
|
||||||
# One of "ssltls", "starttls", "none"
|
# One of "ssltls", "starttls", "none"
|
||||||
encryption_type: ssltls
|
encryption_type: "ssltls"
|
||||||
|
|
||||||
|
# If you need to set the HELO hostname:
|
||||||
|
# helo_host: "localhost"
|
||||||
|
|
||||||
|
# If the email server is hitting the default timeouts (10 seconds), you can increase them here
|
||||||
|
#
|
||||||
|
# connect_timeout: 10s
|
||||||
|
# send_timeout: 10s
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/crowdsecurity/crowdsec/pkg/protobufs"
|
"github.com/crowdsecurity/crowdsec/pkg/protobufs"
|
||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
|
@ -47,6 +48,8 @@ type PluginConfig struct {
|
||||||
EncryptionType string `yaml:"encryption_type"`
|
EncryptionType string `yaml:"encryption_type"`
|
||||||
AuthType string `yaml:"auth_type"`
|
AuthType string `yaml:"auth_type"`
|
||||||
HeloHost string `yaml:"helo_host"`
|
HeloHost string `yaml:"helo_host"`
|
||||||
|
ConnectTimeout string `yaml:"connect_timeout"`
|
||||||
|
SendTimeout string `yaml:"send_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmailPlugin struct {
|
type EmailPlugin struct {
|
||||||
|
@ -77,7 +80,7 @@ func (n *EmailPlugin) Configure(ctx context.Context, config *protobufs.Config) (
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.ReceiverEmails == nil || len(d.ReceiverEmails) == 0 {
|
if d.ReceiverEmails == nil || len(d.ReceiverEmails) == 0 {
|
||||||
return nil, fmt.Errorf("Receiver emails are not set")
|
return nil, fmt.Errorf("receiver emails are not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
n.ConfigByName[d.Name] = d
|
n.ConfigByName[d.Name] = d
|
||||||
|
@ -108,6 +111,24 @@ func (n *EmailPlugin) Notify(ctx context.Context, notification *protobufs.Notifi
|
||||||
server.Authentication = AuthStringToType[cfg.AuthType]
|
server.Authentication = AuthStringToType[cfg.AuthType]
|
||||||
server.Helo = cfg.HeloHost
|
server.Helo = cfg.HeloHost
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if cfg.ConnectTimeout != "" {
|
||||||
|
server.ConnectTimeout, err = time.ParseDuration(cfg.ConnectTimeout)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn(fmt.Sprintf("invalid connect timeout '%s', using default '10s'", cfg.ConnectTimeout))
|
||||||
|
server.ConnectTimeout = 10 * time.Second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.SendTimeout != "" {
|
||||||
|
server.SendTimeout, err = time.ParseDuration(cfg.SendTimeout)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn(fmt.Sprintf("invalid send timeout '%s', using default '10s'", cfg.SendTimeout))
|
||||||
|
server.SendTimeout = 10 * time.Second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.Debug("making smtp connection")
|
logger.Debug("making smtp connection")
|
||||||
smtpClient, err := server.Connect()
|
smtpClient, err := server.Connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -73,7 +73,7 @@ require (
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26
|
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26
|
||||||
github.com/wasilibs/go-re2 v1.3.0
|
github.com/wasilibs/go-re2 v1.3.0
|
||||||
github.com/xhit/go-simple-mail/v2 v2.15.0
|
github.com/xhit/go-simple-mail/v2 v2.16.0
|
||||||
golang.org/x/crypto v0.9.0
|
golang.org/x/crypto v0.9.0
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
|
||||||
golang.org/x/mod v0.11.0
|
golang.org/x/mod v0.11.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -790,8 +790,8 @@ github.com/xdg/scram v1.0.5/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49
|
||||||
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||||
github.com/xdg/stringprep v1.0.3 h1:cmL5Enob4W83ti/ZHuZLuKD/xqJfus4fVPwE+/BDm+4=
|
github.com/xdg/stringprep v1.0.3 h1:cmL5Enob4W83ti/ZHuZLuKD/xqJfus4fVPwE+/BDm+4=
|
||||||
github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||||
github.com/xhit/go-simple-mail/v2 v2.15.0 h1:qMXeqcZErUW/Dw6EXxmPuxHzVI8MdxWnEnu2xcisohU=
|
github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA=
|
||||||
github.com/xhit/go-simple-mail/v2 v2.15.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
|
github.com/xhit/go-simple-mail/v2 v2.16.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
|
||||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
|
65
test/bats/73_plugin_formatting.bats
Normal file
65
test/bats/73_plugin_formatting.bats
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#!/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"
|
||||||
|
is_package_testing && return
|
||||||
|
|
||||||
|
./instance-data load
|
||||||
|
|
||||||
|
tempfile=$(TMPDIR="${BATS_FILE_TMPDIR}" mktemp)
|
||||||
|
export tempfile
|
||||||
|
|
||||||
|
DUMMY_YAML="$(config_get '.config_paths.notification_dir')/dummy.yaml"
|
||||||
|
|
||||||
|
# we test the template that is suggested in the email notification
|
||||||
|
# the $alert is not a shell variable
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
config_set "${DUMMY_YAML}" '
|
||||||
|
.group_wait="5s" |
|
||||||
|
.group_threshold=2 |
|
||||||
|
.output_file=strenv(tempfile) |
|
||||||
|
.format="<html><body> {{range . -}} {{$alert := . -}} {{range .Decisions -}} <p><a href=\"https://www.whois.com/whois/{{.Value}}\">{{.Value}}</a> will get <b>{{.Type}}</b> for next <b>{{.Duration}}</b> for triggering <b>{{.Scenario}}</b> on machine <b>{{$alert.MachineID}}</b>.</p> <p><a href=\"https://app.crowdsec.net/cti/{{.Value}}\">CrowdSec CTI</a></p> {{end -}} {{end -}} </body></html>"
|
||||||
|
'
|
||||||
|
|
||||||
|
config_set "$(config_get '.api.server.profiles_path')" '
|
||||||
|
.notifications=["dummy_default"] |
|
||||||
|
.filters=["Alert.GetScope() == \"Ip\""]
|
||||||
|
'
|
||||||
|
|
||||||
|
config_set '
|
||||||
|
.plugin_config.user="" |
|
||||||
|
.plugin_config.group=""
|
||||||
|
'
|
||||||
|
|
||||||
|
./instance-crowdsec start
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown_file() {
|
||||||
|
load "../lib/teardown_file.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
is_package_testing && skip
|
||||||
|
load "../lib/setup.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------
|
||||||
|
|
||||||
|
@test "add two bans" {
|
||||||
|
rune -0 cscli decisions add --ip 1.2.3.4 --duration 30s
|
||||||
|
assert_stderr --partial 'Decision successfully added'
|
||||||
|
|
||||||
|
rune -0 cscli decisions add --ip 1.2.3.5 --duration 30s
|
||||||
|
assert_stderr --partial 'Decision successfully added'
|
||||||
|
sleep 2
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "expected 1 notification" {
|
||||||
|
rune -0 cat "${tempfile}"
|
||||||
|
assert_output - <<-EOT
|
||||||
|
<html><body> <p><a href="https://www.whois.com/whois/1.2.3.4">1.2.3.4</a> will get <b>ban</b> for next <b>30s</b> for triggering <b>manual 'ban' from 'githubciXXXXXXXXXXXXXXXXXXXXXXXX'</b> on machine <b>githubciXXXXXXXXXXXXXXXXXXXXXXXX</b>.</p> <p><a href="https://app.crowdsec.net/cti/1.2.3.4">CrowdSec CTI</a></p> <p><a href="https://www.whois.com/whois/1.2.3.5">1.2.3.5</a> will get <b>ban</b> for next <b>30s</b> for triggering <b>manual 'ban' from 'githubciXXXXXXXXXXXXXXXXXXXXXXXX'</b> on machine <b>githubciXXXXXXXXXXXXXXXXXXXXXXXX</b>.</p> <p><a href="https://app.crowdsec.net/cti/1.2.3.5">CrowdSec CTI</a></p> </body></html>
|
||||||
|
EOT
|
||||||
|
}
|
Loading…
Reference in a new issue