check if machine is enrolled in cscli console status
This commit is contained in:
parent
110272484d
commit
c982588bca
5 changed files with 108 additions and 43 deletions
|
@ -1,16 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/apiclient"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwhub"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
@ -126,42 +123,12 @@ func NewCapiCmd() *cobra.Command {
|
|||
log.Fatalf("no credentials for Central API (CAPI) in '%s'", csConfig.API.Server.OnlineClient.CredentialsFilePath)
|
||||
}
|
||||
|
||||
password := strfmt.Password(csConfig.API.Server.OnlineClient.Credentials.Password)
|
||||
apiurl, err := url.Parse(csConfig.API.Server.OnlineClient.Credentials.URL)
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url ('%s'): %s", csConfig.API.Server.OnlineClient.Credentials.URL, err)
|
||||
}
|
||||
|
||||
if err := csConfig.LoadHub(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := cwhub.GetHubIdx(csConfig.Hub); err != nil {
|
||||
log.Info("Run 'sudo cscli hub update' to get the hub index")
|
||||
log.Fatalf("Failed to load hub index : %s", err)
|
||||
}
|
||||
scenarios, err := cwhub.GetInstalledScenariosAsString()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get scenarios : %s", err)
|
||||
}
|
||||
if len(scenarios) == 0 {
|
||||
log.Fatalf("no scenarios installed, abort")
|
||||
}
|
||||
|
||||
Client, err = apiclient.NewDefaultClient(apiurl, CAPIURLPrefix, fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()), nil)
|
||||
if err != nil {
|
||||
log.Fatalf("init default client: %s", err)
|
||||
}
|
||||
t := models.WatcherAuthRequest{
|
||||
MachineID: &csConfig.API.Server.OnlineClient.Credentials.Login,
|
||||
Password: &password,
|
||||
Scenarios: scenarios,
|
||||
}
|
||||
log.Infof("Loaded credentials from %s", csConfig.API.Server.OnlineClient.CredentialsFilePath)
|
||||
log.Infof("Trying to authenticate with username %s on %s", csConfig.API.Server.OnlineClient.Credentials.Login, apiurl)
|
||||
_, err = Client.Auth.AuthenticateWatcher(context.Background(), t)
|
||||
log.Infof("Trying to authenticate with username %s on %s", csConfig.API.Server.OnlineClient.Credentials.Login, csConfig.API.Server.OnlineClient.Credentials.URL)
|
||||
|
||||
_, err = CapiAuth(csConfig.API.Server.OnlineClient)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to authenticate to Central API (CAPI) : %s", err)
|
||||
log.Fatalf("unable to connect to CrowdSec Central API: %s", err)
|
||||
}
|
||||
log.Infof("You can successfully interact with Central API (CAPI)")
|
||||
},
|
||||
|
|
|
@ -17,11 +17,27 @@ import (
|
|||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
"github.com/enescakir/emoji"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func isEnrolled(client *apiclient.ApiClient) bool {
|
||||
apiHTTPClient := client.GetClient()
|
||||
jwtTransport := apiHTTPClient.Transport.(*apiclient.JWTTransport)
|
||||
tokenStr := jwtTransport.Token
|
||||
|
||||
token, _ := jwt.Parse(tokenStr, nil)
|
||||
if token == nil {
|
||||
return false
|
||||
}
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
_, ok := claims["organization_id"]
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func NewConsoleCmd() *cobra.Command {
|
||||
var cmdConsole = &cobra.Command{
|
||||
Use: "console [action]",
|
||||
|
@ -192,6 +208,32 @@ Disable given information push to the central API.`,
|
|||
Example: "status tainted",
|
||||
DisableAutoGenTag: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
if csConfig.API.Server == nil {
|
||||
log.Fatalln("There is no configuration on 'api.server:'")
|
||||
}
|
||||
if csConfig.API.Server.OnlineClient == nil {
|
||||
log.Fatalf("Please provide credentials for the Central API (CAPI) in '%s'", csConfig.API.Server.OnlineClient.CredentialsFilePath)
|
||||
}
|
||||
|
||||
if csConfig.API.Server.OnlineClient.Credentials == nil {
|
||||
log.Fatalf("no credentials for Central API (CAPI) in '%s'", csConfig.API.Server.OnlineClient.CredentialsFilePath)
|
||||
}
|
||||
|
||||
log.Debugf("Loaded credentials from %s", csConfig.API.Server.OnlineClient.CredentialsFilePath)
|
||||
log.Debugf("Trying to authenticate with username %s on %s", csConfig.API.Server.OnlineClient.Credentials.Login, csConfig.API.Server.OnlineClient.Credentials.URL)
|
||||
|
||||
client, err := CapiAuth(csConfig.API.Server.OnlineClient)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to connect to CrowdSec Central API: %s", err)
|
||||
}
|
||||
|
||||
if isEnrolled(client) {
|
||||
fmt.Printf("Machine '%s' is enrolled in the console", csConfig.API.Server.OnlineClient.Credentials.Login)
|
||||
} else {
|
||||
fmt.Printf("Machine '%s' is not enrolled in the console", csConfig.API.Server.OnlineClient.Credentials.Login)
|
||||
}
|
||||
|
||||
switch csConfig.Cscli.Output {
|
||||
case "human":
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
|
|
|
@ -2,17 +2,25 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/apiclient"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwhub"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
"github.com/enescakir/emoji"
|
||||
|
@ -776,3 +784,47 @@ func formatNumber(num int) string {
|
|||
res := math.Round(float64(num)/float64(goodUnit.value)*100) / 100
|
||||
return fmt.Sprintf("%.2f%s", res, goodUnit.symbol)
|
||||
}
|
||||
|
||||
func CapiAuth(capiConfig *csconfig.OnlineApiClientCfg) (*apiclient.ApiClient, error) {
|
||||
var err error
|
||||
var client *apiclient.ApiClient
|
||||
|
||||
password := strfmt.Password(csConfig.API.Server.OnlineClient.Credentials.Password)
|
||||
apiurl, err := url.Parse(csConfig.API.Server.OnlineClient.Credentials.URL)
|
||||
if err != nil {
|
||||
return client, fmt.Errorf("parsing api url ('%s'): %s", csConfig.API.Server.OnlineClient.Credentials.URL, err)
|
||||
}
|
||||
|
||||
if err := csConfig.LoadHub(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := cwhub.GetHubIdx(csConfig.Hub); err != nil {
|
||||
log.Info("Run 'sudo cscli hub update' to get the hub index")
|
||||
return client, fmt.Errorf("Failed to load hub index : %s", err)
|
||||
}
|
||||
scenarios, err := cwhub.GetInstalledScenariosAsString()
|
||||
if err != nil {
|
||||
return client, fmt.Errorf("failed to get scenarios : %s", err)
|
||||
}
|
||||
if len(scenarios) == 0 {
|
||||
return client, fmt.Errorf("no scenarios installed, abort")
|
||||
}
|
||||
|
||||
client, err = apiclient.NewDefaultClient(apiurl, CAPIURLPrefix, fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()), nil)
|
||||
if err != nil {
|
||||
return client, fmt.Errorf("init default client: %s", err)
|
||||
}
|
||||
t := models.WatcherAuthRequest{
|
||||
MachineID: &csConfig.API.Server.OnlineClient.Credentials.Login,
|
||||
Password: &password,
|
||||
Scenarios: scenarios,
|
||||
}
|
||||
|
||||
_, err = client.Auth.AuthenticateWatcher(context.Background(), t)
|
||||
if err != nil {
|
||||
return client, fmt.Errorf("Failed to authenticate to Central API (CAPI) : %s", err)
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ func (t *APIKeyTransport) transport() http.RoundTripper {
|
|||
type JWTTransport struct {
|
||||
MachineID *string
|
||||
Password *strfmt.Password
|
||||
token string
|
||||
Token string
|
||||
Expiration time.Time
|
||||
Scenarios []string
|
||||
URL *url.URL
|
||||
|
@ -161,15 +161,15 @@ func (t *JWTTransport) refreshJwtToken() error {
|
|||
if err := t.Expiration.UnmarshalText([]byte(response.Expire)); err != nil {
|
||||
return errors.Wrap(err, "unable to parse jwt expiration")
|
||||
}
|
||||
t.token = response.Token
|
||||
t.Token = response.Token
|
||||
|
||||
log.Debugf("token %s will expire on %s", t.token, t.Expiration.String())
|
||||
log.Debugf("token %s will expire on %s", t.Token, t.Expiration.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
// RoundTrip implements the RoundTripper interface.
|
||||
func (t *JWTTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if t.token == "" || t.Expiration.Add(-time.Minute).Before(time.Now().UTC()) {
|
||||
if t.Token == "" || t.Expiration.Add(-time.Minute).Before(time.Now().UTC()) {
|
||||
if err := t.refreshJwtToken(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ func (t *JWTTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|||
// that we don't modify the Request we were given. This is required by the
|
||||
// specification of http.RoundTripper.
|
||||
req = cloneRequest(req)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", t.token))
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", t.Token))
|
||||
log.Debugf("req-jwt: %s %s", req.Method, req.URL.String())
|
||||
if log.GetLevel() >= log.TraceLevel {
|
||||
dump, _ := httputil.DumpRequest(req, true)
|
||||
|
@ -196,7 +196,7 @@ func (t *JWTTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|||
}
|
||||
if err != nil || resp.StatusCode == 401 {
|
||||
/*we had an error (network error for example, or 401 because token is refused), reset the token ?*/
|
||||
t.token = ""
|
||||
t.Token = ""
|
||||
return resp, errors.Wrapf(err, "performing jwt auth")
|
||||
}
|
||||
log.Debugf("resp-jwt: %d", resp.StatusCode)
|
||||
|
|
|
@ -38,6 +38,10 @@ type ApiClient struct {
|
|||
HeartBeat *HeartBeatService
|
||||
}
|
||||
|
||||
func (a *ApiClient) GetClient() *http.Client {
|
||||
return a.client
|
||||
}
|
||||
|
||||
type service struct {
|
||||
client *ApiClient
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue