From 03dbce1e50cc91ec7c021418465957df9f5ab396 Mon Sep 17 00:00:00 2001 From: alteredCoder Date: Thu, 7 Oct 2021 11:03:23 +0200 Subject: [PATCH] add structure --- config/config.yaml | 1 + pkg/apiserver/apic.go | 94 ++++++++++++++-------- pkg/apiserver/apiserver.go | 13 +-- pkg/apiserver/controllers/controller.go | 19 +++-- pkg/apiserver/controllers/v1/alerts.go | 24 ++---- pkg/apiserver/controllers/v1/controller.go | 1 + pkg/csconfig/api.go | 47 ++++------- pkg/types/console.go | 14 ---- wizard.sh | 3 + 9 files changed, 104 insertions(+), 112 deletions(-) delete mode 100644 pkg/types/console.go diff --git a/config/config.yaml b/config/config.yaml index d93c8fbaa..afc771638 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -41,6 +41,7 @@ api: log_level: info listen_uri: 127.0.0.1:8080 profiles_path: /etc/crowdsec/profiles.yaml + console_path: /etc/crowdsec/console_config.yaml online_client: # Central API credentials (to push signals and receive bad IPs) credentials_path: /etc/crowdsec/online_api_credentials.yaml # tls: diff --git a/pkg/apiserver/apic.go b/pkg/apiserver/apic.go index dd01e311f..8f73665c1 100644 --- a/pkg/apiserver/apic.go +++ b/pkg/apiserver/apic.go @@ -31,19 +31,21 @@ const ( ) type apic struct { - pullInterval time.Duration - pushInterval time.Duration - metricsInterval time.Duration - dbClient *database.Client - apiClient *apiclient.ApiClient - alertToPush chan []*models.Alert - mu sync.Mutex - pushTomb tomb.Tomb - pullTomb tomb.Tomb - metricsTomb tomb.Tomb - startup bool - credentials *csconfig.ApiCredentialsCfg - scenarioList []string + pullInterval time.Duration + pushInterval time.Duration + metricsInterval time.Duration + dbClient *database.Client + apiClient *apiclient.ApiClient + alertToPush chan []*models.Alert + mu sync.Mutex + pushTomb tomb.Tomb + pullTomb tomb.Tomb + metricsTomb tomb.Tomb + startup bool + credentials *csconfig.ApiCredentialsCfg + scenarioList []string + consoleConfig *csconfig.ConsoleConfig + decisionsToDelete chan models.Decision } func IsInSlice(a string, b []string) bool { @@ -75,7 +77,7 @@ func (a *apic) FetchScenariosListFromDB() ([]string, error) { return scenarios, nil } -func AlertToSignal(alert *models.Alert) *models.AddSignalsRequestItem { +func AlertToSignal(alert *models.Alert, scenarioTrust string, keepDecisions bool) *models.AddSignalsRequestItem { return &models.AddSignalsRequestItem{ Message: alert.Message, Scenario: alert.Scenario, @@ -89,18 +91,20 @@ func AlertToSignal(alert *models.Alert) *models.AddSignalsRequestItem { } } -func NewAPIC(config *csconfig.OnlineApiClientCfg, dbClient *database.Client) (*apic, error) { +func NewAPIC(config *csconfig.OnlineApiClientCfg, dbClient *database.Client, consoleConfig *csconfig.ConsoleConfig) (*apic, error) { var err error ret := &apic{ - alertToPush: make(chan []*models.Alert), - dbClient: dbClient, - mu: sync.Mutex{}, - startup: true, - credentials: config.Credentials, - pullTomb: tomb.Tomb{}, - pushTomb: tomb.Tomb{}, - metricsTomb: tomb.Tomb{}, - scenarioList: make([]string, 0), + alertToPush: make(chan []*models.Alert), + dbClient: dbClient, + mu: sync.Mutex{}, + startup: true, + credentials: config.Credentials, + pullTomb: tomb.Tomb{}, + pushTomb: tomb.Tomb{}, + metricsTomb: tomb.Tomb{}, + scenarioList: make([]string, 0), + decisionsToDelete: make(chan models.Decision), + consoleConfig: consoleConfig, } ret.pullInterval, err = time.ParseDuration(PullInterval) @@ -167,20 +171,42 @@ func (a *apic) Push() error { case alerts := <-a.alertToPush: var signals []*models.AddSignalsRequestItem for _, alert := range alerts { - /*we're only interested into decisions coming from scenarios of the hub*/ - if alert.ScenarioHash == nil || *alert.ScenarioHash == "" { - continue - } - /*and we're not interested into tainted scenarios neither*/ - if alert.ScenarioVersion == nil || *alert.ScenarioVersion == "" || *alert.ScenarioVersion == "?" { - continue - } - /*we also ignore alerts in simulated mode*/ if *alert.Simulated { log.Debugf("simulation enabled for alert (id:%d), will not be sent to CAPI", alert.ID) continue } - signals = append(signals, AlertToSignal(alert)) + scenarioTrust := "certified" + if alert.ScenarioHash == nil || *alert.ScenarioHash == "" { + scenarioTrust = "custom" + } + if alert.ScenarioVersion == nil || *alert.ScenarioVersion == "" || *alert.ScenarioVersion == "?" { + scenarioTrust = "tainted" + } + if len(alert.Decisions) > 0 { + if *alert.Decisions[0].Origin == "cscli" { + scenarioTrust = "manual" + } + } + switch scenarioTrust { + case "manual": + if !*a.consoleConfig.ShareManualDecisions { + log.Debugf("manual decision generated an alert, doesn't send it to CAPI because options is disabled") + continue + } + case "tainted": + if !*a.consoleConfig.ShareTaintedScenarios { + log.Debugf("tainted scenario generated an alert, doesn't send it to CAPI because options is disabled") + continue + } + case "custom": + if !*a.consoleConfig.ShareCustomScenarios { + log.Debugf("custom scenario generated an alert, doesn't send it to CAPI because options is disabled") + continue + } + } + + log.Infof("Add signals for '%s' alert", scenarioTrust) + signals = append(signals, AlertToSignal(alert, scenarioTrust, *a.consoleConfig.ShareDecisions)) } a.mu.Lock() cache = append(cache, signals...) diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 1f5013984..9d183e117 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -166,18 +166,19 @@ func NewServer(config *csconfig.LocalApiServerCfg) (*APIServer, error) { }) router.Use(CustomRecoveryWithWriter()) controller := &controllers.Controller{ - DBClient: dbClient, - Ectx: context.Background(), - Router: router, - Profiles: config.Profiles, - Log: clog, + DBClient: dbClient, + Ectx: context.Background(), + Router: router, + Profiles: config.Profiles, + Log: clog, + ConsoleConfig: config.ConsoleConfig, } var apiClient *apic if config.OnlineClient != nil && config.OnlineClient.Credentials != nil { log.Printf("Loading CAPI pusher") - apiClient, err = NewAPIC(config.OnlineClient, dbClient) + apiClient, err = NewAPIC(config.OnlineClient, dbClient, config.ConsoleConfig) if err != nil { return &APIServer{}, err } diff --git a/pkg/apiserver/controllers/controller.go b/pkg/apiserver/controllers/controller.go index 77c7be40d..638019ec8 100644 --- a/pkg/apiserver/controllers/controller.go +++ b/pkg/apiserver/controllers/controller.go @@ -2,6 +2,8 @@ package controllers import ( "context" + "net/http" + "github.com/alexliesenfeld/health" v1 "github.com/crowdsecurity/crowdsec/pkg/apiserver/controllers/v1" "github.com/crowdsecurity/crowdsec/pkg/csconfig" @@ -10,17 +12,18 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/models" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" - "net/http" ) type Controller struct { - Ectx context.Context - DBClient *database.Client - Router *gin.Engine - Profiles []*csconfig.ProfileCfg - CAPIChan chan []*models.Alert - PluginChannel chan csplugin.ProfileAlert - Log *log.Logger + Ectx context.Context + DBClient *database.Client + Router *gin.Engine + Profiles []*csconfig.ProfileCfg + CAPIChan chan []*models.Alert + PluginChannel chan csplugin.ProfileAlert + Log *log.Logger + ConsoleConfig *csconfig.ConsoleConfig + DeleteDecisionChannel chan models.Decision } func (c *Controller) Init() error { diff --git a/pkg/apiserver/controllers/v1/alerts.go b/pkg/apiserver/controllers/v1/alerts.go index 963b61712..a103952be 100644 --- a/pkg/apiserver/controllers/v1/alerts.go +++ b/pkg/apiserver/controllers/v1/alerts.go @@ -128,34 +128,20 @@ func (c *Controller) CreateAlert(gctx *gin.Context) { for _, alert := range input { alert.MachineID = machineID - if len(alert.Decisions) != 0 { - for pIdx, profile := range c.Profiles { - _, matched, err := csprofiles.EvaluateProfile(profile, alert) - if err != nil { - gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) - return - } - if !matched { - continue - } - c.sendAlertToPluginChannel(alert, uint(pIdx)) - if profile.OnSuccess == "break" { - break - } - } - continue - } - for pIdx, profile := range c.Profiles { profileDecisions, matched, err := csprofiles.EvaluateProfile(profile, alert) if err != nil { gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) return } + if !matched { continue } - alert.Decisions = append(alert.Decisions, profileDecisions...) + + if len(alert.Decisions) == 0 { // non manual decision + alert.Decisions = append(alert.Decisions, profileDecisions...) + } profileAlert := *alert c.sendAlertToPluginChannel(&profileAlert, uint(pIdx)) if profile.OnSuccess == "break" { diff --git a/pkg/apiserver/controllers/v1/controller.go b/pkg/apiserver/controllers/v1/controller.go index f6bbb3ce9..5533f95a0 100644 --- a/pkg/apiserver/controllers/v1/controller.go +++ b/pkg/apiserver/controllers/v1/controller.go @@ -18,6 +18,7 @@ type Controller struct { Profiles []*csconfig.ProfileCfg CAPIChan chan []*models.Alert PluginChannel chan csplugin.ProfileAlert + ConsoleConfig map[string]interface{} } func New(dbClient *database.Client, ctx context.Context, profiles []*csconfig.ProfileCfg, capiChan chan []*models.Alert, pluginChannel chan csplugin.ProfileAlert) (*Controller, error) { diff --git a/pkg/csconfig/api.go b/pkg/csconfig/api.go index 7dde7be65..9b7c0bceb 100644 --- a/pkg/csconfig/api.go +++ b/pkg/csconfig/api.go @@ -3,7 +3,6 @@ package csconfig import ( "fmt" "io/ioutil" - "os" "strings" "github.com/crowdsecurity/crowdsec/pkg/apiclient" @@ -79,18 +78,18 @@ func (l *LocalApiClientCfg) Load() error { /*local api service configuration*/ type LocalApiServerCfg struct { - ListenURI string `yaml:"listen_uri,omitempty"` //127.0.0.1:8080 - TLS *TLSCfg `yaml:"tls"` - DbConfig *DatabaseCfg `yaml:"-"` - LogDir string `yaml:"-"` - LogMedia string `yaml:"-"` - OnlineClient *OnlineApiClientCfg `yaml:"online_client"` - ProfilesPath string `yaml:"profiles_path,omitempty"` - ConsoleConfigPath string `yaml:"console_path,omitempty"` - Profiles []*ProfileCfg `yaml:"-"` - LogLevel *log.Level `yaml:"log_level"` - UseForwardedForHeaders bool `yaml:"use_forwarded_for_headers,omitempty"` - ConsoleConfig map[string]interface{} `yaml:"-"` + ListenURI string `yaml:"listen_uri,omitempty"` //127.0.0.1:8080 + TLS *TLSCfg `yaml:"tls"` + DbConfig *DatabaseCfg `yaml:"-"` + LogDir string `yaml:"-"` + LogMedia string `yaml:"-"` + OnlineClient *OnlineApiClientCfg `yaml:"online_client"` + ProfilesPath string `yaml:"profiles_path,omitempty"` + ConsoleConfigPath string `yaml:"console_path,omitempty"` + Profiles []*ProfileCfg `yaml:"-"` + LogLevel *log.Level `yaml:"log_level"` + UseForwardedForHeaders bool `yaml:"use_forwarded_for_headers,omitempty"` + ConsoleConfig *ConsoleConfig `yaml:"-"` } type TLSCfg struct { @@ -109,6 +108,10 @@ func (c *Config) LoadAPIServer() error { return errors.Wrap(err, "while loading profiles for LAPI") } + if err := c.API.Server.LoadConsoleConfig(); err != nil { + return errors.Wrap(err, "while loading console options") + } + if c.API.Server.OnlineClient != nil && c.API.Server.OnlineClient.CredentialsFilePath != "" { if err := c.API.Server.OnlineClient.Load(); err != nil { return errors.Wrap(err, "loading online client credentials") @@ -128,24 +131,6 @@ func (c *Config) LoadAPIServer() error { return nil } -func (c *LocalApiServerCfg) LoadConsoleConfig() error { - c.ConsoleConfig = make(map[string]interface{}) - if _, err := os.Stat(c.ConsoleConfigPath); err != nil && os.IsNotExist(err) { - return nil - } - - yamlFile, err := ioutil.ReadFile(c.ConsoleConfigPath) - if err != nil { - return fmt.Errorf("reading console config file '%s': %s", c.ConsoleConfigPath, err) - } - err = yaml.Unmarshal(yamlFile, c.ConsoleConfig) - if err != nil { - return fmt.Errorf("unmarshaling console config file '%s': %s", c.ConsoleConfigPath, err) - } - - return nil -} - func (c *Config) LoadAPIClient() error { if c.API != nil && c.API.Client != nil && c.API.Client.CredentialsFilePath != "" && !c.DisableAgent { if err := c.API.Client.Load(); err != nil { diff --git a/pkg/types/console.go b/pkg/types/console.go deleted file mode 100644 index 82a472fce..000000000 --- a/pkg/types/console.go +++ /dev/null @@ -1,14 +0,0 @@ -package types - -const ( - SEND_CUSTOM_SCENARIOS = "custom" - SEND_TAINTED_SCENARIOS = "tainted" - SEND_MANUAL_SCENARIOS = "manual" - SEND_LIVE_DECISIONS = "live_decisions" -) - -var CONSOLE_CONFIGS = []string{SEND_CUSTOM_SCENARIOS, SEND_LIVE_DECISIONS, SEND_MANUAL_SCENARIOS, SEND_TAINTED_SCENARIOS} - -type ConsoleConfig struct { - ActivatedSharing []string -} diff --git a/wizard.sh b/wizard.sh index cb15e0792..9fb6ea23d 100755 --- a/wizard.sh +++ b/wizard.sh @@ -31,6 +31,8 @@ CSCLI_BIN="./cmd/crowdsec-cli/cscli" CLIENT_SECRETS="local_api_credentials.yaml" LAPI_SECRETS="online_api_credentials.yaml" +CONSOLE_FILE="console_config.yaml" + BIN_INSTALL_PATH="/usr/local/bin" CROWDSEC_BIN_INSTALLED="${BIN_INSTALL_PATH}/crowdsec" @@ -405,6 +407,7 @@ install_crowdsec() { install -v -m 644 -D ./config/acquis.yaml "${CROWDSEC_CONFIG_PATH}" 1> /dev/null || exit install -v -m 644 -D ./config/profiles.yaml "${CROWDSEC_CONFIG_PATH}" 1> /dev/null || exit install -v -m 644 -D ./config/simulation.yaml "${CROWDSEC_CONFIG_PATH}" 1> /dev/null || exit + install -v -m 644 -D ./config/"${CONSOLE_FILE}" "${CROWDSEC_CONFIG_PATH}" 1> /dev/null || exit mkdir -p ${PID_DIR} || exit PID=${PID_DIR} DATA=${CROWDSEC_DATA_DIR} CFG=${CROWDSEC_CONFIG_PATH} envsubst '$CFG $PID $DATA' < ./config/user.yaml > ${CROWDSEC_CONFIG_PATH}"/user.yaml" || log_fatal "unable to generate user configuration file"