瀏覽代碼

add structure

alteredCoder 3 年之前
父節點
當前提交
03dbce1e50

+ 1 - 0
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:

+ 59 - 33
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 == "" {
+				if *alert.Simulated {
+					log.Debugf("simulation enabled for alert (id:%d), will not be sent to CAPI", alert.ID)
 					continue
 				}
-				/*and we're not interested into tainted scenarios neither*/
+				scenarioTrust := "certified"
+				if alert.ScenarioHash == nil || *alert.ScenarioHash == "" {
+					scenarioTrust = "custom"
+				}
 				if alert.ScenarioVersion == nil || *alert.ScenarioVersion == "" || *alert.ScenarioVersion == "?" {
-					continue
+					scenarioTrust = "tainted"
 				}
-				/*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
+				if len(alert.Decisions) > 0 {
+					if *alert.Decisions[0].Origin == "cscli" {
+						scenarioTrust = "manual"
+					}
 				}
-				signals = append(signals, AlertToSignal(alert))
+				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...)

+ 7 - 6
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
 		}

+ 11 - 8
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 {

+ 5 - 19
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" {

+ 1 - 0
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) {

+ 16 - 31
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 {

+ 0 - 14
pkg/types/console.go

@@ -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
-}

+ 3 - 0
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"