Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mm wizard #51

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ linters:


issues:
# “Look, that’s why there’s rules, understand? So that you think before you
# break ‘em.” ― Terry Pratchett

max-issues-per-linter: 0
max-same-issues: 10
exclude-rules:
Expand Down
2 changes: 1 addition & 1 deletion cmd/crowdsec-cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
rootCmd.AddCommand(NewHubTestCmd())
rootCmd.AddCommand(NewNotificationsCmd())
rootCmd.AddCommand(NewSupportCmd())

rootCmd.AddCommand(NewSetupCmd())
if err := rootCmd.Execute(); err != nil {
if bincoverTesting != "" {
log.Debug("coverage report is enabled")
Expand Down
312 changes: 312 additions & 0 deletions cmd/crowdsec-cli/setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
package main

import (
"bytes"
"fmt"
"os"
"os/exec"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
kyaml "sigs.k8s.io/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
}

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(detectConfigFile)
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(detectConfigFile, 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 = kyaml.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
}
Loading