appsec renaming, part 1
This commit is contained in:
parent
42e1da2507
commit
c3a4066646
12 changed files with 167 additions and 168 deletions
|
@ -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,
|
||||
)
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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{}
|
||||
|
|
|
@ -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)
|
|
@ -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 {
|
54
pkg/acquisition/modules/appsec/metrics.go
Normal file
54
pkg/acquisition/modules/appsec/metrics.go
Normal 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"},
|
||||
)
|
|
@ -1,4 +1,4 @@
|
|||
package wafacquisition
|
||||
package appsecacquisition
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -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(),
|
|
@ -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"},
|
||||
)
|
|
@ -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 ""
|
||||
}
|
|
@ -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"`
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue