appsec renaming, part 1

This commit is contained in:
Sebastien Blot 2023-12-04 21:41:51 +01:00
parent 42e1da2507
commit c3a4066646
No known key found for this signature in database
GPG key ID: DFC2902F40449F6A
12 changed files with 167 additions and 168 deletions

View file

@ -12,7 +12,7 @@ import (
"github.com/crowdsecurity/go-cs-lib/trace"
"github.com/crowdsecurity/go-cs-lib/version"
waap "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/waap"
appsec "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/appsec"
v1 "github.com/crowdsecurity/crowdsec/pkg/apiserver/controllers/v1"
"github.com/crowdsecurity/crowdsec/pkg/cache"
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
@ -163,8 +163,8 @@ func registerPrometheus(config *csconfig.PrometheusCfg) {
v1.LapiRouteHits,
leaky.BucketsCurrentCount,
cache.CacheMetrics, exprhelpers.RegexpCacheMetrics,
waap.WafGlobalParsingHistogram, waap.WafReqCounter, waap.WafRuleHits,
waap.WafBlockCounter,
appsec.AppsecGlobalParsingHistogram, appsec.AppsecReqCounter, appsec.AppsecRuleHits,
appsec.AppsecBlockCounter,
)
} else {
log.Infof("Loading prometheus collectors")
@ -175,7 +175,7 @@ func registerPrometheus(config *csconfig.PrometheusCfg) {
leaky.BucketsPour, leaky.BucketsUnderflow, leaky.BucketsCanceled, leaky.BucketsInstantiation, leaky.BucketsOverflow, leaky.BucketsCurrentCount,
globalActiveDecisions, globalAlerts,
cache.CacheMetrics, exprhelpers.RegexpCacheMetrics,
waap.WafGlobalParsingHistogram, waap.WafInbandParsingHistogram, waap.WafOutbandParsingHistogram, waap.WafReqCounter, waap.WafRuleHits, waap.WafBlockCounter,
appsec.AppsecGlobalParsingHistogram, appsec.AppsecInbandParsingHistogram, appsec.AppsecOutbandParsingHistogram, appsec.AppsecReqCounter, appsec.AppsecRuleHits, appsec.AppsecBlockCounter,
)
}

View file

@ -25,7 +25,7 @@ LOOP:
/*Waap is going to generate 2 events:
- one that is treated as a log and can go to scenarios
- another one that will go directly to LAPI*/
if event.Type == types.WAAP {
if event.Type == types.APPSEC {
outputEventChan <- event
continue
}

View file

@ -18,6 +18,7 @@ import (
"github.com/crowdsecurity/go-cs-lib/trace"
"github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration"
appsecacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/appsec"
cloudwatchacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/cloudwatch"
dockeracquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/docker"
fileacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/file"
@ -28,7 +29,6 @@ import (
lokiacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/loki"
s3acquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/s3"
syslogacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/syslog"
wafacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/waap"
wineventlogacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/wineventlog"
"github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
@ -77,7 +77,7 @@ var AcquisitionSources = map[string]func() DataSource{
"k8s-audit": func() DataSource { return &k8sauditacquisition.KubernetesAuditSource{} },
"loki": func() DataSource { return &lokiacquisition.LokiSource{} },
"s3": func() DataSource { return &s3acquisition.S3Source{} },
"waf": func() DataSource { return &wafacquisition.WaapSource{} },
"waf": func() DataSource { return &appsecacquisition.AppsecSource{} },
}
var transformRuntimes = map[string]*vm.Program{}

View file

@ -1,4 +1,4 @@
package wafacquisition
package appsecacquisition
import (
"context"
@ -32,32 +32,32 @@ var (
)
// configuration structure of the acquis for the Waap
type WaapSourceConfig struct {
type AppsecSourceConfig struct {
ListenAddr string `yaml:"listen_addr"`
CertFilePath string `yaml:"cert_file"`
KeyFilePath string `yaml:"key_file"`
Path string `yaml:"path"`
Routines int `yaml:"routines"`
WaapConfig string `yaml:"waap_config"`
WaapConfigPath string `yaml:"waap_config_path"`
AppsecConfig string `yaml:"appsec_config"`
AppsecConfigPath string `yaml:"appsec_config_path"`
AuthCacheDuration *time.Duration `yaml:"auth_cache_duration"`
configuration.DataSourceCommonCfg `yaml:",inline"`
}
// runtime structure of WaapSourceConfig
type WaapSource struct {
config WaapSourceConfig
logger *log.Entry
mux *http.ServeMux
server *http.Server
addr string
outChan chan types.Event
InChan chan waf.ParsedRequest
WaapRuntime *waf.WaapRuntimeConfig
WaapConfigs map[string]waf.WaapConfig
lapiURL string
AuthCache AuthCache
WaapRunners []WaapRunner //one for each go-routine
type AppsecSource struct {
config AppsecSourceConfig
logger *log.Entry
mux *http.ServeMux
server *http.Server
addr string
outChan chan types.Event
InChan chan waf.ParsedRequest
AppsecRuntime *waf.WaapRuntimeConfig
AppsecConfigs map[string]waf.WaapConfig
lapiURL string
AuthCache AuthCache
AppsecRunners []AppsecRunner //one for each go-routine
}
// Struct to handle cache of authentication
@ -91,11 +91,11 @@ type BodyResponse struct {
Action string `json:"action"`
}
func (wc *WaapSource) UnmarshalConfig(yamlConfig []byte) error {
func (wc *AppsecSource) UnmarshalConfig(yamlConfig []byte) error {
err := yaml.UnmarshalStrict(yamlConfig, &wc.config)
if err != nil {
return errors.Wrap(err, "Cannot parse waf configuration")
return errors.Wrap(err, "Cannot parse appsec configuration")
}
if wc.config.LogLevel == nil {
@ -124,8 +124,8 @@ func (wc *WaapSource) UnmarshalConfig(yamlConfig []byte) error {
wc.config.Routines = 1
}
if wc.config.WaapConfig == "" && wc.config.WaapConfigPath == "" {
return fmt.Errorf("waap_config or waap_config_path must be set")
if wc.config.AppsecConfig == "" && wc.config.AppsecConfigPath == "" {
return fmt.Errorf("appsec_config or appsec_config_path must be set")
}
if wc.config.Name == "" {
@ -139,15 +139,15 @@ func (wc *WaapSource) UnmarshalConfig(yamlConfig []byte) error {
return nil
}
func (w *WaapSource) GetMetrics() []prometheus.Collector {
func (w *AppsecSource) GetMetrics() []prometheus.Collector {
return nil
}
func (w *WaapSource) GetAggregMetrics() []prometheus.Collector {
func (w *AppsecSource) GetAggregMetrics() []prometheus.Collector {
return nil
}
func (w *WaapSource) Configure(yamlConfig []byte, logger *log.Entry) error {
func (w *AppsecSource) Configure(yamlConfig []byte, logger *log.Entry) error {
err := w.UnmarshalConfig(yamlConfig)
if err != nil {
return errors.Wrap(err, "unable to parse waf configuration")
@ -170,96 +170,95 @@ func (w *WaapSource) Configure(yamlConfig []byte, logger *log.Entry) error {
}
w.InChan = make(chan waf.ParsedRequest)
waapCfg := waf.WaapConfig{Logger: w.logger.WithField("component", "waap_config")}
appsecCfg := waf.WaapConfig{Logger: w.logger.WithField("component", "appsec_config")}
//let's load the associated waap_config:
if w.config.WaapConfigPath != "" {
err := waapCfg.LoadByPath(w.config.WaapConfigPath)
//let's load the associated appsec_config:
if w.config.AppsecConfigPath != "" {
err := appsecCfg.LoadByPath(w.config.AppsecConfigPath)
if err != nil {
return fmt.Errorf("unable to load waap_config : %s", err)
return fmt.Errorf("unable to load appsec_config : %s", err)
}
} else if w.config.WaapConfig != "" {
err := waapCfg.Load(w.config.WaapConfig)
} else if w.config.AppsecConfig != "" {
err := appsecCfg.Load(w.config.AppsecConfig)
if err != nil {
return fmt.Errorf("unable to load waap_config : %s", err)
return fmt.Errorf("unable to load appsec_config : %s", err)
}
} else {
return fmt.Errorf("no waap_config provided")
return fmt.Errorf("no appsec_config provided")
}
w.WaapRuntime, err = waapCfg.Build()
w.AppsecRuntime, err = appsecCfg.Build()
if err != nil {
return fmt.Errorf("unable to build waap_config : %s", err)
return fmt.Errorf("unable to build appsec_config : %s", err)
}
err = w.WaapRuntime.ProcessOnLoadRules()
err = w.AppsecRuntime.ProcessOnLoadRules()
if err != nil {
return fmt.Errorf("unable to process on load rules : %s", err)
}
w.WaapRunners = make([]WaapRunner, w.config.Routines)
w.AppsecRunners = make([]AppsecRunner, w.config.Routines)
for nbRoutine := 0; nbRoutine < w.config.Routines; nbRoutine++ {
wafUUID := uuid.New().String()
//we copy WaapRutime for each runner
wrt := *w.WaapRuntime
runner := WaapRunner{
appsecRunnerUUID := uuid.New().String()
//we copy AppsecRutime for each runner
wrt := *w.AppsecRuntime
runner := AppsecRunner{
inChan: w.InChan,
UUID: wafUUID,
UUID: appsecRunnerUUID,
logger: w.logger.WithFields(log.Fields{
"uuid": wafUUID,
"uuid": appsecRunnerUUID,
}),
WaapRuntime: &wrt,
}
err := runner.Init(waapCfg.GetDataDir())
err := runner.Init(appsecCfg.GetDataDir())
if err != nil {
return fmt.Errorf("unable to initialize runner : %s", err)
}
w.WaapRunners[nbRoutine] = runner
w.AppsecRunners[nbRoutine] = runner
}
w.logger.Infof("Created %d waf runners", len(w.WaapRunners))
w.logger.Infof("Created %d appsec runners", len(w.AppsecRunners))
//We don´t use the wrapper provided by coraza because we want to fully control what happens when a rule match to send the information in crowdsec
w.mux.HandleFunc(w.config.Path, w.waapHandler)
w.mux.HandleFunc(w.config.Path, w.appsecHandler)
return nil
}
func (w *WaapSource) ConfigureByDSN(dsn string, labels map[string]string, logger *log.Entry, uuid string) error {
return fmt.Errorf("WAF datasource does not support command line acquisition")
func (w *AppsecSource) ConfigureByDSN(dsn string, labels map[string]string, logger *log.Entry, uuid string) error {
return fmt.Errorf("AppSec datasource does not support command line acquisition")
}
func (w *WaapSource) GetMode() string {
func (w *AppsecSource) GetMode() string {
return w.config.Mode
}
func (w *WaapSource) GetName() string {
return "waf"
func (w *AppsecSource) GetName() string {
return "appsec"
}
func (w *WaapSource) OneShotAcquisition(out chan types.Event, t *tomb.Tomb) error {
return fmt.Errorf("WAF datasource does not support command line acquisition")
func (w *AppsecSource) OneShotAcquisition(out chan types.Event, t *tomb.Tomb) error {
return fmt.Errorf("AppSec datasource does not support command line acquisition")
}
func (w *WaapSource) StreamingAcquisition(out chan types.Event, t *tomb.Tomb) error {
func (w *AppsecSource) StreamingAcquisition(out chan types.Event, t *tomb.Tomb) error {
w.outChan = out
t.Go(func() error {
defer trace.CatchPanic("crowdsec/acquis/waf/live")
defer trace.CatchPanic("crowdsec/acquis/appsec/live")
w.logger.Infof("%d waf runner to start", len(w.WaapRunners))
for _, runner := range w.WaapRunners {
w.logger.Infof("%d appsec runner to start", len(w.AppsecRunners))
for _, runner := range w.AppsecRunners {
runner := runner
runner.outChan = out
t.Go(func() error {
defer trace.CatchPanic("crowdsec/acquis/waf/live/runner")
defer trace.CatchPanic("crowdsec/acquis/appsec/live/runner")
return runner.Run(t)
})
}
w.logger.Infof("Starting WAF server on %s%s", w.config.ListenAddr, w.config.Path)
w.logger.Infof("Starting Appsec server on %s%s", w.config.ListenAddr, w.config.Path)
t.Go(func() error {
var err error
if w.config.CertFilePath != "" && w.config.KeyFilePath != "" {
@ -269,31 +268,31 @@ func (w *WaapSource) StreamingAcquisition(out chan types.Event, t *tomb.Tomb) er
}
if err != nil && err != http.ErrServerClosed {
return errors.Wrap(err, "WAF server failed")
return errors.Wrap(err, "Appsec server failed")
}
return nil
})
<-t.Dying()
w.logger.Infof("Stopping WAF server on %s%s", w.config.ListenAddr, w.config.Path)
w.logger.Infof("Stopping Appsec server on %s%s", w.config.ListenAddr, w.config.Path)
w.server.Shutdown(context.TODO())
return nil
})
return nil
}
func (w *WaapSource) CanRun() error {
func (w *AppsecSource) CanRun() error {
return nil
}
func (w *WaapSource) GetUuid() string {
func (w *AppsecSource) GetUuid() string {
return w.config.UniqueId
}
func (w *WaapSource) Dump() interface{} {
func (w *AppsecSource) Dump() interface{} {
return w
}
func (w *WaapSource) IsAuth(apiKey string) bool {
func (w *AppsecSource) IsAuth(apiKey string) bool {
client := &http.Client{
Timeout: 200 * time.Millisecond,
}
@ -317,7 +316,7 @@ func (w *WaapSource) IsAuth(apiKey string) bool {
}
// should this be in the runner ?
func (w *WaapSource) waapHandler(rw http.ResponseWriter, r *http.Request) {
func (w *AppsecSource) appsecHandler(rw http.ResponseWriter, r *http.Request) {
apiKey := r.Header.Get(waf.APIKeyHeaderName)
clientIP := r.Header.Get(waf.IPHeaderName)
remoteIP := r.RemoteAddr
@ -348,19 +347,19 @@ func (w *WaapSource) waapHandler(rw http.ResponseWriter, r *http.Request) {
}
parsedRequest.WaapEngine = w.config.Name
WafReqCounter.With(prometheus.Labels{"source": parsedRequest.RemoteAddrNormalized, "waap_engine": parsedRequest.WaapEngine}).Inc()
AppsecReqCounter.With(prometheus.Labels{"source": parsedRequest.RemoteAddrNormalized, "appsec_engine": parsedRequest.WaapEngine}).Inc()
w.InChan <- parsedRequest
response := <-parsedRequest.ResponseChannel
if response.InBandInterrupt {
WafBlockCounter.With(prometheus.Labels{"source": parsedRequest.RemoteAddrNormalized, "waap_engine": parsedRequest.WaapEngine}).Inc()
AppsecBlockCounter.With(prometheus.Labels{"source": parsedRequest.RemoteAddrNormalized, "appsec_engine": parsedRequest.WaapEngine}).Inc()
}
waapResponse := w.WaapRuntime.GenerateResponse(response)
appsecResponse := w.AppsecRuntime.GenerateResponse(response)
rw.WriteHeader(waapResponse.HTTPStatus)
body, err := json.Marshal(BodyResponse{Action: waapResponse.Action})
rw.WriteHeader(appsecResponse.HTTPStatus)
body, err := json.Marshal(BodyResponse{Action: appsecResponse.Action})
if err != nil {
log.Errorf("unable to marshal response: %s", err)
rw.WriteHeader(http.StatusInternalServerError)

View file

@ -1,4 +1,4 @@
package wafacquisition
package appsecacquisition
import (
"fmt"
@ -16,7 +16,7 @@ import (
)
// that's the runtime structure of the WAAP as seen from the acquis
type WaapRunner struct {
type AppsecRunner struct {
outChan chan types.Event
inChan chan waf.ParsedRequest
UUID string
@ -26,7 +26,7 @@ type WaapRunner struct {
logger *log.Entry
}
func (r *WaapRunner) Init(datadir string) error {
func (r *AppsecRunner) Init(datadir string) error {
var err error
fs := os.DirFS(datadir)
@ -101,7 +101,7 @@ func (r *WaapRunner) Init(datadir string) error {
return nil
}
func (r *WaapRunner) processRequest(tx waf.ExtendedTransaction, request *waf.ParsedRequest) error {
func (r *AppsecRunner) processRequest(tx waf.ExtendedTransaction, request *waf.ParsedRequest) error {
var in *corazatypes.Interruption
var err error
request.Tx = tx
@ -185,21 +185,21 @@ func (r *WaapRunner) processRequest(tx waf.ExtendedTransaction, request *waf.Par
return nil
}
func (r *WaapRunner) ProcessInBandRules(request *waf.ParsedRequest) error {
func (r *AppsecRunner) ProcessInBandRules(request *waf.ParsedRequest) error {
tx := waf.NewExtendedTransaction(r.WaapInbandEngine, request.UUID)
r.WaapRuntime.InBandTx = tx
err := r.processRequest(tx, request)
return err
}
func (r *WaapRunner) ProcessOutOfBandRules(request *waf.ParsedRequest) error {
func (r *AppsecRunner) ProcessOutOfBandRules(request *waf.ParsedRequest) error {
tx := waf.NewExtendedTransaction(r.WaapOutbandEngine, request.UUID)
r.WaapRuntime.OutOfBandTx = tx
err := r.processRequest(tx, request)
return err
}
func (r *WaapRunner) handleInBandInterrupt(request *waf.ParsedRequest) {
func (r *AppsecRunner) handleInBandInterrupt(request *waf.ParsedRequest) {
//create the associated event for crowdsec itself
evt, err := EventFromRequest(request)
if err != nil {
@ -238,17 +238,17 @@ func (r *WaapRunner) handleInBandInterrupt(request *waf.ParsedRequest) {
// Should the in band match trigger an overflow ?
if r.WaapRuntime.Response.SendAlert {
waapOvlfw, err := WaapEventGeneration(evt)
appsecOvlfw, err := AppsecEventGeneration(evt)
if err != nil {
r.logger.Errorf("unable to generate waap event : %s", err)
r.logger.Errorf("unable to generate appsec event : %s", err)
return
}
r.outChan <- *waapOvlfw
r.outChan <- *appsecOvlfw
}
}
}
func (r *WaapRunner) handleOutBandInterrupt(request *waf.ParsedRequest) {
func (r *AppsecRunner) handleOutBandInterrupt(request *waf.ParsedRequest) {
evt, err := EventFromRequest(request)
if err != nil {
//let's not interrupt the pipeline for this
@ -274,24 +274,24 @@ func (r *WaapRunner) handleOutBandInterrupt(request *waf.ParsedRequest) {
// Should the match trigger an overflow ?
if r.WaapRuntime.Response.SendAlert {
waapOvlfw, err := WaapEventGeneration(evt)
appsecOvlfw, err := AppsecEventGeneration(evt)
if err != nil {
r.logger.Errorf("unable to generate waap event : %s", err)
return
}
r.outChan <- *waapOvlfw
r.outChan <- *appsecOvlfw
}
}
}
func (r *WaapRunner) handleRequest(request *waf.ParsedRequest) {
func (r *AppsecRunner) handleRequest(request *waf.ParsedRequest) {
r.logger.Debugf("Requests handled by runner %s", request.UUID)
r.WaapRuntime.ClearResponse()
request.IsInBand = true
request.IsOutBand = false
//to measure the time spent in the WAF
//to measure the time spent in the Application Security Engine
startParsing := time.Now()
//inband WAAP rules
@ -306,7 +306,7 @@ func (r *WaapRunner) handleRequest(request *waf.ParsedRequest) {
}
elapsed := time.Since(startParsing)
WafInbandParsingHistogram.With(prometheus.Labels{"source": request.RemoteAddr}).Observe(elapsed.Seconds())
AppsecInbandParsingHistogram.With(prometheus.Labels{"source": request.RemoteAddr}).Observe(elapsed.Seconds())
// send back the result to the HTTP handler for the InBand part
request.ResponseChannel <- r.WaapRuntime.Response
@ -329,7 +329,7 @@ func (r *WaapRunner) handleRequest(request *waf.ParsedRequest) {
}
}
func (r *WaapRunner) Run(t *tomb.Tomb) error {
func (r *AppsecRunner) Run(t *tomb.Tomb) error {
r.logger.Infof("Waap Runner ready to process event")
for {
select {

View file

@ -0,0 +1,54 @@
package appsecacquisition
import "github.com/prometheus/client_golang/prometheus"
var AppsecGlobalParsingHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Help: "Time spent processing a request by the Application Security Engine.",
Name: "cs_appsec_parsing_time_seconds",
Buckets: []float64{0.0005, 0.001, 0.0015, 0.002, 0.0025, 0.003, 0.004, 0.005, 0.0075, 0.01},
},
[]string{"source"},
)
var AppsecInbandParsingHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Help: "Time spent processing a request by the inband Application Security Engine.",
Name: "cs_appsec_inband_parsing_time_seconds",
Buckets: []float64{0.0005, 0.001, 0.0015, 0.002, 0.0025, 0.003, 0.004, 0.005, 0.0075, 0.01},
},
[]string{"source"},
)
var AppsecOutbandParsingHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Help: "Time spent processing a request by the Application Security Engine.",
Name: "cs_appsec_outband_parsing_time_seconds",
Buckets: []float64{0.0005, 0.001, 0.0015, 0.002, 0.0025, 0.003, 0.004, 0.005, 0.0075, 0.01},
},
[]string{"source"},
)
var AppsecReqCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "cs_appsec_reqs_total",
Help: "Total events processed by the Application Security Engine.",
},
[]string{"source", "appsec_engine"},
)
var AppsecBlockCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "cs_appsec_block_total",
Help: "Total events blocked by the Application Security Engine.",
},
[]string{"source", "appsec_engine"},
)
var AppsecRuleHits = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "cs_appsec_rule_hits",
Help: "Count of triggered rule, by rule_name, type (inband/outofband), appsec_engine and source",
},
[]string{"rule_name", "type", "appsec_engine", "source"},
)

View file

@ -1,4 +1,4 @@
package wafacquisition
package appsecacquisition
import (
"fmt"

View file

@ -1,4 +1,4 @@
package wafacquisition
package appsecacquisition
import (
"encoding/json"
@ -15,13 +15,13 @@ import (
log "github.com/sirupsen/logrus"
)
func WaapEventGeneration(inEvt types.Event) (*types.Event, error) {
func AppsecEventGeneration(inEvt types.Event) (*types.Event, error) {
//if the request didnd't trigger inband rules, we don't want to generate an event to LAPI/CAPI
if !inEvt.Waap.HasInBandMatches {
return nil, nil
}
evt := types.Event{}
evt.Type = types.WAAP
evt.Type = types.APPSEC
evt.Process = true
source := models.Source{
Value: ptr.Of(inEvt.Parsed["source_ip"]),
@ -53,7 +53,7 @@ func WaapEventGeneration(inEvt types.Event) (*types.Event, error) {
alert.EventsCount = ptr.Of(int32(1))
alert.Labels = []string{"waf"} //don't know what to do about this
alert.Leakspeed = ptr.Of("")
msg := fmt.Sprintf("WAF alert: %s", inEvt.Waap.MatchedRules.GetName())
msg := fmt.Sprintf("Application Security Engine alert: %s", inEvt.Waap.MatchedRules.GetName())
alert.Message = &msg
alert.Scenario = ptr.Of(inEvt.Waap.MatchedRules.GetName()) // @sbl : should we be able to do inEvt.Waap.MatchedRules.GetHash()
alert.ScenarioHash = ptr.Of(inEvt.Waap.MatchedRules.GetHash()) // @sbl : should we be able to do inEvt.Waap.MatchedRules.GetHash()
@ -91,18 +91,18 @@ func EventFromRequest(r *waf.ParsedRequest) (types.Event, error) {
evt.Line = types.Line{
Time: time.Now(),
//should we add some info like listen addr/port/path ?
Labels: map[string]string{"type": "crowdsec-waap"},
Labels: map[string]string{"type": "crowdsec-waap"}, //FIXME: use the labels from the acquis
Process: true,
Module: "waap",
Src: "waap",
Module: "appsec",
Src: "appsec",
Raw: "dummy-waap-data", //we discard empty Line.Raw items :)
}
evt.Waap = types.WaapEvent{}
evt.Waap = types.AppsecEvent{}
return evt, nil
}
func LogWaapEvent(evt *types.Event, logger *log.Entry) {
func LogAppsecEvent(evt *types.Event, logger *log.Entry) {
req := evt.Parsed["target_uri"]
if len(req) > 12 {
req = req[:10] + ".."
@ -125,12 +125,12 @@ func LogWaapEvent(evt *types.Event, logger *log.Entry) {
"module": "waf",
"source": evt.Parsed["source_ip"],
"target_uri": req,
}).Debugf("%s triggerd non-blocking rules on %s (%d rules) [%v]", evt.Parsed["source_ip"], req, len(evt.Waap.MatchedRules), evt.Waap.GetRuleIDs())
}).Debugf("%s triggered non-blocking rules on %s (%d rules) [%v]", evt.Parsed["source_ip"], req, len(evt.Waap.MatchedRules), evt.Waap.GetRuleIDs())
}
}
func (r *WaapRunner) AccumulateTxToEvent(evt *types.Event, req *waf.ParsedRequest) error {
func (r *AppsecRunner) AccumulateTxToEvent(evt *types.Event, req *waf.ParsedRequest) error {
if evt == nil {
//an error was already emitted, let's not spam the logs
@ -215,7 +215,7 @@ func (r *WaapRunner) AccumulateTxToEvent(evt *types.Event, req *waf.ParsedReques
r.logger.Debugf("custom rule for event, setting name: %s, version: %s, hash: %s", name, version, hash)
}
WafRuleHits.With(prometheus.Labels{"rule_name": ruleNameProm, "type": kind, "source": req.RemoteAddrNormalized, "waap_engine": req.WaapEngine}).Inc()
AppsecRuleHits.With(prometheus.Labels{"rule_name": ruleNameProm, "type": kind, "source": req.RemoteAddrNormalized, "appsec_engine": req.WaapEngine}).Inc()
corazaRule := map[string]interface{}{
"id": rule.Rule().ID(),

View file

@ -1,54 +0,0 @@
package wafacquisition
import "github.com/prometheus/client_golang/prometheus"
var WafGlobalParsingHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Help: "Time spent processing a request by the WAF.",
Name: "cs_waf_parsing_time_seconds",
Buckets: []float64{0.0005, 0.001, 0.0015, 0.002, 0.0025, 0.003, 0.004, 0.005, 0.0075, 0.01},
},
[]string{"source"},
)
var WafInbandParsingHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Help: "Time spent processing a request by the inband WAF.",
Name: "cs_waf_inband_parsing_time_seconds",
Buckets: []float64{0.0005, 0.001, 0.0015, 0.002, 0.0025, 0.003, 0.004, 0.005, 0.0075, 0.01},
},
[]string{"source"},
)
var WafOutbandParsingHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Help: "Time spent processing a request by the WAF.",
Name: "cs_waf_outband_parsing_time_seconds",
Buckets: []float64{0.0005, 0.001, 0.0015, 0.002, 0.0025, 0.003, 0.004, 0.005, 0.0075, 0.01},
},
[]string{"source"},
)
var WafReqCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "cs_waf_reqs_total",
Help: "Total events processed by the WAF.",
},
[]string{"source", "waap_engine"},
)
var WafBlockCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "cs_waf_block_total",
Help: "Total events blocked by the WAF.",
},
[]string{"source", "waap_engine"},
)
var WafRuleHits = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "cs_waf_rule_hits",
Help: "Count of triggered rule, by rule_name, type (inband/outofband), waap_engine and source",
},
[]string{"rule_name", "type", "waap_engine", "source"},
)

View file

@ -19,7 +19,7 @@ len(evt.Waf.ByTagRx("*CVE*").ByConfidence("high").ByAction("block")) > 1
type MatchedRules []map[string]interface{}
type WaapEvent struct {
type AppsecEvent struct {
HasInBandMatches, HasOutBandMatches bool
MatchedRules
Vars map[string]string
@ -44,7 +44,7 @@ const (
Kind Field = "kind"
)
func (w WaapEvent) GetVar(varName string) string {
func (w AppsecEvent) GetVar(varName string) string {
if w.Vars == nil {
return ""
}

View file

@ -13,7 +13,7 @@ import (
const (
LOG = iota
OVFLW
WAAP
APPSEC
)
// Event is the structure representing a runtime event (log or overflow)
@ -41,7 +41,7 @@ type Event struct {
StrTimeFormat string `yaml:"StrTimeFormat,omitempty" json:"StrTimeFormat,omitempty"`
MarshaledTime string `yaml:"MarshaledTime,omitempty" json:"MarshaledTime,omitempty"`
Process bool `yaml:"Process,omitempty" json:"Process,omitempty"` //can be set to false to avoid processing line
Waap WaapEvent `yaml:"Waap,omitempty" json:"Waap,omitempty"`
Waap AppsecEvent `yaml:"Waap,omitempty" json:"Waap,omitempty"`
/* Meta is the only part that will make it to the API - it should be normalized */
Meta map[string]string `yaml:"Meta,omitempty" json:"Meta,omitempty"`
}