config.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  8. "github.com/crowdsecurity/crowdsec/pkg/cwhub"
  9. "github.com/crowdsecurity/crowdsec/pkg/types"
  10. log "github.com/sirupsen/logrus"
  11. "github.com/spf13/cobra"
  12. "gopkg.in/yaml.v2"
  13. )
  14. type OldAPICfg struct {
  15. MachineID string `json:"machine_id"`
  16. Password string `json:"password"`
  17. }
  18. /* Backup crowdsec configurations to directory <dirPath> :
  19. - Main config (config.yaml)
  20. - Profiles config (profiles.yaml)
  21. - Simulation config (simulation.yaml)
  22. - Backup of API credentials (local API and online API)
  23. - List of scenarios, parsers, postoverflows and collections that are up-to-date
  24. - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections
  25. */
  26. func backupConfigToDirectory(dirPath string) error {
  27. var err error
  28. if dirPath == "" {
  29. return fmt.Errorf("directory path can't be empty")
  30. }
  31. log.Infof("Starting configuration backup")
  32. _, err = os.Stat(dirPath)
  33. if err == nil {
  34. return fmt.Errorf("%s already exists", dirPath)
  35. }
  36. if err = os.MkdirAll(dirPath, os.ModePerm); err != nil {
  37. return fmt.Errorf("error while creating %s : %s", dirPath, err)
  38. }
  39. if csConfig.ConfigPaths.SimulationFilePath != "" {
  40. backupSimulation := fmt.Sprintf("%s/simulation.yaml", dirPath)
  41. if err = types.CopyFile(csConfig.ConfigPaths.SimulationFilePath, backupSimulation); err != nil {
  42. return fmt.Errorf("failed copy %s to %s : %s", csConfig.ConfigPaths.SimulationFilePath, backupSimulation, err)
  43. }
  44. log.Infof("Saved simulation to %s", backupSimulation)
  45. }
  46. if csConfig.Crowdsec != nil && csConfig.Crowdsec.AcquisitionFilePath != "" {
  47. backupAcquisition := fmt.Sprintf("%s/acquis.yaml", dirPath)
  48. if err = types.CopyFile(csConfig.Crowdsec.AcquisitionFilePath, backupAcquisition); err != nil {
  49. return fmt.Errorf("failed copy %s to %s : %s", csConfig.Crowdsec.AcquisitionFilePath, backupAcquisition, err)
  50. }
  51. log.Infof("Saved acquis to %s", backupAcquisition)
  52. }
  53. if ConfigFilePath != "" {
  54. backupMain := fmt.Sprintf("%s/config.yaml", dirPath)
  55. if err = types.CopyFile(ConfigFilePath, backupMain); err != nil {
  56. return fmt.Errorf("failed copy %s to %s : %s", ConfigFilePath, backupMain, err)
  57. }
  58. log.Infof("Saved default yaml to %s", backupMain)
  59. }
  60. if csConfig.API != nil && csConfig.API.Server != nil && csConfig.API.Server.OnlineClient != nil && csConfig.API.Server.OnlineClient.CredentialsFilePath != "" {
  61. backupCAPICreds := fmt.Sprintf("%s/online_api_credentials.yaml", dirPath)
  62. if err = types.CopyFile(csConfig.API.Server.OnlineClient.CredentialsFilePath, backupCAPICreds); err != nil {
  63. return fmt.Errorf("failed copy %s to %s : %s", csConfig.API.Server.OnlineClient.CredentialsFilePath, backupCAPICreds, err)
  64. }
  65. log.Infof("Saved online API credentials to %s", backupCAPICreds)
  66. }
  67. if csConfig.API != nil && csConfig.API.Client != nil && csConfig.API.Client.CredentialsFilePath != "" {
  68. backupLAPICreds := fmt.Sprintf("%s/local_api_credentials.yaml", dirPath)
  69. if err = types.CopyFile(csConfig.API.Client.CredentialsFilePath, backupLAPICreds); err != nil {
  70. return fmt.Errorf("failed copy %s to %s : %s", csConfig.API.Client.CredentialsFilePath, backupLAPICreds, err)
  71. }
  72. log.Infof("Saved local API credentials to %s", backupLAPICreds)
  73. }
  74. if csConfig.API != nil && csConfig.API.Server != nil && csConfig.API.Server.ProfilesPath != "" {
  75. backupProfiles := fmt.Sprintf("%s/profiles.yaml", dirPath)
  76. if err = types.CopyFile(csConfig.API.Server.ProfilesPath, backupProfiles); err != nil {
  77. return fmt.Errorf("failed copy %s to %s : %s", csConfig.API.Server.ProfilesPath, backupProfiles, err)
  78. }
  79. log.Infof("Saved profiles to %s", backupProfiles)
  80. }
  81. if err = BackupHub(dirPath); err != nil {
  82. return fmt.Errorf("failed to backup hub config : %s", err)
  83. }
  84. return nil
  85. }
  86. /* Restore crowdsec configurations to directory <dirPath> :
  87. - Main config (config.yaml)
  88. - Profiles config (profiles.yaml)
  89. - Simulation config (simulation.yaml)
  90. - Backup of API credentials (local API and online API)
  91. - List of scenarios, parsers, postoverflows and collections that are up-to-date
  92. - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections
  93. */
  94. func restoreConfigFromDirectory(dirPath string) error {
  95. var err error
  96. if !restoreOldBackup {
  97. backupMain := fmt.Sprintf("%s/config.yaml", dirPath)
  98. if _, err = os.Stat(backupMain); err == nil {
  99. if csConfig.ConfigPaths != nil && csConfig.ConfigPaths.ConfigDir != "" {
  100. if err = types.CopyFile(backupMain, csConfig.ConfigPaths.ConfigDir); err != nil {
  101. return fmt.Errorf("failed copy %s to %s : %s", backupMain, csConfig.ConfigPaths.ConfigDir, err)
  102. }
  103. }
  104. }
  105. // Now we have config.yaml, we should regenerate config struct to have rights paths etc
  106. ConfigFilePath = fmt.Sprintf("%s/config.yaml", csConfig.ConfigPaths.ConfigDir)
  107. initConfig()
  108. backupCAPICreds := fmt.Sprintf("%s/online_api_credentials.yaml", dirPath)
  109. if _, err = os.Stat(backupCAPICreds); err == nil {
  110. if err = types.CopyFile(backupCAPICreds, csConfig.API.Server.OnlineClient.CredentialsFilePath); err != nil {
  111. return fmt.Errorf("failed copy %s to %s : %s", backupCAPICreds, csConfig.API.Server.OnlineClient.CredentialsFilePath, err)
  112. }
  113. }
  114. backupLAPICreds := fmt.Sprintf("%s/local_api_credentials.yaml", dirPath)
  115. if _, err = os.Stat(backupLAPICreds); err == nil {
  116. if err = types.CopyFile(backupLAPICreds, csConfig.API.Client.CredentialsFilePath); err != nil {
  117. return fmt.Errorf("failed copy %s to %s : %s", backupLAPICreds, csConfig.API.Client.CredentialsFilePath, err)
  118. }
  119. }
  120. backupProfiles := fmt.Sprintf("%s/profiles.yaml", dirPath)
  121. if _, err = os.Stat(backupProfiles); err == nil {
  122. if err = types.CopyFile(backupProfiles, csConfig.API.Server.ProfilesPath); err != nil {
  123. return fmt.Errorf("failed copy %s to %s : %s", backupProfiles, csConfig.API.Server.ProfilesPath, err)
  124. }
  125. }
  126. } else {
  127. var oldAPICfg OldAPICfg
  128. backupOldAPICfg := fmt.Sprintf("%s/api_creds.json", dirPath)
  129. jsonFile, err := os.Open(backupOldAPICfg)
  130. if err != nil {
  131. log.Warningf("failed to open %s : %s", backupOldAPICfg, err)
  132. } else {
  133. byteValue, _ := ioutil.ReadAll(jsonFile)
  134. err = json.Unmarshal(byteValue, &oldAPICfg)
  135. if err != nil {
  136. return fmt.Errorf("failed to load json file %s : %s", backupOldAPICfg, err)
  137. }
  138. apiCfg := csconfig.ApiCredentialsCfg{
  139. Login: oldAPICfg.MachineID,
  140. Password: oldAPICfg.Password,
  141. URL: CAPIBaseURL,
  142. }
  143. apiConfigDump, err := yaml.Marshal(apiCfg)
  144. if err != nil {
  145. return fmt.Errorf("unable to dump api credentials: %s", err)
  146. }
  147. apiConfigDumpFile := fmt.Sprintf("%s/online_api_credentials.yaml", csConfig.ConfigPaths.ConfigDir)
  148. if csConfig.API.Server.OnlineClient != nil && csConfig.API.Server.OnlineClient.CredentialsFilePath != "" {
  149. apiConfigDumpFile = csConfig.API.Server.OnlineClient.CredentialsFilePath
  150. }
  151. err = ioutil.WriteFile(apiConfigDumpFile, apiConfigDump, 0644)
  152. if err != nil {
  153. return fmt.Errorf("write api credentials in '%s' failed: %s", apiConfigDumpFile, err)
  154. }
  155. log.Infof("Saved API credentials to %s", apiConfigDumpFile)
  156. }
  157. }
  158. backupSimulation := fmt.Sprintf("%s/simulation.yaml", dirPath)
  159. if _, err = os.Stat(backupSimulation); err == nil {
  160. if err = types.CopyFile(backupSimulation, csConfig.ConfigPaths.SimulationFilePath); err != nil {
  161. return fmt.Errorf("failed copy %s to %s : %s", backupSimulation, csConfig.ConfigPaths.SimulationFilePath, err)
  162. }
  163. }
  164. backupAcquisition := fmt.Sprintf("%s/acquis.yaml", dirPath)
  165. if _, err = os.Stat(backupAcquisition); err == nil {
  166. if err = types.CopyFile(backupAcquisition, csConfig.Crowdsec.AcquisitionFilePath); err != nil {
  167. return fmt.Errorf("failed copy %s to %s : %s", backupAcquisition, csConfig.Crowdsec.AcquisitionFilePath, err)
  168. }
  169. }
  170. if err = RestoreHub(dirPath); err != nil {
  171. return fmt.Errorf("failed to restore hub config : %s", err)
  172. }
  173. return nil
  174. }
  175. func NewConfigCmd() *cobra.Command {
  176. var cmdConfig = &cobra.Command{
  177. Use: "config [command]",
  178. Short: "Allows to view current config",
  179. Args: cobra.ExactArgs(0),
  180. }
  181. var cmdConfigShow = &cobra.Command{
  182. Use: "show",
  183. Short: "Displays current config",
  184. Long: `Displays the current cli configuration.`,
  185. Args: cobra.ExactArgs(0),
  186. Run: func(cmd *cobra.Command, args []string) {
  187. switch csConfig.Cscli.Output {
  188. case "human":
  189. fmt.Printf("Global:\n")
  190. fmt.Printf(" - Configuration Folder : %s\n", csConfig.ConfigPaths.ConfigDir)
  191. fmt.Printf(" - Data Folder : %s\n", csConfig.ConfigPaths.DataDir)
  192. fmt.Printf(" - Log Folder : %s\n", csConfig.Common.LogDir)
  193. fmt.Printf(" - Hub Folder : %s\n", csConfig.ConfigPaths.HubDir)
  194. fmt.Printf(" - Simulation File : %s\n", csConfig.ConfigPaths.SimulationFilePath)
  195. fmt.Printf(" - Log level : %s\n", csConfig.Common.LogLevel)
  196. fmt.Printf(" - Log Media : %s\n", csConfig.Common.LogMedia)
  197. fmt.Printf("Crowdsec:\n")
  198. fmt.Printf(" - Acquisition File : %s\n", csConfig.Crowdsec.AcquisitionFilePath)
  199. fmt.Printf(" - Parsers routines : %d\n", csConfig.Crowdsec.ParserRoutinesCount)
  200. fmt.Printf("cscli:\n")
  201. fmt.Printf(" - Output : %s\n", csConfig.Cscli.Output)
  202. fmt.Printf(" - Hub Branch : %s\n", csConfig.Cscli.HubBranch)
  203. fmt.Printf(" - Hub Folder : %s\n", csConfig.Cscli.HubDir)
  204. fmt.Printf("API Client:\n")
  205. fmt.Printf(" - URL : %s\n", csConfig.API.Client.Credentials.URL)
  206. fmt.Printf(" - Login : %s\n", csConfig.API.Client.Credentials.Login)
  207. fmt.Printf(" - Credentials File : %s\n", csConfig.API.Client.CredentialsFilePath)
  208. fmt.Printf("Local API Server:\n")
  209. fmt.Printf(" - Listen URL : %s\n", csConfig.API.Server.ListenURI)
  210. fmt.Printf(" - Profile File : %s\n", csConfig.API.Server.ProfilesPath)
  211. if csConfig.API.Server.TLS != nil {
  212. if csConfig.API.Server.TLS.CertFilePath != "" {
  213. fmt.Printf(" - Cert File : %s\n", csConfig.API.Server.TLS.CertFilePath)
  214. }
  215. if csConfig.API.Server.TLS.KeyFilePath != "" {
  216. fmt.Printf(" - Key File : %s\n", csConfig.API.Server.TLS.KeyFilePath)
  217. }
  218. }
  219. fmt.Printf(" - Database:\n")
  220. fmt.Printf(" - Type : %s\n", csConfig.DbConfig.Type)
  221. switch csConfig.DbConfig.Type {
  222. case "sqlite":
  223. fmt.Printf(" - Path : %s\n", csConfig.DbConfig.DbPath)
  224. case "mysql", "postgresql", "postgres":
  225. fmt.Printf(" - Host : %s\n", csConfig.DbConfig.Host)
  226. fmt.Printf(" - Port : %d\n", csConfig.DbConfig.Port)
  227. fmt.Printf(" - User : %s\n", csConfig.DbConfig.User)
  228. fmt.Printf(" - DB Name : %s\n", csConfig.DbConfig.DbName)
  229. }
  230. if csConfig.DbConfig.Flush != nil {
  231. if *csConfig.DbConfig.Flush.MaxAge != "" {
  232. fmt.Printf(" - Flush age : %s\n", *csConfig.DbConfig.Flush.MaxAge)
  233. }
  234. if *csConfig.DbConfig.Flush.MaxItems != 0 {
  235. fmt.Printf(" - Flush size : %d\n", *csConfig.DbConfig.Flush.MaxItems)
  236. }
  237. }
  238. fmt.Printf("Central API:\n")
  239. fmt.Printf(" - URL : %s\n", csConfig.API.Server.OnlineClient.Credentials.URL)
  240. fmt.Printf(" - Login : %s\n", csConfig.API.Server.OnlineClient.Credentials.Login)
  241. fmt.Printf(" - Credentials File : %s\n", csConfig.API.Server.OnlineClient.CredentialsFilePath)
  242. case "json":
  243. data, err := json.MarshalIndent(csConfig, "", " ")
  244. if err != nil {
  245. log.Fatalf("failed to marshal configuration: %s", err)
  246. }
  247. fmt.Printf("%s\n", string(data))
  248. case "raw":
  249. data, err := yaml.Marshal(csConfig)
  250. if err != nil {
  251. log.Fatalf("failed to marshal configuration: %s", err)
  252. }
  253. fmt.Printf("%s\n", string(data))
  254. }
  255. },
  256. }
  257. cmdConfig.AddCommand(cmdConfigShow)
  258. var cmdConfigBackup = &cobra.Command{
  259. Use: "backup <directory>",
  260. Short: "Backup current config",
  261. Long: `Backup the current crowdsec configuration including :
  262. - Main config (config.yaml)
  263. - Simulation config (simulation.yaml)
  264. - Profiles config (profiles.yaml)
  265. - List of scenarios, parsers, postoverflows and collections that are up-to-date
  266. - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections
  267. - Backup of API credentials (local API and online API)`,
  268. Example: `cscli config backup ./my-backup`,
  269. Args: cobra.ExactArgs(1),
  270. Run: func(cmd *cobra.Command, args []string) {
  271. var err error
  272. if err = cwhub.GetHubIdx(csConfig.Cscli); err != nil {
  273. log.Fatalf("failed to get Hub index : %v", err)
  274. }
  275. if err = backupConfigToDirectory(args[0]); err != nil {
  276. log.Fatalf("Failed to backup configurations: %s", err)
  277. }
  278. },
  279. }
  280. cmdConfig.AddCommand(cmdConfigBackup)
  281. var cmdConfigRestore = &cobra.Command{
  282. Use: "restore <directory>",
  283. Short: "Restore config in backup <directory>",
  284. Long: `Restore the crowdsec configuration from specified backup <directory> including:
  285. - Main config (config.yaml)
  286. - Simulation config (simulation.yaml)
  287. - Profiles config (profiles.yaml)
  288. - List of scenarios, parsers, postoverflows and collections that are up-to-date
  289. - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections
  290. - Backup of API credentials (local API and online API)`,
  291. Args: cobra.ExactArgs(1),
  292. Run: func(cmd *cobra.Command, args []string) {
  293. var err error
  294. if err = cwhub.GetHubIdx(csConfig.Cscli); err != nil {
  295. log.Fatalf("failed to get Hub index : %v", err)
  296. }
  297. if err := restoreConfigFromDirectory(args[0]); err != nil {
  298. log.Fatalf("failed restoring configurations from %s : %s", args[0], err)
  299. }
  300. },
  301. }
  302. cmdConfigRestore.PersistentFlags().BoolVar(&restoreOldBackup, "old-backup", false, "To use when you are upgrading crowdsec v0.X to v1.X and you need to restore backup from v0.X")
  303. cmdConfig.AddCommand(cmdConfigRestore)
  304. return cmdConfig
  305. }