Check cscli preconditions with crowdsec-cli/require package (#2388)

This commit is contained in:
mmetc 2023-07-27 17:02:20 +02:00 committed by GitHub
parent a01ce18b98
commit 5cb7013575
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 260 additions and 105 deletions

View file

@ -25,6 +25,8 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/database" "github.com/crowdsecurity/crowdsec/pkg/database"
"github.com/crowdsecurity/crowdsec/pkg/models" "github.com/crowdsecurity/crowdsec/pkg/models"
"github.com/crowdsecurity/crowdsec/pkg/types" "github.com/crowdsecurity/crowdsec/pkg/types"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
) )
func DecisionsFromAlert(alert *models.Alert) string { func DecisionsFromAlert(alert *models.Alert) string {
@ -525,8 +527,8 @@ func NewAlertsFlushCmd() *cobra.Command {
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
var err error var err error
if err := csConfig.LoadAPIServer(); err != nil || csConfig.DisableAPI { if err := require.LAPI(csConfig); err != nil {
return fmt.Errorf("local API is disabled, please run this command on the local API machine") return err
} }
dbClient, err = database.NewClient(csConfig.DbConfig) dbClient, err = database.NewClient(csConfig.DbConfig)
if err != nil { if err != nil {

View file

@ -16,6 +16,8 @@ import (
middlewares "github.com/crowdsecurity/crowdsec/pkg/apiserver/middlewares/v1" middlewares "github.com/crowdsecurity/crowdsec/pkg/apiserver/middlewares/v1"
"github.com/crowdsecurity/crowdsec/pkg/database" "github.com/crowdsecurity/crowdsec/pkg/database"
"github.com/crowdsecurity/crowdsec/pkg/types" "github.com/crowdsecurity/crowdsec/pkg/types"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
) )
func getBouncers(out io.Writer, dbClient *database.Client) error { func getBouncers(out io.Writer, dbClient *database.Client) error {
@ -200,9 +202,10 @@ Note: This command requires database direct access, so is intended to be run on
DisableAutoGenTag: true, DisableAutoGenTag: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
var err error var err error
if err := csConfig.LoadAPIServer(); err != nil || csConfig.DisableAPI { if err = require.LAPI(csConfig); err != nil {
return fmt.Errorf("local API is disabled, please run this command on the local API machine") return err
} }
dbClient, err = database.NewClient(csConfig.DbConfig) dbClient, err = database.NewClient(csConfig.DbConfig)
if err != nil { if err != nil {
return fmt.Errorf("unable to create new database client: %s", err) return fmt.Errorf("unable to create new database client: %s", err)

View file

@ -19,6 +19,8 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/fflag" "github.com/crowdsecurity/crowdsec/pkg/fflag"
"github.com/crowdsecurity/crowdsec/pkg/models" "github.com/crowdsecurity/crowdsec/pkg/models"
"github.com/crowdsecurity/crowdsec/pkg/types" "github.com/crowdsecurity/crowdsec/pkg/types"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
) )
const CAPIBaseURL string = "https://api.crowdsec.net/" const CAPIBaseURL string = "https://api.crowdsec.net/"
@ -31,14 +33,12 @@ func NewCapiCmd() *cobra.Command {
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
DisableAutoGenTag: true, DisableAutoGenTag: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := csConfig.LoadAPIServer(); err != nil { if err := require.LAPI(csConfig); err != nil {
return fmt.Errorf("local API is disabled, please run this command on the local API machine: %w", err) return err
} }
if csConfig.DisableAPI {
return nil if err := require.CAPI(csConfig); err != nil {
} return err
if csConfig.API.Server.OnlineClient == nil {
log.Fatalf("no configuration for Central API in '%s'", *csConfig.FilePath)
} }
return nil return nil
@ -134,10 +134,6 @@ func NewCapiStatusCmd() *cobra.Command {
Args: cobra.MinimumNArgs(0), Args: cobra.MinimumNArgs(0),
DisableAutoGenTag: true, DisableAutoGenTag: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
var err error
if csConfig.API.Server == nil {
log.Fatal("There is no configuration on 'api.server:'")
}
if csConfig.API.Server.OnlineClient == nil { if csConfig.API.Server.OnlineClient == nil {
log.Fatalf("Please provide credentials for the Central API (CAPI) in '%s'", csConfig.API.Server.OnlineClient.CredentialsFilePath) log.Fatalf("Please provide credentials for the Central API (CAPI) in '%s'", csConfig.API.Server.OnlineClient.CredentialsFilePath)
} }

View file

@ -71,7 +71,7 @@ var configShowTemplate = `Global:
{{- end }} {{- end }}
{{- if .Crowdsec }} {{- if .Crowdsec }}
Crowdsec: Crowdsec{{if and .Crowdsec.Enable (not (ValueBool .Crowdsec.Enable))}} (disabled){{end}}:
- Acquisition File : {{.Crowdsec.AcquisitionFilePath}} - Acquisition File : {{.Crowdsec.AcquisitionFilePath}}
- Parsers routines : {{.Crowdsec.ParserRoutinesCount}} - Parsers routines : {{.Crowdsec.ParserRoutinesCount}}
{{- if .Crowdsec.AcquisitionDirPath }} {{- if .Crowdsec.AcquisitionDirPath }}
@ -97,7 +97,7 @@ API Client:
{{- end }} {{- end }}
{{- if .API.Server }} {{- if .API.Server }}
Local API Server: Local API Server{{if and .API.Server.Enable (not (ValueBool .API.Server.Enable))}} (disabled){{end}}:
- Listen URL : {{.API.Server.ListenURI}} - Listen URL : {{.API.Server.ListenURI}}
- Profile File : {{.API.Server.ProfilesPath}} - Profile File : {{.API.Server.ProfilesPath}}
@ -194,7 +194,15 @@ func runConfigShow(cmd *cobra.Command, args []string) error {
switch csConfig.Cscli.Output { switch csConfig.Cscli.Output {
case "human": case "human":
tmp, err := template.New("config").Parse(configShowTemplate) // The tests on .Enable look funny because the option has a true default which has
// not been set yet (we don't really load the LAPI) and go templates don't dereference
// pointers in boolean tests. Prefix notation is the cherry on top.
funcs := template.FuncMap{
// can't use generics here
"ValueBool": func(b *bool) bool { return b!=nil && *b },
}
tmp, err := template.New("config").Funcs(funcs).Parse(configShowTemplate)
if err != nil { if err != nil {
return err return err
} }

View file

@ -4,9 +4,7 @@ import (
"context" "context"
"encoding/csv" "encoding/csv"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/fs"
"net/url" "net/url"
"os" "os"
@ -24,6 +22,8 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/cwhub" "github.com/crowdsecurity/crowdsec/pkg/cwhub"
"github.com/crowdsecurity/crowdsec/pkg/fflag" "github.com/crowdsecurity/crowdsec/pkg/fflag"
"github.com/crowdsecurity/crowdsec/pkg/types" "github.com/crowdsecurity/crowdsec/pkg/types"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
) )
func NewConsoleCmd() *cobra.Command { func NewConsoleCmd() *cobra.Command {
@ -33,24 +33,14 @@ func NewConsoleCmd() *cobra.Command {
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
DisableAutoGenTag: true, DisableAutoGenTag: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := csConfig.LoadAPIServer(); err != nil || csConfig.DisableAPI { if err := require.LAPI(csConfig); err != nil {
var fdErr *fs.PathError return err
if errors.As(err, &fdErr) {
log.Fatalf("Unable to load Local API : %s", fdErr)
}
if err != nil {
log.Fatalf("Unable to load required Local API Configuration : %s", err)
}
log.Fatal("Local API is disabled, please run this command on the local API machine")
} }
if csConfig.DisableAPI { if err := require.CAPI(csConfig); err != nil {
log.Fatal("Local API is disabled, please run this command on the local API machine") return err
} }
if csConfig.API.Server.OnlineClient == nil { if err := require.Enrolled(csConfig); err != nil {
log.Fatalf("No configuration for Central API (CAPI) in '%s'", *csConfig.FilePath) return err
}
if csConfig.API.Server.OnlineClient.Credentials == nil {
log.Fatal("You must configure Central API (CAPI) with `cscli capi register` before accessing console features.")
} }
return nil return nil
}, },

View file

@ -17,6 +17,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/crowdsecurity/crowdsec/pkg/metabase" "github.com/crowdsecurity/crowdsec/pkg/metabase"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
) )
var ( var (
@ -54,23 +56,23 @@ cscli dashboard start
cscli dashboard stop cscli dashboard stop
cscli dashboard remove cscli dashboard remove
`, `,
PersistentPreRun: func(cmd *cobra.Command, args []string) { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := metabase.TestAvailability(); err != nil { if err := require.LAPI(csConfig); err != nil {
log.Fatalf("%s", err) return err
} }
if err := csConfig.LoadAPIServer(); err != nil || csConfig.DisableAPI { if err := metabase.TestAvailability(); err != nil {
log.Fatal("Local API is disabled, please run this command on the local API machine") return err
} }
metabaseConfigFolderPath := filepath.Join(csConfig.ConfigPaths.ConfigDir, metabaseConfigFolder) metabaseConfigFolderPath := filepath.Join(csConfig.ConfigPaths.ConfigDir, metabaseConfigFolder)
metabaseConfigPath = filepath.Join(metabaseConfigFolderPath, metabaseConfigFile) metabaseConfigPath = filepath.Join(metabaseConfigFolderPath, metabaseConfigFile)
if err := os.MkdirAll(metabaseConfigFolderPath, os.ModePerm); err != nil { if err := os.MkdirAll(metabaseConfigFolderPath, os.ModePerm); err != nil {
log.Fatal(err) return err
} }
if err := csConfig.LoadDBConfig(); err != nil {
log.Errorf("This command requires direct database access (must be run on the local API machine)") if err := require.DB(csConfig); err != nil {
log.Fatal(err) return err
} }
/* /*
@ -84,6 +86,7 @@ cscli dashboard remove
metabaseContainerID = oldContainerID metabaseContainerID = oldContainerID
} }
} }
return nil
}, },
} }

View file

@ -26,6 +26,8 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/database" "github.com/crowdsecurity/crowdsec/pkg/database"
"github.com/crowdsecurity/crowdsec/pkg/database/ent" "github.com/crowdsecurity/crowdsec/pkg/database/ent"
"github.com/crowdsecurity/crowdsec/pkg/types" "github.com/crowdsecurity/crowdsec/pkg/types"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
) )
var ( var (
@ -411,11 +413,8 @@ Note: This command requires database direct access, so is intended to be run on
DisableAutoGenTag: true, DisableAutoGenTag: true,
Aliases: []string{"machine"}, Aliases: []string{"machine"},
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := csConfig.LoadAPIServer(); err != nil || csConfig.DisableAPI { if err := require.LAPI(csConfig); err != nil {
if err != nil { return err
log.Errorf("local api : %s", err)
}
return fmt.Errorf("local API is disabled, please run this command on the local API machine")
} }
return nil return nil

View file

@ -25,6 +25,8 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/csconfig" "github.com/crowdsecurity/crowdsec/pkg/csconfig"
"github.com/crowdsecurity/crowdsec/pkg/csplugin" "github.com/crowdsecurity/crowdsec/pkg/csplugin"
"github.com/crowdsecurity/crowdsec/pkg/csprofiles" "github.com/crowdsecurity/crowdsec/pkg/csprofiles"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
) )
type NotificationsCfg struct { type NotificationsCfg struct {
@ -41,16 +43,18 @@ func NewNotificationsCmd() *cobra.Command {
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
Aliases: []string{"notifications", "notification"}, Aliases: []string{"notifications", "notification"},
DisableAutoGenTag: true, DisableAutoGenTag: true,
PersistentPreRun: func(cmd *cobra.Command, args []string) { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
var ( if err := require.LAPI(csConfig); err != nil {
err error return err
)
if err = csConfig.API.Server.LoadProfiles(); err != nil {
log.Fatal(err)
} }
if csConfig.ConfigPaths.NotificationDir == "" { if err := require.Profiles(csConfig); err != nil {
log.Fatalf("config_paths.notification_dir is not set in crowdsec config") return err
} }
if err := require.Notifications(csConfig); err != nil {
return err
}
return nil
}, },
} }

View file

@ -1,7 +1,6 @@
package main package main
import ( import (
"fmt"
"time" "time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -12,6 +11,8 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/apiserver" "github.com/crowdsecurity/crowdsec/pkg/apiserver"
"github.com/crowdsecurity/crowdsec/pkg/database" "github.com/crowdsecurity/crowdsec/pkg/database"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
) )
func NewPapiCmd() *cobra.Command { func NewPapiCmd() *cobra.Command {
@ -21,14 +22,14 @@ func NewPapiCmd() *cobra.Command {
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
DisableAutoGenTag: true, DisableAutoGenTag: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := csConfig.LoadAPIServer(); err != nil || csConfig.DisableAPI { if err := require.LAPI(csConfig); err != nil {
return fmt.Errorf("Local API is disabled, please run this command on the local API machine: %w", err) return err
} }
if csConfig.API.Server.OnlineClient == nil { if err := require.CAPI(csConfig); err != nil {
log.Fatalf("no configuration for Central API in '%s'", *csConfig.FilePath) return err
} }
if csConfig.API.Server.OnlineClient.Credentials.PapiURL == "" { if err := require.PAPI(csConfig); err != nil {
log.Fatalf("no PAPI URL in configuration") return err
} }
return nil return nil
}, },

View file

@ -0,0 +1,85 @@
package require
import (
"fmt"
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
)
func LAPI(c *csconfig.Config) error {
if err := c.LoadAPIServer(); err != nil {
return fmt.Errorf("failed to load Local API: %w", err)
}
if c.DisableAPI {
return fmt.Errorf("local API is disabled -- this command must be run on the local API machine")
}
return nil
}
func CAPI(c *csconfig.Config) error {
if c.API.Server.OnlineClient == nil {
return fmt.Errorf("no configuration for Central API (CAPI) in '%s'", *c.FilePath)
}
return nil
}
func PAPI(c *csconfig.Config) error {
if err := LAPI(c); err != nil {
return err
}
if err := CAPI(c); err != nil {
return err
}
if c.API.Server.OnlineClient.Credentials.PapiURL == "" {
return fmt.Errorf("no PAPI URL in configuration")
}
return nil
}
func Enrolled(c *csconfig.Config) error {
if err := CAPI(c); err != nil {
return err
}
if c.API.Server.OnlineClient.Credentials == nil {
return fmt.Errorf("the Central API (CAPI) must be configured with 'cscli capi register'")
}
return nil
}
func DB(c *csconfig.Config) error {
if err := c.LoadDBConfig(); err != nil {
return fmt.Errorf("this command requires direct database access (must be run on the local API machine): %w", err)
}
return nil
}
func Profiles(c *csconfig.Config) error {
if err := LAPI(c); err != nil {
return err
}
if err := c.API.Server.LoadProfiles(); err != nil {
return fmt.Errorf("while loading profiles: %w", err)
}
return nil
}
func Notifications(c *csconfig.Config) error {
if err := LAPI(c); err != nil {
return err
}
if c.ConfigPaths.NotificationDir == "" {
return fmt.Errorf("config_paths.notification_dir is not set in crowdsec config")
}
return nil
}

View file

@ -249,13 +249,13 @@ func LoadConfig(configFile string, disableAgent bool, disableAPI bool, quiet boo
return nil, err return nil, err
} }
if !flags.DisableAgent { if !cConfig.DisableAgent {
if err := cConfig.LoadCrowdsec(); err != nil { if err := cConfig.LoadCrowdsec(); err != nil {
return nil, err return nil, err
} }
} }
if !flags.DisableAPI { if !cConfig.DisableAPI {
if err := cConfig.LoadAPIServer(); err != nil { if err := cConfig.LoadAPIServer(); err != nil {
return nil, err return nil, err
} }
@ -290,7 +290,7 @@ func LoadConfig(configFile string, disableAgent bool, disableAPI bool, quiet boo
cConfig.API.Server.OnlineClient = nil cConfig.API.Server.OnlineClient = nil
} }
/*if the api is disabled as well, just read file and exit, don't daemonize*/ /*if the api is disabled as well, just read file and exit, don't daemonize*/
if flags.DisableAPI { if cConfig.DisableAPI {
cConfig.Common.Daemonize = false cConfig.Common.Daemonize = false
} }
log.Infof("single file mode : log_media=%s daemonize=%t", cConfig.Common.LogMedia, cConfig.Common.Daemonize) log.Infof("single file mode : log_media=%s daemonize=%t", cConfig.Common.LogMedia, cConfig.Common.Daemonize)

View file

@ -243,7 +243,7 @@ if istrue "$DISABLE_ONLINE_API"; then
fi fi
# registration to online API for signal push # registration to online API for signal push
if isfalse "$DISABLE_ONLINE_API" ; then if isfalse "$DISABLE_LOCAL_API" && isfalse "$DISABLE_ONLINE_API" ; then
CONFIG_DIR=$(conf_get '.config_paths.config_dir') CONFIG_DIR=$(conf_get '.config_paths.config_dir')
export CONFIG_DIR export CONFIG_DIR
config_exists=$(conf_get '.api.server.online_client | has("credentials_path")') config_exists=$(conf_get '.api.server.online_client | has("credentials_path")')
@ -255,7 +255,7 @@ if isfalse "$DISABLE_ONLINE_API" ; then
fi fi
# Enroll instance if enroll key is provided # Enroll instance if enroll key is provided
if isfalse "$DISABLE_ONLINE_API" && [ "$ENROLL_KEY" != "" ]; then if isfalse "$DISABLE_LOCAL_API" && isfalse "$DISABLE_ONLINE_API" && [ "$ENROLL_KEY" != "" ]; then
enroll_args="" enroll_args=""
if [ "$ENROLL_INSTANCE_NAME" != "" ]; then if [ "$ENROLL_INSTANCE_NAME" != "" ]; then
enroll_args="--name $ENROLL_INSTANCE_NAME" enroll_args="--name $ENROLL_INSTANCE_NAME"
@ -278,8 +278,7 @@ if [ "$GID" != "" ]; then
fi fi
fi fi
# XXX only with LAPI if isfalse "$DISABLE_LOCAL_API" && istrue "$USE_TLS"; then
if istrue "$USE_TLS"; then
agents_allowed_yaml=$(csv2yaml "$AGENTS_ALLOWED_OU") agents_allowed_yaml=$(csv2yaml "$AGENTS_ALLOWED_OU")
export agents_allowed_yaml export agents_allowed_yaml
bouncers_allowed_yaml=$(csv2yaml "$BOUNCERS_ALLOWED_OU") bouncers_allowed_yaml=$(csv2yaml "$BOUNCERS_ALLOWED_OU")
@ -358,7 +357,7 @@ shopt -s nullglob extglob
for BOUNCER in /run/secrets/@(bouncer_key|BOUNCER_KEY)* ; do for BOUNCER in /run/secrets/@(bouncer_key|BOUNCER_KEY)* ; do
KEY=$(cat "${BOUNCER}") KEY=$(cat "${BOUNCER}")
NAME=$(echo "${BOUNCER}" | awk -F "/" '{printf $NF}' | cut -d_ -f2-) NAME=$(echo "${BOUNCER}" | awk -F "/" '{printf $NF}' | cut -d_ -f2-)
if [[ -n $KEY ]] && [[ -n $NAME ]]; then if [[ -n $KEY ]] && [[ -n $NAME ]]; then
register_bouncer "$NAME" "$KEY" register_bouncer "$NAME" "$KEY"
fi fi
done done
@ -369,6 +368,12 @@ shopt -u nullglob extglob
conf_set_if "$CAPI_WHITELISTS_PATH" '.api.server.capi_whitelists_path = strenv(CAPI_WHITELISTS_PATH)' conf_set_if "$CAPI_WHITELISTS_PATH" '.api.server.capi_whitelists_path = strenv(CAPI_WHITELISTS_PATH)'
conf_set_if "$METRICS_PORT" '.prometheus.listen_port=env(METRICS_PORT)' conf_set_if "$METRICS_PORT" '.prometheus.listen_port=env(METRICS_PORT)'
if istrue "$DISABLE_LOCAL_API"; then
conf_set '.api.server.enable=false'
else
conf_set '.api.server.enable=true'
fi
ARGS="" ARGS=""
if [ "$CONFIG_FILE" != "" ]; then if [ "$CONFIG_FILE" != "" ]; then
ARGS="-c $CONFIG_FILE" ARGS="-c $CONFIG_FILE"
@ -390,10 +395,6 @@ if istrue "$DISABLE_AGENT"; then
ARGS="$ARGS -no-cs" ARGS="$ARGS -no-cs"
fi fi
if istrue "$DISABLE_LOCAL_API"; then
ARGS="$ARGS -no-api"
fi
if istrue "$LEVEL_TRACE"; then if istrue "$LEVEL_TRACE"; then
ARGS="$ARGS -trace" ARGS="$ARGS -trace"
fi fi

View file

@ -234,6 +234,21 @@ func (c *Config) LoadAPIServer() error {
return nil return nil
} }
if c.API.Server.Enable == nil {
// if the option is not present, it is enabled by default
c.API.Server.Enable = ptr.Of(true)
}
if !*c.API.Server.Enable {
log.Warning("crowdsec local API is disabled because 'enable' is set to false")
c.DisableAPI = true
return nil
}
if c.DisableAPI {
return nil
}
//inherit log level from common, then api->server //inherit log level from common, then api->server
var logLevel log.Level var logLevel log.Level
if c.API.Server.LogLevel != nil { if c.API.Server.LogLevel != nil {
@ -268,21 +283,6 @@ func (c *Config) LoadAPIServer() error {
log.Infof("loaded capi whitelist from %s: %d IPs, %d CIDRs", c.API.Server.CapiWhitelistsPath, len(c.API.Server.CapiWhitelists.Ips), len(c.API.Server.CapiWhitelists.Cidrs)) log.Infof("loaded capi whitelist from %s: %d IPs, %d CIDRs", c.API.Server.CapiWhitelistsPath, len(c.API.Server.CapiWhitelists.Ips), len(c.API.Server.CapiWhitelists.Cidrs))
} }
if c.API.Server.Enable == nil {
// if the option is not present, it is enabled by default
c.API.Server.Enable = ptr.Of(true)
}
if !*c.API.Server.Enable {
log.Warning("crowdsec local API is disabled because 'enable' is set to false")
c.DisableAPI = true
return nil
}
if c.DisableAPI {
return nil
}
if err := c.LoadCommon(); err != nil { if err := c.LoadCommon(); err != nil {
return fmt.Errorf("loading common configuration: %s", err) return fmt.Errorf("loading common configuration: %s", err)
} }

View file

@ -234,6 +234,7 @@ func TestLoadAPIServer(t *testing.T) {
DisableAPI: false, DisableAPI: false,
}, },
expected: &LocalApiServerCfg{ expected: &LocalApiServerCfg{
Enable: ptr.Of(true),
PapiLogLevel: &logLevel, PapiLogLevel: &logLevel,
}, },
expectedErr: "no database configuration provided", expectedErr: "no database configuration provided",

View file

@ -45,16 +45,23 @@ teardown() {
config_disable_lapi config_disable_lapi
rune -1 cscli capi status rune -1 cscli capi status
assert_stderr --partial "crowdsec local API is disabled" assert_stderr --partial "crowdsec local API is disabled"
assert_stderr --partial "There is no configuration on 'api.server:'" assert_stderr --partial "local API is disabled -- this command must be run on the local API machine"
} }
@test "cscli config show -o human" { @test "no lapi: cscli config show -o human" {
config_disable_lapi config_set '.api.server.enable=false'
rune -0 cscli config show -o human rune -0 cscli config show -o human
assert_output --partial "Global:" assert_output --partial "Global:"
assert_output --partial "Crowdsec:" assert_output --partial "Crowdsec:"
assert_output --partial "cscli:" assert_output --partial "cscli:"
refute_output --partial "Local API Server:" assert_output --partial "Local API Server (disabled):"
config_set 'del(.api.server)'
rune -0 cscli config show -o human
assert_output --partial "Global:"
assert_output --partial "Crowdsec:"
assert_output --partial "cscli:"
refute_output --partial "Local API Server"
} }
@test "cscli config backup" { @test "cscli config backup" {
@ -73,7 +80,7 @@ teardown() {
config_disable_lapi config_disable_lapi
./instance-crowdsec start || true ./instance-crowdsec start || true
rune -1 cscli machines list rune -1 cscli machines list
assert_stderr --partial "local API is disabled, please run this command on the local API machine" assert_stderr --partial "local API is disabled -- this command must be run on the local API machine"
} }
@test "cscli metrics" { @test "cscli metrics" {
@ -85,5 +92,5 @@ teardown() {
assert_output --partial "/v1/watchers/login" assert_output --partial "/v1/watchers/login"
assert_stderr --partial "crowdsec local API is disabled" assert_stderr --partial "crowdsec local API is disabled"
assert_stderr --partial "local API is disabled, please run this command on the local API machine" assert_stderr --partial "local API is disabled -- this command must be run on the local API machine"
} }

View file

@ -40,13 +40,19 @@ teardown() {
} }
@test "no agent: cscli config show" { @test "no agent: cscli config show" {
config_disable_agent config_set '.crowdsec_service.enable=false'
rune -0 cscli config show -o human rune -0 cscli config show -o human
assert_output --partial "Global:" assert_output --partial "Global:"
assert_output --partial "cscli:" assert_output --partial "cscli:"
assert_output --partial "Local API Server:" assert_output --partial "Local API Server:"
assert_output --partial "Crowdsec (disabled):"
refute_output --partial "Crowdsec:" config_set 'del(.crowdsec_service)'
rune -0 cscli config show -o human
assert_output --partial "Global:"
assert_output --partial "cscli:"
assert_output --partial "Local API Server:"
refute_output --partial "Crowdsec"
} }
@test "no agent: cscli config backup" { @test "no agent: cscli config backup" {

View file

@ -60,5 +60,11 @@ setup() {
ONLINE_API_CREDENTIALS_YAML="$(config_get '.api.server.online_client.credentials_path')" ONLINE_API_CREDENTIALS_YAML="$(config_get '.api.server.online_client.credentials_path')"
rm "${ONLINE_API_CREDENTIALS_YAML}" rm "${ONLINE_API_CREDENTIALS_YAML}"
rune -1 cscli capi status rune -1 cscli capi status
assert_stderr --partial "local API is disabled, please run this command on the local API machine: loading online client credentials: failed to read api server credentials configuration file '${ONLINE_API_CREDENTIALS_YAML}': open ${ONLINE_API_CREDENTIALS_YAML}: no such file or directory" assert_stderr --partial "failed to load Local API: loading online client credentials: failed to read api server credentials configuration file '${ONLINE_API_CREDENTIALS_YAML}': open ${ONLINE_API_CREDENTIALS_YAML}: no such file or directory"
}
@test "capi register must be run from lapi" {
config_disable_lapi
rune -1 cscli capi register --schmilblick githubciXXXXXXXXXXXXXXXXXXXXXXXX
assert_stderr --partial "local API is disabled -- this command must be run on the local API machine"
} }

View file

@ -41,7 +41,7 @@ teardown() {
config_disable_capi config_disable_capi
./instance-crowdsec start ./instance-crowdsec start
rune -1 cscli capi status rune -1 cscli capi status
assert_stderr --partial "no configuration for Central API in " assert_stderr --partial "no configuration for Central API (CAPI) in "
} }
@test "no capi: cscli config show" { @test "no capi: cscli config show" {

View file

@ -311,7 +311,7 @@ update-notifier-motd.timer enabled enabled
@test "cscli setup detect (process)" { @test "cscli setup detect (process)" {
# This is harder to mock, because gopsutil requires proc/ to be a mount # This is harder to mock, because gopsutil requires proc/ to be a mount
# point. So we pick a process that exists for sure. # point. So we pick a process that exists for sure.
expected_process=$(basename "$SHELL") expected_process=cscli
cat <<-EOT >"${DETECT_YAML}" cat <<-EOT >"${DETECT_YAML}"
version: 1.0 version: 1.0

View file

@ -0,0 +1,39 @@
#!/usr/bin/env bats
# vim: ft=bats:list:ts=8:sts=4:sw=4:et:ai:si:
set -u
setup_file() {
load "../lib/setup_file.sh"
}
teardown_file() {
load "../lib/teardown_file.sh"
}
setup() {
load "../lib/setup.sh"
load "../lib/bats-file/load.bash"
./instance-data load
./instance-crowdsec start
}
teardown() {
cd "$TEST_DIR" || exit 1
./instance-crowdsec stop
}
#----------
@test "cscli notifications list" {
rune -0 cscli notifications list
assert_output --partial "Name"
assert_output --partial "Type"
assert_output --partial "Profile name"
}
@test "cscli notifications must be run from lapi" {
config_disable_lapi
rune -1 cscli notifications list
assert_stderr --partial "local API is disabled -- this command must be run on the local API machine"
}

View file

@ -67,7 +67,9 @@ config_set() {
export -f config_set export -f config_set
config_disable_agent() { config_disable_agent() {
config_set 'del(.crowdsec_service)' config_set '.crowdsec_service.enable=false'
# this should be equivalent to:
# config_set 'del(.crowdsec_service)'
} }
export -f config_disable_agent export -f config_disable_agent
@ -77,7 +79,9 @@ config_log_stderr() {
export -f config_log_stderr export -f config_log_stderr
config_disable_lapi() { config_disable_lapi() {
config_set 'del(.api.server)' config_set '.api.server.enable=false'
# this should be equivalent to:
# config_set 'del(.api.server)'
} }
export -f config_disable_lapi export -f config_disable_lapi