Compare commits

...

1 commit

Author SHA1 Message Date
alteredCoder
6c27e1216c first commit 2021-11-19 18:32:59 +01:00
2 changed files with 280 additions and 0 deletions

View file

@ -176,6 +176,8 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
rootCmd.AddCommand(NewConsoleCmd()) rootCmd.AddCommand(NewConsoleCmd())
rootCmd.AddCommand(NewExplainCmd()) rootCmd.AddCommand(NewExplainCmd())
rootCmd.AddCommand(NewHubTestCmd()) rootCmd.AddCommand(NewHubTestCmd())
rootCmd.AddCommand(NewWizardCmd())
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
log.Fatalf("While executing root command : %s", err) log.Fatalf("While executing root command : %s", err)
} }

278
cmd/crowdsec-cli/wizard.go Normal file
View file

@ -0,0 +1,278 @@
package main
import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
type detect struct {
LogFiles []string `json:"log_files"`
JournalCTL []string `json:"journalctl"`
ServiceName []string `json:"services_name"`
Collections []string `json:"collections"`
Parsers []string `json:"parsers"`
Scenarios []string `json:"scenarios"`
PostOverflows []string `json:"postoverflows"`
Type string `json:"type"`
}
type State struct {
Service string
Collections []string
Parsers []string
Scenarios []string
PostOverflows []string
Type string
LogsPath []string
JournalCTLFilters []string
ServicesName []string // for windows
}
type detectionManager struct {
Filepath string
OS map[string]*detect `json:"os"`
Services map[string]*detect `json:"services"`
State map[string]*State
}
// 1 month ago
var fileOldLimit = time.Now().AddDate(0, -1, 0)
const journalCTlOldLimit = "1 month ago"
const journalctlCmd = "journalctl"
func NewServiceDetect(filepath string) (*detectionManager, error) {
sd := &detectionManager{Filepath: filepath, State: make(map[string]*State)}
jsonFile, err := ioutil.ReadFile(filepath)
if err != nil {
return sd, err
}
err = json.Unmarshal(jsonFile, sd)
return sd, err
}
func isFileOlder(t time.Time, limit time.Time) bool {
return t.Before(limit)
}
func detectService(serviceName string, detection *detect) (*State, bool, error) {
detected := false
state := &State{
Service: serviceName,
Type: detection.Type,
LogsPath: make([]string, 0),
JournalCTLFilters: make([]string, 0),
Collections: detection.Collections,
Parsers: detection.Parsers,
Scenarios: detection.Scenarios,
PostOverflows: detection.PostOverflows,
}
for _, filePath := range detection.LogFiles {
files, err := filepath.Glob(filePath)
if err != nil {
continue
}
if len(files) == 0 {
log.Debugf("No matching files for pattern %s", filePath)
continue
}
// check if at least one file is younger than 1 month
ok := false
for _, file := range files {
fileInfo, err := os.Stat(file)
if err != nil {
continue
}
if isFileOlder(fileInfo.ModTime(), fileOldLimit) {
continue
}
ok = true
break
}
if ok {
detected = true
state.LogsPath = append(state.LogsPath, filePath)
}
}
for _, journalCTLFilter := range detection.JournalCTL {
args := []string{journalCTLFilter, "--since", journalCTlOldLimit}
cmd := exec.CommandContext(context.Background(), journalctlCmd, args...)
stdout, err := cmd.Output()
if err != nil {
log.Errorf("checking journalctl filter '%s' return error: %s", journalCTLFilter, err)
continue
}
scanner := bufio.NewScanner(bytes.NewReader(stdout))
ok := true
for scanner.Scan() {
if strings.Contains(scanner.Text(), "No entries") {
log.Debugf("no entries since '%s' in journalctl '%s' filter, continue", journalCTlOldLimit, journalCTLFilter)
ok = false
break
}
}
if ok {
detected = true
state.JournalCTLFilters = append(state.JournalCTLFilters, journalCTLFilter)
}
}
return state, detected, nil
}
func (d *detectionManager) Detect() error {
var err error
log.Debugf("Detected OS: %s", runtime.GOOS)
err = d.DetectOS(runtime.GOOS)
if err != nil {
return err
}
for serviceName := range d.Services {
err = d.DetectService(serviceName)
if err != nil {
return err
}
}
return nil
}
func (d *detectionManager) Apply(config *csconfig.CrowdsecServiceCfg) error {
for serviceName, service := range d.State {
log.Printf("service: %s|%+v", serviceName, service)
// check if service already configured
dataSourceExist := false
for _, dataSource := range dataSources {
for logFile := range service.LogsPath {
for filenames := range dataSource.
}
}
}
return nil
}
func (d *detectionManager) DetectOS(osName string) error {
var ok bool
var err error
var detectedOS *detect
if detectedOS, ok = d.OS[osName]; !ok {
return fmt.Errorf("os '%s' not supported", osName)
}
state, detected, err := detectService(osName, detectedOS)
if err != nil {
return err
}
if detected {
d.State[osName] = state
}
return nil
}
func (d *detectionManager) Print() {
for serviceName, service := range d.State {
fmt.Printf("%s detected\n", strings.Title(serviceName))
if len(service.LogsPath) > 0 {
fmt.Printf(" * logs files found:\n")
for _, logPath := range service.LogsPath {
fmt.Printf(" - %s\n", logPath)
}
}
if len(service.JournalCTLFilters) > 0 {
fmt.Printf(" * journalctl found:\n")
for _, journalctl := range service.JournalCTLFilters {
fmt.Printf(" - %s\n", journalctl)
}
}
}
}
func (d *detectionManager) DetectService(serviceName string) error {
var ok bool
var err error
var service *detect
if service, ok = d.Services[serviceName]; !ok {
return fmt.Errorf("service '%s' not found or can't be detected", service)
}
state, detected, err := detectService(serviceName, service)
if err != nil {
return err
}
if detected {
d.State[serviceName] = state
}
return nil
}
func NewWizardCmd() *cobra.Command {
var cmdWizard = &cobra.Command{
Use: "wizard [action]",
Short: "Help to configure crowdsec",
Args: cobra.MinimumNArgs(1),
DisableAutoGenTag: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := csConfig.LoadCrowdsec(); err != nil || csConfig.DisableAgent {
log.Fatal("CrowdSec agent is not configured or disabled, can't run the wizard")
}
return nil
},
}
var apply bool
var reconfigure bool
var serviceDetectionFile string
var service string
var cmdWizardDetect = &cobra.Command{
Use: "detect",
Short: "Detect running services, generate acquisitions and install collections",
DisableAutoGenTag: true,
Run: func(cmd *cobra.Command, args []string) {
serviceDetector, err := NewServiceDetect(serviceDetectionFile)
if err != nil {
log.Fatalf("unable to load detection services: %s", err)
}
if err := serviceDetector.Detect(); err != nil {
log.Fatalf("unable to detect services: %s", err)
}
serviceDetector.Print()
if apply {
if err := serviceDetector.Apply(csConfig.Crowdsec); err != nil {
log.Fatalf("unable to apply configuration: %s", err)
}
}
},
}
cmdWizardDetect.Flags().StringVarP(&serviceDetectionFile, "file", "f", "/etc/crowdsec/service_detection.json", "File to detect services")
cmdWizardDetect.Flags().BoolVarP(&apply, "apply", "a", false, "Apply the detection")
cmdWizardDetect.Flags().StringVarP(&service, "service", "s", "", "Service to detect")
cmdWizardDetect.Flags().BoolVarP(&reconfigure, "reconfigure", "r", false, "Reconfigure all the acquisitions/collections")
cmdWizard.AddCommand(cmdWizardDetect)
return cmdWizard
}