123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- package main
- import (
- "bytes"
- "fmt"
- "os"
- "os/exec"
- log "github.com/sirupsen/logrus"
- "github.com/spf13/cobra"
- "gopkg.in/yaml.v3"
- goccyyaml "github.com/goccy/go-yaml"
- "github.com/crowdsecurity/crowdsec/pkg/csconfig"
- "github.com/crowdsecurity/crowdsec/pkg/setup"
- )
- // NewSetupCmd defines the "cscli setup" command.
- func NewSetupCmd() *cobra.Command {
- cmdSetup := &cobra.Command{
- Use: "setup",
- Short: "Tools to configure crowdsec",
- Long: "Manage hub configuration and service detection",
- Args: cobra.MinimumNArgs(0),
- DisableAutoGenTag: true,
- }
- //
- // cscli setup detect
- //
- {
- cmdSetupDetect := &cobra.Command{
- Use: "detect",
- Short: "detect running services, generate a setup file",
- DisableAutoGenTag: true,
- RunE: runSetupDetect,
- }
- defaultServiceDetect := csconfig.DefaultConfigPath("hub", "detect.yaml")
- flags := cmdSetupDetect.Flags()
- flags.String("detect-config", defaultServiceDetect, "path to service detection configuration")
- flags.Bool("list-supported-services", false, "do not detect; only print supported services")
- flags.StringSlice("force-unit", nil, "force detection of a systemd unit (can be repeated)")
- flags.StringSlice("force-process", nil, "force detection of a running process (can be repeated)")
- flags.StringSlice("skip-service", nil, "ignore a service, don't recommend hub/datasources (can be repeated)")
- flags.String("force-os-family", "", "override OS.Family: one of linux, freebsd, windows or darwin")
- flags.String("force-os-id", "", "override OS.ID=[debian | ubuntu | , redhat...]")
- flags.String("force-os-version", "", "override OS.RawVersion (of OS or Linux distribution)")
- flags.Bool("snub-systemd", false, "don't use systemd, even if available")
- flags.Bool("yaml", false, "output yaml, not json")
- cmdSetup.AddCommand(cmdSetupDetect)
- }
- //
- // cscli setup install-hub
- //
- {
- cmdSetupInstallHub := &cobra.Command{
- Use: "install-hub [setup_file] [flags]",
- Short: "install items from a setup file",
- Args: cobra.ExactArgs(1),
- DisableAutoGenTag: true,
- RunE: runSetupInstallHub,
- }
- flags := cmdSetupInstallHub.Flags()
- flags.Bool("dry-run", false, "don't install anything; print out what would have been")
- cmdSetup.AddCommand(cmdSetupInstallHub)
- }
- //
- // cscli setup datasources
- //
- {
- cmdSetupDataSources := &cobra.Command{
- Use: "datasources [setup_file] [flags]",
- Short: "generate datasource (acquisition) configuration from a setup file",
- Args: cobra.ExactArgs(1),
- DisableAutoGenTag: true,
- RunE: runSetupDataSources,
- }
- flags := cmdSetupDataSources.Flags()
- flags.String("to-dir", "", "write the configuration to a directory, in multiple files")
- cmdSetup.AddCommand(cmdSetupDataSources)
- }
- //
- // cscli setup validate
- //
- {
- cmdSetupValidate := &cobra.Command{
- Use: "validate [setup_file]",
- Short: "validate a setup file",
- Args: cobra.ExactArgs(1),
- DisableAutoGenTag: true,
- RunE: runSetupValidate,
- }
- cmdSetup.AddCommand(cmdSetupValidate)
- }
- return cmdSetup
- }
- func runSetupDetect(cmd *cobra.Command, args []string) error {
- flags := cmd.Flags()
- detectConfigFile, err := flags.GetString("detect-config")
- if err != nil {
- return err
- }
- var detectReader *os.File
- switch detectConfigFile {
- case "-":
- log.Tracef("Reading detection rules from stdin")
- detectReader = os.Stdin
- default:
- log.Tracef("Reading detection rules: %s", detectConfigFile)
- detectReader, err = os.Open(detectConfigFile)
- if err != nil {
- return err
- }
- }
- listSupportedServices, err := flags.GetBool("list-supported-services")
- if err != nil {
- return err
- }
- forcedUnits, err := flags.GetStringSlice("force-unit")
- if err != nil {
- return err
- }
- forcedProcesses, err := flags.GetStringSlice("force-process")
- if err != nil {
- return err
- }
- forcedOSFamily, err := flags.GetString("force-os-family")
- if err != nil {
- return err
- }
- forcedOSID, err := flags.GetString("force-os-id")
- if err != nil {
- return err
- }
- forcedOSVersion, err := flags.GetString("force-os-version")
- if err != nil {
- return err
- }
- skipServices, err := flags.GetStringSlice("skip-service")
- if err != nil {
- return err
- }
- snubSystemd, err := flags.GetBool("snub-systemd")
- if err != nil {
- return err
- }
- if !snubSystemd {
- _, err := exec.LookPath("systemctl")
- if err != nil {
- log.Debug("systemctl not available: snubbing systemd")
- snubSystemd = true
- }
- }
- outYaml, err := flags.GetBool("yaml")
- if err != nil {
- return err
- }
- if forcedOSFamily == "" && forcedOSID != "" {
- log.Debug("force-os-id is set: force-os-family defaults to 'linux'")
- forcedOSFamily = "linux"
- }
- if listSupportedServices {
- supported, err := setup.ListSupported(detectReader)
- if err != nil {
- return err
- }
- for _, svc := range supported {
- fmt.Println(svc)
- }
- return nil
- }
- opts := setup.DetectOptions{
- ForcedUnits: forcedUnits,
- ForcedProcesses: forcedProcesses,
- ForcedOS: setup.ExprOS{
- Family: forcedOSFamily,
- ID: forcedOSID,
- RawVersion: forcedOSVersion,
- },
- SkipServices: skipServices,
- SnubSystemd: snubSystemd,
- }
- hubSetup, err := setup.Detect(detectReader, opts)
- if err != nil {
- return fmt.Errorf("detecting services: %w", err)
- }
- setup, err := setupAsString(hubSetup, outYaml)
- if err != nil {
- return err
- }
- fmt.Println(setup)
- return nil
- }
- func setupAsString(cs setup.Setup, outYaml bool) (string, error) {
- var (
- ret []byte
- err error
- )
- wrap := func(err error) error {
- return fmt.Errorf("while marshaling setup: %w", err)
- }
- indentLevel := 2
- buf := &bytes.Buffer{}
- enc := yaml.NewEncoder(buf)
- enc.SetIndent(indentLevel)
- if err = enc.Encode(cs); err != nil {
- return "", wrap(err)
- }
- if err = enc.Close(); err != nil {
- return "", wrap(err)
- }
- ret = buf.Bytes()
- if !outYaml {
- // take a general approach to output json, so we avoid the
- // double tags in the structures and can use go-yaml features
- // missing from the json package
- ret, err = goccyyaml.YAMLToJSON(ret)
- if err != nil {
- return "", wrap(err)
- }
- }
- return string(ret), nil
- }
- func runSetupDataSources(cmd *cobra.Command, args []string) error {
- flags := cmd.Flags()
- fromFile := args[0]
- toDir, err := flags.GetString("to-dir")
- if err != nil {
- return err
- }
- input, err := os.ReadFile(fromFile)
- if err != nil {
- return fmt.Errorf("while reading setup file: %w", err)
- }
- output, err := setup.DataSources(input, toDir)
- if err != nil {
- return err
- }
- if toDir == "" {
- fmt.Println(output)
- }
- return nil
- }
- func runSetupInstallHub(cmd *cobra.Command, args []string) error {
- flags := cmd.Flags()
- fromFile := args[0]
- dryRun, err := flags.GetBool("dry-run")
- if err != nil {
- return err
- }
- input, err := os.ReadFile(fromFile)
- if err != nil {
- return fmt.Errorf("while reading file %s: %w", fromFile, err)
- }
- if err = setup.InstallHubItems(csConfig, input, dryRun); err != nil {
- return err
- }
- return nil
- }
- func runSetupValidate(cmd *cobra.Command, args []string) error {
- fromFile := args[0]
- input, err := os.ReadFile(fromFile)
- if err != nil {
- return fmt.Errorf("while reading stdin: %w", err)
- }
- if err = setup.Validate(input); err != nil {
- fmt.Printf("%v\n", err)
- return fmt.Errorf("invalid setup file")
- }
- return nil
- }
|