123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- package main
- import (
- "context"
- "encoding/csv"
- "encoding/json"
- "errors"
- "fmt"
- "io/fs"
- "net/url"
- "os"
- "github.com/crowdsecurity/crowdsec/pkg/apiclient"
- "github.com/crowdsecurity/crowdsec/pkg/csconfig"
- "github.com/crowdsecurity/crowdsec/pkg/cwhub"
- "github.com/crowdsecurity/crowdsec/pkg/cwversion"
- "github.com/crowdsecurity/crowdsec/pkg/types"
- "github.com/enescakir/emoji"
- "github.com/go-openapi/strfmt"
- "github.com/olekukonko/tablewriter"
- log "github.com/sirupsen/logrus"
- "github.com/spf13/cobra"
- )
- func NewConsoleCmd() *cobra.Command {
- var cmdConsole = &cobra.Command{
- Use: "console [action]",
- Short: "Manage interaction with Crowdsec console (https://app.crowdsec.net)",
- Args: cobra.MinimumNArgs(1),
- DisableAutoGenTag: true,
- PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
- if err := csConfig.LoadAPIServer(); err != nil || csConfig.DisableAPI {
- var fdErr *fs.PathError
- 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 {
- log.Fatal("Local API is disabled, please run this command on the local API machine")
- }
- if csConfig.API.Server.OnlineClient == nil {
- log.Fatalf("No configuration for Central API (CAPI) in '%s'", *csConfig.FilePath)
- }
- if csConfig.API.Server.OnlineClient.Credentials == nil {
- log.Fatal("You must configure Central API (CAPI) with `cscli capi register` before enrolling your instance")
- }
- return nil
- },
- }
- name := ""
- tags := []string{}
- cmdEnroll := &cobra.Command{
- Use: "enroll [enroll-key]",
- Short: "Enroll this instance to https://app.crowdsec.net [requires local API]",
- Long: `
- Enroll this instance to https://app.crowdsec.net
-
- You can get your enrollment key by creating an account on https://app.crowdsec.net.
- After running this command your will need to validate the enrollment in the webapp.`,
- Example: `cscli console enroll YOUR-ENROLL-KEY
- cscli console enroll --name [instance_name] YOUR-ENROLL-KEY
- cscli console enroll --name [instance_name] --tags [tag_1] --tags [tag_2] YOUR-ENROLL-KEY
- `,
- Args: cobra.ExactArgs(1),
- DisableAutoGenTag: true,
- Run: func(cmd *cobra.Command, args []string) {
- password := strfmt.Password(csConfig.API.Server.OnlineClient.Credentials.Password)
- apiURL, err := url.Parse(csConfig.API.Server.OnlineClient.Credentials.URL)
- if err != nil {
- log.Fatalf("Could not parse CAPI URL : %s", err)
- }
- if err := csConfig.LoadHub(); err != nil {
- log.Fatalf(err.Error())
- }
- if err := cwhub.GetHubIdx(csConfig.Hub); err != nil {
- log.Fatalf("Failed to load hub index : %s", err)
- log.Infoln("Run 'sudo cscli hub update' to get the hub index")
- }
- scenarios, err := cwhub.GetInstalledScenariosAsString()
- if err != nil {
- log.Fatalf("failed to get scenarios : %s", err.Error())
- }
- if len(scenarios) == 0 {
- scenarios = make([]string, 0)
- }
- c, _ := apiclient.NewClient(&apiclient.Config{
- MachineID: csConfig.API.Server.OnlineClient.Credentials.Login,
- Password: password,
- Scenarios: scenarios,
- UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
- URL: apiURL,
- VersionPrefix: "v2",
- })
- _, err = c.Auth.EnrollWatcher(context.Background(), args[0], name, tags)
- if err != nil {
- log.Fatalf("Could not enroll instance: %s", err)
- }
- SetConsoleOpts(csconfig.CONSOLE_CONFIGS, true)
- if err := csConfig.API.Server.DumpConsoleConfig(); err != nil {
- log.Fatalf("failed writing console config : %s", err)
- }
- log.Infof("Enabled tainted&manual alerts sharing, see 'cscli console status'.")
- log.Infof("Watcher successfully enrolled. Visit https://app.crowdsec.net to accept it.")
- log.Infof("Please restart crowdsec after accepting the enrollment.")
- },
- }
- cmdEnroll.Flags().StringVarP(&name, "name", "n", "", "Name to display in the console")
- cmdEnroll.Flags().StringSliceVarP(&tags, "tags", "t", tags, "Tags to display in the console")
- cmdConsole.AddCommand(cmdEnroll)
- var enableAll, disableAll bool
- cmdEnable := &cobra.Command{
- Use: "enable [feature-flag]",
- Short: "Enable a feature flag",
- Example: "enable alerts-tainted",
- Long: `
- Enable given information push to the central API. Allows to empower the console`,
- ValidArgs: csconfig.CONSOLE_CONFIGS,
- DisableAutoGenTag: true,
- Run: func(cmd *cobra.Command, args []string) {
- if enableAll {
- SetConsoleOpts(csconfig.CONSOLE_CONFIGS, true)
- log.Infof("All features have been enabled successfully")
- } else {
- if len(args) == 0 {
- log.Fatalf("You must specify at least one feature to enable")
- }
- SetConsoleOpts(args, true)
- log.Infof("%v have been enabled", args)
- }
- if err := csConfig.API.Server.DumpConsoleConfig(); err != nil {
- log.Fatalf("failed writing console config : %s", err)
- }
- log.Infof(ReloadMessage())
- },
- }
- cmdEnable.Flags().BoolVarP(&enableAll, "all", "a", false, "Enable all feature flags")
- cmdConsole.AddCommand(cmdEnable)
- cmdDisable := &cobra.Command{
- Use: "disable [feature-flag]",
- Short: "Disable a feature flag",
- Example: "disable alerts-tainted",
- Long: `
- Disable given information push to the central API.`,
- ValidArgs: csconfig.CONSOLE_CONFIGS,
- Args: cobra.MinimumNArgs(1),
- DisableAutoGenTag: true,
- Run: func(cmd *cobra.Command, args []string) {
- if disableAll {
- SetConsoleOpts(csconfig.CONSOLE_CONFIGS, false)
- } else {
- SetConsoleOpts(args, false)
- }
- if err := csConfig.API.Server.DumpConsoleConfig(); err != nil {
- log.Fatalf("failed writing console config : %s", err)
- }
- if disableAll {
- log.Infof("All features have been disabled")
- } else {
- log.Infof("%v have been disabled", args)
- }
- log.Infof(ReloadMessage())
- },
- }
- cmdDisable.Flags().BoolVarP(&disableAll, "all", "a", false, "Enable all feature flags")
- cmdConsole.AddCommand(cmdDisable)
- cmdConsoleStatus := &cobra.Command{
- Use: "status [feature-flag]",
- Short: "Shows status of one or all feature flags",
- Example: "status alerts-tainted",
- DisableAutoGenTag: true,
- Run: func(cmd *cobra.Command, args []string) {
- switch csConfig.Cscli.Output {
- case "human":
- table := tablewriter.NewWriter(os.Stdout)
- table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
- table.SetAlignment(tablewriter.ALIGN_LEFT)
- table.SetHeader([]string{"Option Name", "Activated", "Description"})
- for _, option := range csconfig.CONSOLE_CONFIGS {
- switch option {
- case csconfig.SEND_CUSTOM_SCENARIOS:
- activated := string(emoji.CrossMark)
- if *csConfig.API.Server.ConsoleConfig.ShareCustomScenarios {
- activated = string(emoji.CheckMarkButton)
- }
- table.Append([]string{option, activated, "Send alerts from custom scenarios to the console"})
- case csconfig.SEND_MANUAL_SCENARIOS:
- activated := string(emoji.CrossMark)
- if *csConfig.API.Server.ConsoleConfig.ShareManualDecisions {
- activated = string(emoji.CheckMarkButton)
- }
- table.Append([]string{option, activated, "Send manual decisions to the console"})
- case csconfig.SEND_TAINTED_SCENARIOS:
- activated := string(emoji.CrossMark)
- if *csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios {
- activated = string(emoji.CheckMarkButton)
- }
- table.Append([]string{option, activated, "Send alerts from tainted scenarios to the console"})
- case csconfig.SEND_LABEL:
- activated := string(emoji.CrossMark)
- if *csConfig.API.Server.ConsoleConfig.ShareLabel {
- activated = string(emoji.CheckMarkButton)
- }
- table.Append([]string{option, activated, "Send label with alerts to the console"})
- }
- }
- table.Render()
- case "json":
- data, err := json.MarshalIndent(csConfig.API.Server.ConsoleConfig, "", " ")
- if err != nil {
- log.Fatalf("failed to marshal configuration: %s", err)
- }
- fmt.Printf("%s\n", string(data))
- case "raw":
- csvwriter := csv.NewWriter(os.Stdout)
- err := csvwriter.Write([]string{"option", "enabled"})
- if err != nil {
- log.Fatal(err)
- }
- rows := [][]string{
- {"share_manual_decisions", fmt.Sprintf("%t", *csConfig.API.Server.ConsoleConfig.ShareManualDecisions)},
- {"share_custom", fmt.Sprintf("%t", *csConfig.API.Server.ConsoleConfig.ShareCustomScenarios)},
- {"share_tainted", fmt.Sprintf("%t", *csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios)},
- {"share_labels", fmt.Sprintf("%t", *csConfig.API.Server.ConsoleConfig.ShareLabel)},
- }
- for _, row := range rows {
- err = csvwriter.Write(row)
- if err != nil {
- log.Fatal(err)
- }
- }
- csvwriter.Flush()
- }
- },
- }
- cmdConsole.AddCommand(cmdConsoleStatus)
- cmdLabel := &cobra.Command{
- Use: "label [feature-flag]",
- Short: "Manage label to send with alerts",
- DisableAutoGenTag: true,
- Run: func(cmd *cobra.Command, args []string) {
- printHelp(cmd)
- },
- }
- var key string
- var values []string
- cmdLabelAdd := &cobra.Command{
- Use: "add",
- Short: "Add label to send with alerts",
- DisableAutoGenTag: true,
- Run: func(cmd *cobra.Command, args []string) {
- if _, ok := csConfig.API.Server.ConsoleConfig.LabelsToSend[key]; !ok {
- csConfig.API.Server.ConsoleConfig.LabelsToSend[key] = make([]string, 0)
- }
- data := csConfig.API.Server.ConsoleConfig.LabelsToSend[key]
- for _, val := range values {
- if !inSlice(val, data) {
- data = append(data, val)
- }
- csConfig.API.Server.ConsoleConfig.LabelsToSend[key] = data
- }
- if err := csConfig.API.Server.DumpLabelConfigFile(); err != nil {
- log.Fatalf(err.Error())
- }
- },
- }
- cmdLabelAdd.Flags().StringVarP(&key, "key", "k", "", "The key of the different values to send")
- cmdLabelAdd.Flags().StringSliceVar(&values, "value", []string{}, "The expr fields to associate with the key")
- cmdLabelAdd.MarkFlagRequired("key")
- cmdLabelAdd.MarkFlagRequired("value")
- cmdLabel.AddCommand(cmdLabelAdd)
- cmdConsole.AddCommand(cmdLabel)
- return cmdConsole
- }
- func SetConsoleOpts(args []string, wanted bool) {
- for _, arg := range args {
- switch arg {
- case csconfig.SEND_CUSTOM_SCENARIOS:
- /*for each flag check if it's already set before setting it*/
- if csConfig.API.Server.ConsoleConfig.ShareCustomScenarios != nil {
- if *csConfig.API.Server.ConsoleConfig.ShareCustomScenarios == wanted {
- log.Infof("%s already set to %t", csconfig.SEND_CUSTOM_SCENARIOS, wanted)
- } else {
- log.Infof("%s set to %t", csconfig.SEND_CUSTOM_SCENARIOS, wanted)
- *csConfig.API.Server.ConsoleConfig.ShareCustomScenarios = wanted
- }
- } else {
- log.Infof("%s set to %t", csconfig.SEND_CUSTOM_SCENARIOS, wanted)
- csConfig.API.Server.ConsoleConfig.ShareCustomScenarios = types.BoolPtr(wanted)
- }
- case csconfig.SEND_TAINTED_SCENARIOS:
- /*for each flag check if it's already set before setting it*/
- if csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios != nil {
- if *csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios == wanted {
- log.Infof("%s already set to %t", csconfig.SEND_TAINTED_SCENARIOS, wanted)
- } else {
- log.Infof("%s set to %t", csconfig.SEND_TAINTED_SCENARIOS, wanted)
- *csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios = wanted
- }
- } else {
- log.Infof("%s set to %t", csconfig.SEND_TAINTED_SCENARIOS, wanted)
- csConfig.API.Server.ConsoleConfig.ShareTaintedScenarios = types.BoolPtr(wanted)
- }
- case csconfig.SEND_MANUAL_SCENARIOS:
- /*for each flag check if it's already set before setting it*/
- if csConfig.API.Server.ConsoleConfig.ShareManualDecisions != nil {
- if *csConfig.API.Server.ConsoleConfig.ShareManualDecisions == wanted {
- log.Infof("%s already set to %t", csconfig.SEND_MANUAL_SCENARIOS, wanted)
- } else {
- log.Infof("%s set to %t", csconfig.SEND_MANUAL_SCENARIOS, wanted)
- *csConfig.API.Server.ConsoleConfig.ShareManualDecisions = wanted
- }
- } else {
- log.Infof("%s set to %t", csconfig.SEND_MANUAL_SCENARIOS, wanted)
- csConfig.API.Server.ConsoleConfig.ShareManualDecisions = types.BoolPtr(wanted)
- }
- case csconfig.SEND_LABEL:
- /*for each flag check if it's already set before setting it*/
- if csConfig.API.Server.ConsoleConfig.ShareLabel != nil {
- if *csConfig.API.Server.ConsoleConfig.ShareLabel == wanted {
- log.Infof("%s already set to %t", csconfig.SEND_LABEL, wanted)
- } else {
- log.Infof("%s set to %t", csconfig.SEND_LABEL, wanted)
- *csConfig.API.Server.ConsoleConfig.ShareLabel = wanted
- }
- } else {
- log.Infof("%s set to %t", csconfig.SEND_LABEL, wanted)
- csConfig.API.Server.ConsoleConfig.ShareLabel = types.BoolPtr(wanted)
- }
- default:
- log.Fatalf("unknown flag %s", arg)
- }
- }
- }
|