api.go 7.4 KB

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