add console enroll
command to cscli (#828)
This commit is contained in:
parent
b29730520f
commit
3994aec7fe
|
@ -166,5 +166,6 @@ func NewCapiCmd() *cobra.Command {
|
|||
},
|
||||
}
|
||||
cmdCapi.AddCommand(cmdCapiStatus)
|
||||
|
||||
return cmdCapi
|
||||
}
|
||||
|
|
98
cmd/crowdsec-cli/console.go
Normal file
98
cmd/crowdsec-cli/console.go
Normal file
|
@ -0,0 +1,98 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/apiclient"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwhub"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
"github.com/go-openapi/strfmt"
|
||||
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),
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := csConfig.LoadAPIServer(); err != nil || 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 crowdsec API in '%s'", *csConfig.FilePath)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
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",
|
||||
Args: cobra.ExactArgs(1),
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := csConfig.LoadAPIServer(); err != nil || 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 crowdsec API in '%s'", *csConfig.FilePath)
|
||||
}
|
||||
if csConfig.API.Server.OnlineClient.Credentials == nil {
|
||||
log.Fatal("You must configure CAPI with `cscli capi register` before enrolling your instance")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
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.GetUpstreamInstalledScenariosAsString()
|
||||
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])
|
||||
if err != nil {
|
||||
log.Fatalf("Could not enroll instance: %s", err)
|
||||
}
|
||||
log.Infof("Watcher successfully enrolled. Visit https://app.crowdsec.net to accept it.")
|
||||
},
|
||||
}
|
||||
|
||||
cmdConsole.AddCommand(cmdEnroll)
|
||||
return cmdConsole
|
||||
}
|
|
@ -78,7 +78,9 @@ func initConfig() {
|
|||
}
|
||||
|
||||
var validArgs = []string{
|
||||
"scenarios", "parsers", "collections", "capi", "lapi", "postoverflows", "machines", "metrics", "bouncers", "alerts", "decisions", "simulation", "hub", "dashboard", "config", "completion", "version",
|
||||
"scenarios", "parsers", "collections", "capi", "lapi", "postoverflows", "machines",
|
||||
"metrics", "bouncers", "alerts", "decisions", "simulation", "hub", "dashboard",
|
||||
"config", "completion", "version", "console",
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -148,6 +150,7 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
|
|||
rootCmd.AddCommand(NewCapiCmd())
|
||||
rootCmd.AddCommand(NewLapiCmd())
|
||||
rootCmd.AddCommand(NewCompletionCmd())
|
||||
rootCmd.AddCommand(NewConsoleCmd())
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
log.Fatalf("While executing root command : %s", err)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@ import (
|
|||
|
||||
type AuthService service
|
||||
|
||||
// Don't add it to the models, as they are used with LAPI, but the enroll endpoint is specific to CAPI
|
||||
type enrollRequest struct {
|
||||
EnrollKey string `json:"attachment_key"`
|
||||
}
|
||||
|
||||
func (s *AuthService) UnregisterWatcher(ctx context.Context) (*Response, error) {
|
||||
|
||||
u := fmt.Sprintf("%s/watchers", s.client.URLPrefix)
|
||||
|
@ -55,3 +60,17 @@ func (s *AuthService) AuthenticateWatcher(ctx context.Context, auth models.Watch
|
|||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *AuthService) EnrollWatcher(ctx context.Context, enrollKey string) (*Response, error) {
|
||||
u := fmt.Sprintf("%s/watchers/enroll", s.client.URLPrefix)
|
||||
req, err := s.client.NewRequest("POST", u, &enrollRequest{EnrollKey: enrollKey})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
|
|
@ -179,3 +179,60 @@ func TestWatcherUnregister(t *testing.T) {
|
|||
}
|
||||
log.Printf("->%T", client)
|
||||
}
|
||||
|
||||
func TestWatcherEnroll(t *testing.T) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/watchers/enroll", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
buf := new(bytes.Buffer)
|
||||
_, _ = buf.ReadFrom(r.Body)
|
||||
newStr := buf.String()
|
||||
log.Debugf("body -> %s", newStr)
|
||||
if newStr == `{"attachment_key":"goodkey"}
|
||||
` {
|
||||
log.Print("good key")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `{"statusCode": 200, "message": "OK"}`)
|
||||
} else {
|
||||
log.Print("bad key")
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
fmt.Fprintf(w, `{"message":"the attachment key provided is not valid"}`)
|
||||
}
|
||||
})
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `{"code":200,"expire":"2029-11-30T14:14:24+01:00","token":"toto"}`)
|
||||
})
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
|
||||
mycfg := &Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
Scenarios: []string{"crowdsecurity/test"},
|
||||
}
|
||||
client, err := NewClient(mycfg)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
_, err = client.Auth.EnrollWatcher(context.Background(), "goodkey")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpect auth err: %s", err)
|
||||
}
|
||||
|
||||
_, err = client.Auth.EnrollWatcher(context.Background(), "badkey")
|
||||
assert.Contains(t, err.Error(), "the attachment key provided is not valid")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue