From 9faa49c7e8a25d6977a7f6376902e77fbb05d5dd Mon Sep 17 00:00:00 2001 From: mmetc <92726601+mmetc@users.noreply.github.com> Date: Wed, 8 Mar 2023 22:47:25 +0100 Subject: [PATCH] Load lapi config for `config show output` (#2097) This adds URL and login parameters as it was intended. Also rewrite configShow and displayOneAlert to use an embedded text/template for shorter code. --- cmd/crowdsec-cli/alerts.go | 43 ++++-- cmd/crowdsec-cli/config_show.go | 255 +++++++++++++++++--------------- test/bats/01_cscli.bats | 11 ++ 3 files changed, 175 insertions(+), 134 deletions(-) diff --git a/cmd/crowdsec-cli/alerts.go b/cmd/crowdsec-cli/alerts.go index f617f38bc..0c55e89c6 100644 --- a/cmd/crowdsec-cli/alerts.go +++ b/cmd/crowdsec-cli/alerts.go @@ -10,6 +10,7 @@ import ( "sort" "strconv" "strings" + "text/template" "time" "github.com/fatih/color" @@ -135,25 +136,35 @@ func AlertsToTable(alerts *models.GetAlertsResponse, printMachine bool) error { return nil } +var alertTemplate = ` +################################################################################################ + + - ID : {{.ID}} + - Date : {{.CreatedAt}} + - Machine : {{.MachineID}} + - Simulation : {{.Simulated}} + - Reason : {{.Scenario}} + - Events Count : {{.EventsCount}} + - Scope:Value : {{.Source.Scope}}{{if .Source.Value}}:{{.Source.Value}}{{end}} + - Country : {{.Source.Cn}} + - AS : {{.Source.AsName}} + - Begin : {{.StartAt}} + - End : {{.StopAt}} + - UUID : {{.UUID}} + +` + + func DisplayOneAlert(alert *models.Alert, withDetail bool) error { if csConfig.Cscli.Output == "human" { - fmt.Printf("\n################################################################################################\n\n") - scopeAndValue := *alert.Source.Scope - if *alert.Source.Value != "" { - scopeAndValue += ":" + *alert.Source.Value + tmpl, err := template.New("alert").Parse(alertTemplate) + if err != nil { + return err + } + err = tmpl.Execute(os.Stdout, alert) + if err != nil { + return err } - fmt.Printf(" - ID : %d\n", alert.ID) - fmt.Printf(" - Date : %s\n", alert.CreatedAt) - fmt.Printf(" - Machine : %s\n", alert.MachineID) - fmt.Printf(" - Simulation : %v\n", *alert.Simulated) - fmt.Printf(" - Reason : %s\n", *alert.Scenario) - fmt.Printf(" - Events Count : %d\n", *alert.EventsCount) - fmt.Printf(" - Scope:Value : %s\n", scopeAndValue) - fmt.Printf(" - Country : %s\n", alert.Source.Cn) - fmt.Printf(" - AS : %s\n", alert.Source.AsName) - fmt.Printf(" - Begin : %s\n", *alert.StartAt) - fmt.Printf(" - End : %s\n", *alert.StopAt) - fmt.Printf(" - UUID : %s\n\n", alert.UUID) alertDecisionsTable(color.Output, alert) diff --git a/cmd/crowdsec-cli/config_show.go b/cmd/crowdsec-cli/config_show.go index a5865d4c8..82f56732d 100644 --- a/cmd/crowdsec-cli/config_show.go +++ b/cmd/crowdsec-cli/config_show.go @@ -3,10 +3,13 @@ package main import ( "encoding/json" "fmt" + "os" + "text/template" "github.com/antonmedv/expr" "github.com/spf13/cobra" "gopkg.in/yaml.v2" + log "github.com/sirupsen/logrus" "github.com/crowdsecurity/crowdsec/pkg/csconfig" ) @@ -47,9 +50,137 @@ func showConfigKey(key string) error { return nil } + +var configShowTemplate = `Global: + +{{- if .ConfigPaths }} + - Configuration Folder : {{.ConfigPaths.ConfigDir}} + - Configuration Folder : {{.ConfigPaths.ConfigDir}} + - Data Folder : {{.ConfigPaths.DataDir}} + - Hub Folder : {{.ConfigPaths.HubDir}} + - Simulation File : {{.ConfigPaths.SimulationFilePath}} +{{- end }} + +{{- if .Common }} + - Log Folder : {{.Common.LogDir}} + - Log level : {{.Common.LogLevel}} + - Log Media : {{.Common.LogMedia}} +{{- end }} + +{{- if .Crowdsec }} +Crowdsec: + - Acquisition File : {{.Crowdsec.AcquisitionFilePath}} + - Parsers routines : {{.Crowdsec.ParserRoutinesCount}} +{{- if .Crowdsec.AcquisitionDirPath }} + - Acquisition Folder : {{.Crowdsec.AcquisitionDirPath}} +{{- end }} +{{- end }} + +{{- if .Cscli }} +cscli: + - Output : {{.Cscli.Output}} + - Hub Branch : {{.Cscli.HubBranch}} + - Hub Folder : {{.Cscli.HubDir}} +{{- end }} + +{{- if .API }} +{{- if .API.Client }} +API Client: +{{- if .API.Client.Credentials }} + - URL : {{.API.Client.Credentials.URL}} + - Login : {{.API.Client.Credentials.Login}} +{{- end }} + - Credentials File : {{.API.Client.CredentialsFilePath}} +{{- end }} + +{{- if .API.Server }} +Local API Server: + - Listen URL : {{.API.Server.ListenURI}} + - Profile File : {{.API.Server.ProfilesPath}} + +{{- if .API.Server.TLS }} +{{- if .API.Server.TLS.CertFilePath }} + - Cert File : {{.API.Server.TLS.CertFilePath}} +{{- end }} + +{{- if .API.Server.TLS.KeyFilePath }} + - Key File : {{.API.Server.TLS.KeyFilePath}} +{{- end }} + +{{- if .API.Server.TLS.CACertPath }} + - CA Cert : {{.API.Server.TLS.CACertPath}} +{{- end }} + +{{- if .API.Server.TLS.CRLPath }} + - CRL : {{.API.Server.TLS.CRLPath}} +{{- end }} + +{{- if .API.Server.TLS.CacheExpiration }} + - Cache Expiration : {{.API.Server.TLS.CacheExpiration}} +{{- end }} + +{{- if .API.Server.TLS.ClientVerification }} + - Client Verification : {{.API.Server.TLS.ClientVerification}} +{{- end }} + +{{- if .API.Server.TLS.AllowedAgentsOU }} +{{- range .API.Server.TLS.AllowedAgentsOU }} + - Allowed Agents OU : {{.}} +{{- end }} +{{- end }} + +{{- if .API.Server.TLS.AllowedBouncersOU }} +{{- range .API.Server.TLS.AllowedBouncersOU }} + - Allowed Bouncers OU : {{.}} +{{- end }} +{{- end }} +{{- end }} + + - Trusted IPs: +{{- range .API.Server.TrustedIPs }} + - {{.}} +{{- end }} + +{{- if and .API.Server.OnlineClient .API.Server.OnlineClient.Credentials }} +Central API: + - URL : {{.API.Server.OnlineClient.Credentials.URL}} + - Login : {{.API.Server.OnlineClient.Credentials.Login}} + - Credentials File : {{.API.Server.OnlineClient.CredentialsFilePath}} +{{- end }} +{{- end }} +{{- end }} + +{{- if .DbConfig }} + - Database: + - Type : {{.DbConfig.Type}} +{{- if eq .DbConfig.Type "sqlite" }} + - Path : {{.DbConfig.DbPath}} +{{- else}} + - Host : {{.DbConfig.Host}} + - Port : {{.DbConfig.Port}} + - User : {{.DbConfig.User}} + - DB Name : {{.DbConfig.DbName}} +{{- end }} +{{- if .DbConfig.Flush }} +{{- if .DbConfig.Flush.MaxAge }} + - Flush age : {{.DbConfig.Flush.MaxAge}} +{{- end }} +{{- if .DbConfig.Flush.MaxItems }} + - Flush size : {{.DbConfig.Flush.MaxItems}} +{{- end }} +{{- end }} +{{- end }} +` + + func runConfigShow(cmd *cobra.Command, args []string) error { flags := cmd.Flags() + if err := csConfig.LoadAPIClient(); err != nil { + log.Errorf("failed to load API client configuration: %s", err) + // don't return, we can still show the configuration + } + key, err := flags.GetString("key") if err != nil { return err @@ -61,125 +192,13 @@ func runConfigShow(cmd *cobra.Command, args []string) error { switch csConfig.Cscli.Output { case "human": - fmt.Printf("Global:\n") - - if csConfig.ConfigPaths != nil { - fmt.Printf(" - Configuration Folder : %s\n", csConfig.ConfigPaths.ConfigDir) - fmt.Printf(" - Data Folder : %s\n", csConfig.ConfigPaths.DataDir) - fmt.Printf(" - Hub Folder : %s\n", csConfig.ConfigPaths.HubDir) - fmt.Printf(" - Simulation File : %s\n", csConfig.ConfigPaths.SimulationFilePath) + tmp, err := template.New("config").Parse(configShowTemplate) + if err != nil { + return err } - - if csConfig.Common != nil { - fmt.Printf(" - Log Folder : %s\n", csConfig.Common.LogDir) - fmt.Printf(" - Log level : %s\n", csConfig.Common.LogLevel) - fmt.Printf(" - Log Media : %s\n", csConfig.Common.LogMedia) - } - - if csConfig.Crowdsec != nil { - fmt.Printf("Crowdsec:\n") - fmt.Printf(" - Acquisition File : %s\n", csConfig.Crowdsec.AcquisitionFilePath) - fmt.Printf(" - Parsers routines : %d\n", csConfig.Crowdsec.ParserRoutinesCount) - if csConfig.Crowdsec.AcquisitionDirPath != "" { - fmt.Printf(" - Acquisition Folder : %s\n", csConfig.Crowdsec.AcquisitionDirPath) - } - } - - if csConfig.Cscli != nil { - fmt.Printf("cscli:\n") - fmt.Printf(" - Output : %s\n", csConfig.Cscli.Output) - fmt.Printf(" - Hub Branch : %s\n", csConfig.Cscli.HubBranch) - fmt.Printf(" - Hub Folder : %s\n", csConfig.Cscli.HubDir) - } - - if csConfig.API != nil { - if csConfig.API.Client != nil && csConfig.API.Client.Credentials != nil { - fmt.Printf("API Client:\n") - fmt.Printf(" - URL : %s\n", csConfig.API.Client.Credentials.URL) - fmt.Printf(" - Login : %s\n", csConfig.API.Client.Credentials.Login) - fmt.Printf(" - Credentials File : %s\n", csConfig.API.Client.CredentialsFilePath) - } - - if csConfig.API.Server != nil { - fmt.Printf("Local API Server:\n") - fmt.Printf(" - Listen URL : %s\n", csConfig.API.Server.ListenURI) - fmt.Printf(" - Profile File : %s\n", csConfig.API.Server.ProfilesPath) - - if csConfig.API.Server.TLS != nil { - if csConfig.API.Server.TLS.CertFilePath != "" { - fmt.Printf(" - Cert File : %s\n", csConfig.API.Server.TLS.CertFilePath) - } - - if csConfig.API.Server.TLS.KeyFilePath != "" { - fmt.Printf(" - Key File : %s\n", csConfig.API.Server.TLS.KeyFilePath) - } - - if csConfig.API.Server.TLS.CACertPath != "" { - fmt.Printf(" - CA Cert : %s\n", csConfig.API.Server.TLS.CACertPath) - } - - if csConfig.API.Server.TLS.CRLPath != "" { - fmt.Printf(" - CRL : %s\n", csConfig.API.Server.TLS.CRLPath) - } - - if csConfig.API.Server.TLS.CacheExpiration != nil { - fmt.Printf(" - Cache Expiration : %s\n", csConfig.API.Server.TLS.CacheExpiration) - } - - if csConfig.API.Server.TLS.ClientVerification != "" { - fmt.Printf(" - Client Verification : %s\n", csConfig.API.Server.TLS.ClientVerification) - } - - if csConfig.API.Server.TLS.AllowedAgentsOU != nil { - for _, ou := range csConfig.API.Server.TLS.AllowedAgentsOU { - fmt.Printf(" - Allowed Agents OU : %s\n", ou) - } - } - - if csConfig.API.Server.TLS.AllowedBouncersOU != nil { - for _, ou := range csConfig.API.Server.TLS.AllowedBouncersOU { - fmt.Printf(" - Allowed Bouncers OU : %s\n", ou) - } - } - } - - fmt.Printf(" - Trusted IPs: \n") - - for _, ip := range csConfig.API.Server.TrustedIPs { - fmt.Printf(" - %s\n", ip) - } - - if csConfig.API.Server.OnlineClient != nil && csConfig.API.Server.OnlineClient.Credentials != nil { - fmt.Printf("Central API:\n") - fmt.Printf(" - URL : %s\n", csConfig.API.Server.OnlineClient.Credentials.URL) - fmt.Printf(" - Login : %s\n", csConfig.API.Server.OnlineClient.Credentials.Login) - fmt.Printf(" - Credentials File : %s\n", csConfig.API.Server.OnlineClient.CredentialsFilePath) - } - } - } - - if csConfig.DbConfig != nil { - fmt.Printf(" - Database:\n") - fmt.Printf(" - Type : %s\n", csConfig.DbConfig.Type) - - switch csConfig.DbConfig.Type { - case "sqlite": - fmt.Printf(" - Path : %s\n", csConfig.DbConfig.DbPath) - default: - fmt.Printf(" - Host : %s\n", csConfig.DbConfig.Host) - fmt.Printf(" - Port : %d\n", csConfig.DbConfig.Port) - fmt.Printf(" - User : %s\n", csConfig.DbConfig.User) - fmt.Printf(" - DB Name : %s\n", csConfig.DbConfig.DbName) - } - - if csConfig.DbConfig.Flush != nil { - if *csConfig.DbConfig.Flush.MaxAge != "" { - fmt.Printf(" - Flush age : %s\n", *csConfig.DbConfig.Flush.MaxAge) - } - if *csConfig.DbConfig.Flush.MaxItems != 0 { - fmt.Printf(" - Flush size : %d\n", *csConfig.DbConfig.Flush.MaxItems) - } - } + err = tmp.Execute(os.Stdout, csConfig) + if err != nil { + return err } case "json": data, err := json.MarshalIndent(csConfig, "", " ") diff --git a/test/bats/01_cscli.bats b/test/bats/01_cscli.bats index 8959f425d..a8d1b689f 100644 --- a/test/bats/01_cscli.bats +++ b/test/bats/01_cscli.bats @@ -97,6 +97,17 @@ teardown() { rune -0 cscli config show --key Config.API.Server.ListenURI assert_output "127.0.0.1:8080" + + # check that LAPI configuration is loaded (human and json, not shows in raw) + + rune -0 cscli config show -o human + assert_line --regexp ".*- URL\s+: http://127.0.0.1:8080/" + assert_line --regexp ".*- Login\s+: githubciXXXXXXXXXXXXXXXXXXXXXXXX" + assert_line --regexp ".*- Credentials File\s+: .*/local_api_credentials.yaml" + + rune -0 cscli config show -o json + rune -0 jq -c '.API.Client.Credentials | [.url,.login]' <(output) + assert_output '["http://127.0.0.1:8080/","githubciXXXXXXXXXXXXXXXXXXXXXXXX"]' } @test "cscli config backup / restore" {