api.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "math/rand"
  6. "path"
  7. "strings"
  8. "time"
  9. "github.com/crowdsecurity/crowdsec/pkg/cwhub"
  10. "github.com/crowdsecurity/crowdsec/pkg/outputs"
  11. "github.com/crowdsecurity/crowdsec/pkg/sqlite"
  12. "github.com/crowdsecurity/crowdsec/pkg/types"
  13. "github.com/denisbrodbeck/machineid"
  14. log "github.com/sirupsen/logrus"
  15. "github.com/spf13/cobra"
  16. "gopkg.in/yaml.v2"
  17. )
  18. var (
  19. passwordLength = 64
  20. upper = "ABCDEFGHIJKLMNOPQRSTUVWXY"
  21. lower = "abcdefghijklmnopqrstuvwxyz"
  22. digits = "0123456789"
  23. )
  24. var (
  25. apiConfigFile = "api.yaml"
  26. )
  27. var userID string // for flag parsing
  28. var dbctx *sqlite.Context
  29. var outputCTX *outputs.Output
  30. func dumpCredentials() error {
  31. if config.output == "json" {
  32. credsYaml, err := json.Marshal(&outputCTX.API.Creds)
  33. if err != nil {
  34. log.Fatalf("Can't marshal credentials : %v", err)
  35. }
  36. fmt.Printf("%s\n", string(credsYaml))
  37. } else {
  38. credsYaml, err := yaml.Marshal(&outputCTX.API.Creds)
  39. if err != nil {
  40. log.Fatalf("Can't marshal credentials : %v", err)
  41. }
  42. fmt.Printf("%s\n", string(credsYaml))
  43. }
  44. return nil
  45. }
  46. func generatePassword() string {
  47. rand.Seed(time.Now().UnixNano())
  48. charset := upper + lower + digits
  49. buf := make([]byte, passwordLength)
  50. buf[0] = digits[rand.Intn(len(digits))]
  51. buf[1] = upper[rand.Intn(len(upper))]
  52. buf[2] = lower[rand.Intn(len(lower))]
  53. for i := 3; i < passwordLength; i++ {
  54. buf[i] = charset[rand.Intn(len(charset))]
  55. }
  56. rand.Shuffle(len(buf), func(i, j int) {
  57. buf[i], buf[j] = buf[j], buf[i]
  58. })
  59. return string(buf)
  60. }
  61. func pullTOP() error {
  62. /*profile from cwhub*/
  63. var profiles []string
  64. if _, ok := cwhub.HubIdx[cwhub.SCENARIOS]; !ok || len(cwhub.HubIdx[cwhub.SCENARIOS]) == 0 {
  65. log.Errorf("no loaded scenarios, can't fill profiles")
  66. return fmt.Errorf("no profiles")
  67. }
  68. for _, item := range cwhub.HubIdx[cwhub.SCENARIOS] {
  69. if item.Tainted || !item.Installed {
  70. continue
  71. }
  72. profiles = append(profiles, item.Name)
  73. }
  74. outputCTX.API.Creds.Profile = strings.Join(profiles[:], ",")
  75. if err := outputCTX.API.Signin(); err != nil {
  76. log.Fatalf(err.Error())
  77. }
  78. ret, err := outputCTX.API.PullTop()
  79. if err != nil {
  80. log.Fatalf(err.Error())
  81. }
  82. log.Warningf("api pull returned %d entries", len(ret))
  83. for _, item := range ret {
  84. if _, ok := item["range_ip"]; !ok {
  85. continue
  86. }
  87. if _, ok := item["scenario"]; !ok {
  88. continue
  89. }
  90. item["scenario"] = fmt.Sprintf("api: %s", item["scenario"])
  91. if _, ok := item["action"]; !ok {
  92. continue
  93. }
  94. if _, ok := item["expiration"]; !ok {
  95. continue
  96. }
  97. if _, ok := item["country"]; !ok {
  98. item["country"] = ""
  99. }
  100. if _, ok := item["as_org"]; !ok {
  101. item["as_org"] = ""
  102. }
  103. if _, ok := item["as_num"]; !ok {
  104. item["as_num"] = ""
  105. }
  106. var signalOcc types.SignalOccurence
  107. signalOcc, err = simpleBanToSignal(item["range_ip"], item["scenario"], item["expiration"], item["action"], item["as_name"], item["as_num"], item["country"], "api")
  108. if err != nil {
  109. return fmt.Errorf("failed to convert ban to signal : %s", err)
  110. }
  111. if err := outputCTX.Insert(signalOcc); err != nil {
  112. log.Fatalf("Unable to write pull to sqliteDB : %+s", err.Error())
  113. }
  114. }
  115. outputCTX.Flush()
  116. log.Infof("Wrote %d bans from api to database.", len(ret))
  117. return nil
  118. }
  119. func NewAPICmd() *cobra.Command {
  120. var cmdAPI = &cobra.Command{
  121. Use: "api [action]",
  122. Short: "Crowdsec API interaction",
  123. Long: `
  124. Allow to register your machine into crowdsec API to send and receive signal.
  125. `,
  126. Example: `
  127. cscli api register # Register to Crowdsec API
  128. cscli api pull # Pull malevolant IPs from Crowdsec API
  129. cscli api reset # Reset your machines credentials
  130. cscli api enroll # Enroll your machine to the user account you created on Crowdsec backend
  131. cscli api credentials # Display your API credentials
  132. `,
  133. Args: cobra.MinimumNArgs(1),
  134. PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
  135. var err error
  136. if !config.configured {
  137. return fmt.Errorf("you must configure cli before interacting with hub")
  138. }
  139. outputConfig := outputs.OutputFactory{
  140. BackendFolder: config.BackendPluginFolder,
  141. }
  142. outputCTX, err = outputs.NewOutput(&outputConfig, false)
  143. if err != nil {
  144. return err
  145. }
  146. err = outputCTX.LoadAPIConfig(path.Join(config.InstallFolder, apiConfigFile))
  147. if err != nil {
  148. return err
  149. }
  150. return nil
  151. },
  152. }
  153. var cmdAPIRegister = &cobra.Command{
  154. Use: "register",
  155. Short: "Register on Crowdsec API",
  156. Long: `This command will register your machine to crowdsec API to allow you to receive list of malveolent IPs.
  157. The printed machine_id and password should be added to your api.yaml file.`,
  158. Example: `cscli api register`,
  159. Args: cobra.MinimumNArgs(0),
  160. Run: func(cmd *cobra.Command, args []string) {
  161. id, err := machineid.ID()
  162. if err != nil {
  163. log.Fatalf("failed to get machine id: %s", err)
  164. }
  165. password := generatePassword()
  166. if err := outputCTX.API.RegisterMachine(id, password); err != nil {
  167. log.Fatalf(err.Error())
  168. }
  169. fmt.Printf("machine_id: %s\n", outputCTX.API.Creds.User)
  170. fmt.Printf("password: %s\n", outputCTX.API.Creds.Password)
  171. return
  172. },
  173. }
  174. var cmdAPIEnroll = &cobra.Command{
  175. Use: "enroll",
  176. Short: "Associate your machine to an existing crowdsec user",
  177. Long: `Enrolling your machine into your user account will allow for more accurate lists and threat detection. See website to create user account.`,
  178. Example: `cscli api enroll -u 1234567890ffff`,
  179. Args: cobra.MinimumNArgs(0),
  180. Run: func(cmd *cobra.Command, args []string) {
  181. if err := outputCTX.API.Signin(); err != nil {
  182. log.Fatalf("unable to signin : %s", err)
  183. }
  184. if err := outputCTX.API.Enroll(userID); err != nil {
  185. log.Fatalf(err.Error())
  186. }
  187. return
  188. },
  189. }
  190. var cmdAPIResetPassword = &cobra.Command{
  191. Use: "reset",
  192. Short: "Reset password on CrowdSec API",
  193. Long: `Attempts to reset your credentials to the API.`,
  194. Example: `cscli api reset`,
  195. Args: cobra.MinimumNArgs(0),
  196. Run: func(cmd *cobra.Command, args []string) {
  197. id, err := machineid.ID()
  198. if err != nil {
  199. log.Fatalf("failed to get machine id: %s", err)
  200. }
  201. password := generatePassword()
  202. if err := outputCTX.API.ResetPassword(id, password); err != nil {
  203. log.Fatalf(err.Error())
  204. }
  205. fmt.Printf("machine_id: %s\n", outputCTX.API.Creds.User)
  206. fmt.Printf("password: %s\n", outputCTX.API.Creds.Password)
  207. return
  208. },
  209. }
  210. var cmdAPIPull = &cobra.Command{
  211. Use: "pull",
  212. Short: "Pull crowdsec API TopX",
  213. Long: `Pulls a list of malveolent IPs relevant to your situation and add them into the local ban database.`,
  214. Example: `cscli api pull`,
  215. Args: cobra.MinimumNArgs(0),
  216. Run: func(cmd *cobra.Command, args []string) {
  217. if err := cwhub.GetHubIdx(); err != nil {
  218. log.Fatalf(err.Error())
  219. }
  220. err := pullTOP()
  221. if err != nil {
  222. log.Fatalf(err.Error())
  223. }
  224. return
  225. },
  226. }
  227. var cmdAPICreds = &cobra.Command{
  228. Use: "credentials",
  229. Short: "Display api credentials",
  230. Long: ``,
  231. Example: `cscli api credentials`,
  232. Args: cobra.MinimumNArgs(0),
  233. Run: func(cmd *cobra.Command, args []string) {
  234. if err := dumpCredentials(); err != nil {
  235. log.Fatalf(err.Error())
  236. }
  237. return
  238. },
  239. }
  240. cmdAPI.AddCommand(cmdAPICreds)
  241. cmdAPIEnroll.Flags().StringVarP(&userID, "user", "u", "", "User ID (required)")
  242. if err := cmdAPIEnroll.MarkFlagRequired("user"); err != nil {
  243. log.Errorf("'user' flag : %s", err)
  244. }
  245. cmdAPI.AddCommand(cmdAPIEnroll)
  246. cmdAPI.AddCommand(cmdAPIResetPassword)
  247. cmdAPI.AddCommand(cmdAPIRegister)
  248. cmdAPI.AddCommand(cmdAPIPull)
  249. return cmdAPI
  250. }