crowdsec/pkg/csconfig/config.go
2021-02-11 18:28:01 +01:00

309 lines
8.7 KiB
Go

package csconfig
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/crowdsecurity/crowdsec/pkg/apiclient"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
)
/*top-level config : defaults,overriden by cfg file,overriden by cli*/
type GlobalConfig struct {
//just a path to ourself :p
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:"-"`
}
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
}
func (c *GlobalConfig) LoadConfigurationFile(path string, disableAPI bool, disableAgent bool) error {
c.DisableAPI = disableAPI
c.DisableAgent = disableAgent
fcontent, err := ioutil.ReadFile(path)
if err != nil {
return errors.Wrap(err, "failed to read config file")
}
configData := os.ExpandEnv(string(fcontent))
err = yaml.UnmarshalStrict([]byte(configData), c)
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")
}
return nil
}
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 {
if c.Crowdsec.AcquisitionFilePath == "" {
c.Crowdsec.AcquisitionFilePath = filepath.Clean(c.ConfigPaths.ConfigDir + "/acquis.yaml")
}
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
}
}
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
}
if c.API.Client != nil && c.API.Client.CredentialsFilePath != "" && !c.DisableAgent {
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)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed unmarshaling api client credential configuration file '%s'", c.API.Client.CredentialsFilePath))
}
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 + "/"
}
}
if c.API.Client.InsecureSkipVerify == nil {
apiclient.InsecureSkipVerify = false
} else {
apiclient.InsecureSkipVerify = *c.API.Client.InsecureSkipVerify
}
}
if c.API.Server != nil && !c.DisableAPI {
c.API.Server.DbConfig = c.DbConfig
c.API.Server.LogDir = c.Common.LogDir
c.API.Server.LogMedia = c.Common.LogMedia
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)
}
}
}
return nil
}
func (c *GlobalConfig) LoadSimulation() error {
if c.ConfigPaths == nil {
return fmt.Errorf("ConfigPaths is empty")
}
simCfg := SimulationConfig{}
if c.ConfigPaths.SimulationFilePath == "" {
c.ConfigPaths.SimulationFilePath = filepath.Clean(c.ConfigPaths.ConfigDir + "/simulation.yaml")
}
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)
}
}
if simCfg.Simulation == nil {
simCfg.Simulation = new(bool)
}
if c.Crowdsec != nil {
c.Crowdsec.SimulationConfig = &simCfg
}
if c.Cscli != nil {
c.Cscli.SimulationConfig = &simCfg
}
return nil
}
func NewConfig() *GlobalConfig {
cfg := GlobalConfig{}
return &cfg
}
func NewDefaultConfig() *GlobalConfig {
logLevel := log.InfoLevel
CommonCfg := CommonCfg{
Daemonize: false,
PidDir: "/tmp/",
LogMedia: "stdout",
//LogDir unneeded
LogLevel: &logLevel,
WorkingDir: ".",
}
prometheus := PrometheusCfg{
Enabled: true,
Level: "full",
}
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",
}
crowdsecCfg := CrowdsecServiceCfg{
AcquisitionFilePath: "/etc/crowdsec/config/acquis.yaml",
ParserRoutinesCount: 1,
}
cscliCfg := CscliCfg{
Output: "human",
}
apiCfg := APICfg{
Client: &LocalApiClientCfg{
CredentialsFilePath: "/etc/crowdsec/config/lapi-secrets.yaml",
},
Server: &LocalApiServerCfg{
ListenURI: "127.0.0.1:8080",
UseForwardedForHeaders: false,
OnlineClient: &OnlineApiClientCfg{
CredentialsFilePath: "/etc/crowdsec/config/online-api-secrets.yaml",
},
},
}
dbConfig := DatabaseCfg{
Type: "sqlite",
DbPath: "/var/lib/crowdsec/data/crowdsec.db",
}
globalCfg := GlobalConfig{
Common: &CommonCfg,
Prometheus: &prometheus,
Crowdsec: &crowdsecCfg,
Cscli: &cscliCfg,
API: &apiCfg,
ConfigPaths: &configPaths,
DbConfig: &dbConfig,
}
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 {
*k, err = filepath.Abs(*k)
if err != nil {
return errors.Wrap(err, "failed to clean path")
}
}
}
if c.Crowdsec != nil {
var crowdsecCleanup = []*string{
&c.Crowdsec.AcquisitionFilePath,
}
for _, k := range crowdsecCleanup {
*k, err = filepath.Abs(*k)
if err != nil {
return errors.Wrap(err, "failed to clean path")
}
}
}
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 {
*k, err = filepath.Abs(*k)
if err != nil {
return errors.Wrap(err, "failed to clean path")
}
}
}
return nil
}