2020-05-22 15:45:08 +00:00
|
|
|
package csconfig
|
2020-05-15 09:49:17 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2021-02-04 16:17:01 +00:00
|
|
|
"os"
|
2020-05-15 09:49:17 +00:00
|
|
|
"path/filepath"
|
2020-11-30 09:37:17 +00:00
|
|
|
"strings"
|
2020-05-15 09:49:17 +00:00
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
"github.com/crowdsecurity/crowdsec/pkg/apiclient"
|
|
|
|
"github.com/pkg/errors"
|
2020-05-15 09:49:17 +00:00
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
)
|
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
/*top-level config : defaults,overriden by cfg file,overriden by cli*/
|
|
|
|
type GlobalConfig struct {
|
|
|
|
//just a path to ourself :p
|
2021-02-09 16:59:35 +00:00
|
|
|
Self *string `yaml:"-"`
|
|
|
|
Common *CommonCfg `yaml:"common,omitempty"`
|
|
|
|
Prometheus *PrometheusCfg `yaml:"prometheus,omitempty"`
|
|
|
|
Crowdsec *CrowdsecServiceCfg `yaml:"crowdsec_service,omitempty"`
|
|
|
|
Cscli *CscliCfg `yaml:"cscli,omitempty"`
|
|
|
|
DbConfig *DatabaseCfg `yaml:"db_config,omitempty"`
|
|
|
|
API *APICfg `yaml:"api,omitempty"`
|
|
|
|
ConfigPaths *ConfigurationPaths `yaml:"config_paths,omitempty"`
|
|
|
|
DisableAPI bool `yaml:"-"`
|
|
|
|
DisableAgent bool `yaml:"-"`
|
2020-07-16 13:59:09 +00:00
|
|
|
}
|
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
func (c *GlobalConfig) Dump() error {
|
|
|
|
out, err := yaml.Marshal(c)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed marshaling config")
|
|
|
|
}
|
|
|
|
fmt.Printf("%s", string(out))
|
|
|
|
return nil
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 16:59:35 +00:00
|
|
|
func (c *GlobalConfig) LoadConfigurationFile(path string, disableAPI bool, disableAgent bool) error {
|
|
|
|
c.DisableAPI = disableAPI
|
|
|
|
c.DisableAgent = disableAgent
|
2020-11-30 09:37:17 +00:00
|
|
|
fcontent, err := ioutil.ReadFile(path)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to read config file")
|
|
|
|
}
|
2021-02-04 16:17:01 +00:00
|
|
|
configData := os.ExpandEnv(string(fcontent))
|
|
|
|
err = yaml.UnmarshalStrict([]byte(configData), c)
|
2020-11-30 09:37:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed unmarshaling config")
|
|
|
|
}
|
|
|
|
path, err = filepath.Abs(path)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to load absolute path")
|
|
|
|
}
|
|
|
|
c.Self = &path
|
|
|
|
if err := c.LoadConfiguration(); err != nil {
|
|
|
|
return errors.Wrap(err, "failed to load sub configurations")
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
|
|
|
|
return nil
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
func (c *GlobalConfig) LoadConfiguration() error {
|
|
|
|
if c.ConfigPaths.ConfigDir == "" {
|
|
|
|
return fmt.Errorf("please provide a configuration directory with the 'config_dir' directive in the 'config_paths' section")
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.ConfigPaths.DataDir == "" {
|
|
|
|
return fmt.Errorf("please provide a data directory with the 'data_dir' directive in the 'config_paths' section")
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.ConfigPaths.HubDir == "" {
|
|
|
|
c.ConfigPaths.HubDir = filepath.Clean(c.ConfigPaths.ConfigDir + "/hub")
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.ConfigPaths.HubIndexFile == "" {
|
|
|
|
c.ConfigPaths.HubIndexFile = filepath.Clean(c.ConfigPaths.HubDir + "/.index.json")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := c.LoadSimulation(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Crowdsec != nil {
|
2021-02-17 12:55:36 +00:00
|
|
|
if c.Crowdsec.AcquisitionFilePath != "" {
|
|
|
|
log.Infof("non-empty acquisition file path %s", c.Crowdsec.AcquisitionFilePath)
|
|
|
|
if _, err := os.Stat(c.Crowdsec.AcquisitionFilePath); err != nil {
|
|
|
|
return errors.Wrapf(err, "while checking acquisition path %s", c.Crowdsec.AcquisitionFilePath)
|
|
|
|
}
|
|
|
|
c.Crowdsec.AcquisitionFiles = append(c.Crowdsec.AcquisitionFiles, c.Crowdsec.AcquisitionFilePath)
|
|
|
|
}
|
|
|
|
if c.Crowdsec.AcquisitionDirPath != "" {
|
|
|
|
files, err := filepath.Glob(c.Crowdsec.AcquisitionDirPath + "/*.yaml")
|
|
|
|
c.Crowdsec.AcquisitionFiles = append(c.Crowdsec.AcquisitionFiles, files...)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "while globing acquis_dir")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if c.Crowdsec.AcquisitionDirPath == "" && c.Crowdsec.AcquisitionFilePath == "" {
|
|
|
|
return fmt.Errorf("no acquisition_path nor acquisition_dir")
|
2020-07-16 13:59:09 +00:00
|
|
|
}
|
2021-02-17 12:55:36 +00:00
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
c.Crowdsec.ConfigDir = c.ConfigPaths.ConfigDir
|
|
|
|
c.Crowdsec.DataDir = c.ConfigPaths.DataDir
|
|
|
|
c.Crowdsec.HubDir = c.ConfigPaths.HubDir
|
|
|
|
c.Crowdsec.HubIndexFile = c.ConfigPaths.HubIndexFile
|
|
|
|
if c.Crowdsec.ParserRoutinesCount <= 0 {
|
|
|
|
c.Crowdsec.ParserRoutinesCount = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Crowdsec.BucketsRoutinesCount <= 0 {
|
|
|
|
c.Crowdsec.BucketsRoutinesCount = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Crowdsec.OutputRoutinesCount <= 0 {
|
|
|
|
c.Crowdsec.OutputRoutinesCount = 1
|
2020-07-16 13:59:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
if err := c.CleanupPaths(); err != nil {
|
|
|
|
return errors.Wrap(err, "invalid config")
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Cscli != nil {
|
|
|
|
c.Cscli.DbConfig = c.DbConfig
|
|
|
|
c.Cscli.ConfigDir = c.ConfigPaths.ConfigDir
|
|
|
|
c.Cscli.DataDir = c.ConfigPaths.DataDir
|
|
|
|
c.Cscli.HubDir = c.ConfigPaths.HubDir
|
|
|
|
c.Cscli.HubIndexFile = c.ConfigPaths.HubIndexFile
|
2021-02-17 12:53:57 +00:00
|
|
|
if c.Cscli.PrometheusUrl == "" {
|
|
|
|
port := 6060
|
|
|
|
if c.Prometheus.ListenPort != 0 {
|
|
|
|
port = c.Prometheus.ListenPort
|
|
|
|
}
|
|
|
|
c.Cscli.PrometheusUrl = fmt.Sprintf("http://127.0.0.1:%d/", port)
|
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
}
|
2020-07-29 14:58:25 +00:00
|
|
|
|
2021-02-09 16:59:35 +00:00
|
|
|
if c.API.Client != nil && c.API.Client.CredentialsFilePath != "" && !c.DisableAgent {
|
2020-11-30 09:37:17 +00:00
|
|
|
fcontent, err := ioutil.ReadFile(c.API.Client.CredentialsFilePath)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, fmt.Sprintf("failed to read api client credential configuration file '%s'", c.API.Client.CredentialsFilePath))
|
|
|
|
}
|
|
|
|
err = yaml.UnmarshalStrict(fcontent, &c.API.Client.Credentials)
|
2020-05-24 16:15:59 +00:00
|
|
|
if err != nil {
|
2020-11-30 09:37:17 +00:00
|
|
|
return errors.Wrap(err, fmt.Sprintf("failed unmarshaling api client credential configuration file '%s'", c.API.Client.CredentialsFilePath))
|
2020-05-24 16:15:59 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
if c.API.Client.Credentials != nil && c.API.Client.Credentials.URL != "" {
|
|
|
|
if !strings.HasSuffix(c.API.Client.Credentials.URL, "/") {
|
|
|
|
c.API.Client.Credentials.URL = c.API.Client.Credentials.URL + "/"
|
|
|
|
}
|
2020-05-24 16:15:59 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
if c.API.Client.InsecureSkipVerify == nil {
|
2021-02-02 13:15:13 +00:00
|
|
|
apiclient.InsecureSkipVerify = false
|
2020-11-30 09:37:17 +00:00
|
|
|
} else {
|
|
|
|
apiclient.InsecureSkipVerify = *c.API.Client.InsecureSkipVerify
|
2020-05-24 16:15:59 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-29 14:58:25 +00:00
|
|
|
|
2021-02-09 16:59:35 +00:00
|
|
|
if c.API.Server != nil && !c.DisableAPI {
|
2020-11-30 09:37:17 +00:00
|
|
|
c.API.Server.DbConfig = c.DbConfig
|
|
|
|
c.API.Server.LogDir = c.Common.LogDir
|
2021-02-11 17:28:01 +00:00
|
|
|
c.API.Server.LogMedia = c.Common.LogMedia
|
2020-11-30 09:37:17 +00:00
|
|
|
if err := c.API.Server.LoadProfiles(); err != nil {
|
|
|
|
return errors.Wrap(err, "while loading profiles for LAPI")
|
|
|
|
}
|
|
|
|
if c.API.Server.OnlineClient != nil && c.API.Server.OnlineClient.CredentialsFilePath != "" {
|
|
|
|
c.API.Server.OnlineClient.Credentials = new(ApiCredentialsCfg)
|
|
|
|
fcontent, err := ioutil.ReadFile(c.API.Server.OnlineClient.CredentialsFilePath)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, fmt.Sprintf("failed to read api server credentials configuration file '%s'", c.API.Server.OnlineClient.CredentialsFilePath))
|
|
|
|
}
|
|
|
|
err = yaml.UnmarshalStrict(fcontent, c.API.Server.OnlineClient.Credentials)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, fmt.Sprintf("failed unmarshaling api server credentials configuration file '%s'", c.API.Server.OnlineClient.CredentialsFilePath))
|
|
|
|
}
|
|
|
|
if c.API.Server.OnlineClient.Credentials == nil {
|
|
|
|
log.Debugf("online credentials not found in '%s', will not use crowdsec api", c.API.Server.OnlineClient.CredentialsFilePath)
|
|
|
|
}
|
|
|
|
}
|
2020-07-16 13:59:09 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
|
2020-05-24 16:15:59 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
func (c *GlobalConfig) LoadSimulation() error {
|
|
|
|
if c.ConfigPaths == nil {
|
|
|
|
return fmt.Errorf("ConfigPaths is empty")
|
|
|
|
}
|
2020-05-15 09:49:17 +00:00
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
simCfg := SimulationConfig{}
|
2020-05-15 09:49:17 +00:00
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
if c.ConfigPaths.SimulationFilePath == "" {
|
|
|
|
c.ConfigPaths.SimulationFilePath = filepath.Clean(c.ConfigPaths.ConfigDir + "/simulation.yaml")
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
rcfg, err := ioutil.ReadFile(c.ConfigPaths.SimulationFilePath)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "while reading '%s'", c.ConfigPaths.SimulationFilePath)
|
|
|
|
} else {
|
|
|
|
if err := yaml.UnmarshalStrict(rcfg, &simCfg); err != nil {
|
|
|
|
return fmt.Errorf("while unmarshaling simulation file '%s' : %s", c.ConfigPaths.SimulationFilePath, err)
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
if simCfg.Simulation == nil {
|
|
|
|
simCfg.Simulation = new(bool)
|
|
|
|
}
|
|
|
|
if c.Crowdsec != nil {
|
|
|
|
c.Crowdsec.SimulationConfig = &simCfg
|
|
|
|
}
|
|
|
|
if c.Cscli != nil {
|
|
|
|
c.Cscli.SimulationConfig = &simCfg
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewConfig() *GlobalConfig {
|
|
|
|
cfg := GlobalConfig{}
|
|
|
|
return &cfg
|
|
|
|
}
|
2020-05-15 09:49:17 +00:00
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
func NewDefaultConfig() *GlobalConfig {
|
|
|
|
logLevel := log.InfoLevel
|
|
|
|
CommonCfg := CommonCfg{
|
|
|
|
Daemonize: false,
|
|
|
|
PidDir: "/tmp/",
|
|
|
|
LogMedia: "stdout",
|
|
|
|
//LogDir unneeded
|
|
|
|
LogLevel: &logLevel,
|
|
|
|
WorkingDir: ".",
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
prometheus := PrometheusCfg{
|
|
|
|
Enabled: true,
|
|
|
|
Level: "full",
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
configPaths := ConfigurationPaths{
|
|
|
|
ConfigDir: "/etc/crowdsec/",
|
|
|
|
DataDir: "/var/lib/crowdsec/data/",
|
|
|
|
SimulationFilePath: "/etc/crowdsec/config/simulation.yaml",
|
|
|
|
HubDir: "/etc/crowdsec/hub",
|
|
|
|
HubIndexFile: "/etc/crowdsec/hub/.index.json",
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
crowdsecCfg := CrowdsecServiceCfg{
|
|
|
|
AcquisitionFilePath: "/etc/crowdsec/config/acquis.yaml",
|
|
|
|
ParserRoutinesCount: 1,
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
|
|
|
|
cscliCfg := CscliCfg{
|
|
|
|
Output: "human",
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
|
|
|
|
apiCfg := APICfg{
|
|
|
|
Client: &LocalApiClientCfg{
|
|
|
|
CredentialsFilePath: "/etc/crowdsec/config/lapi-secrets.yaml",
|
|
|
|
},
|
|
|
|
Server: &LocalApiServerCfg{
|
2021-02-09 18:10:14 +00:00
|
|
|
ListenURI: "127.0.0.1:8080",
|
|
|
|
UseForwardedForHeaders: false,
|
2020-11-30 09:37:17 +00:00
|
|
|
OnlineClient: &OnlineApiClientCfg{
|
|
|
|
CredentialsFilePath: "/etc/crowdsec/config/online-api-secrets.yaml",
|
|
|
|
},
|
|
|
|
},
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
|
|
|
|
dbConfig := DatabaseCfg{
|
|
|
|
Type: "sqlite",
|
|
|
|
DbPath: "/var/lib/crowdsec/data/crowdsec.db",
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
|
|
|
|
globalCfg := GlobalConfig{
|
|
|
|
Common: &CommonCfg,
|
|
|
|
Prometheus: &prometheus,
|
|
|
|
Crowdsec: &crowdsecCfg,
|
|
|
|
Cscli: &cscliCfg,
|
|
|
|
API: &apiCfg,
|
|
|
|
ConfigPaths: &configPaths,
|
|
|
|
DbConfig: &dbConfig,
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
|
|
|
|
return &globalCfg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *GlobalConfig) CleanupPaths() error {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
if c.Common != nil {
|
|
|
|
var CommonCleanup = []*string{
|
|
|
|
&c.Common.PidDir,
|
|
|
|
&c.Common.LogDir,
|
|
|
|
&c.Common.WorkingDir,
|
|
|
|
}
|
|
|
|
for _, k := range CommonCleanup {
|
2021-02-17 12:55:36 +00:00
|
|
|
if *k == "" {
|
|
|
|
continue
|
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
*k, err = filepath.Abs(*k)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to clean path")
|
|
|
|
}
|
|
|
|
}
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
|
|
|
|
if c.Crowdsec != nil {
|
|
|
|
var crowdsecCleanup = []*string{
|
|
|
|
&c.Crowdsec.AcquisitionFilePath,
|
|
|
|
}
|
|
|
|
for _, k := range crowdsecCleanup {
|
2021-02-17 12:55:36 +00:00
|
|
|
if *k == "" {
|
|
|
|
continue
|
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
*k, err = filepath.Abs(*k)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to clean path")
|
|
|
|
}
|
|
|
|
}
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
|
|
|
|
2020-11-30 09:37:17 +00:00
|
|
|
if c.ConfigPaths != nil {
|
|
|
|
var configPathsCleanup = []*string{
|
|
|
|
&c.ConfigPaths.HubDir,
|
|
|
|
&c.ConfigPaths.HubIndexFile,
|
|
|
|
&c.ConfigPaths.ConfigDir,
|
|
|
|
&c.ConfigPaths.DataDir,
|
|
|
|
&c.ConfigPaths.SimulationFilePath,
|
|
|
|
}
|
|
|
|
for _, k := range configPathsCleanup {
|
2021-02-17 12:55:36 +00:00
|
|
|
if *k == "" {
|
|
|
|
continue
|
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
*k, err = filepath.Abs(*k)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed to clean path")
|
|
|
|
}
|
|
|
|
}
|
2020-05-15 09:49:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|