encrypt_datasource_passwords.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package datamigrations
  2. import (
  3. "context"
  4. "encoding/json"
  5. "github.com/fatih/color"
  6. "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
  7. "github.com/grafana/grafana/pkg/cmd/grafana-cli/utils"
  8. "github.com/grafana/grafana/pkg/services/sqlstore"
  9. "github.com/grafana/grafana/pkg/setting"
  10. "github.com/grafana/grafana/pkg/util"
  11. "github.com/grafana/grafana/pkg/util/errutil"
  12. )
  13. var (
  14. datasourceTypes = []string{
  15. "mysql",
  16. "influxdb",
  17. "elasticsearch",
  18. "graphite",
  19. "prometheus",
  20. "opentsdb",
  21. }
  22. )
  23. // EncryptDatasourcePaswords migrates un-encrypted secrets on datasources
  24. // to the secureJson Column.
  25. func EncryptDatasourcePaswords(c utils.CommandLine, sqlStore *sqlstore.SqlStore) error {
  26. return sqlStore.WithDbSession(context.Background(), func(session *sqlstore.DBSession) error {
  27. passwordsUpdated, err := migrateColumn(session, "password")
  28. if err != nil {
  29. return err
  30. }
  31. basicAuthUpdated, err := migrateColumn(session, "basic_auth_password")
  32. if err != nil {
  33. return err
  34. }
  35. logger.Info("\n")
  36. if passwordsUpdated > 0 {
  37. logger.Infof("%s Encrypted password field for %d datasources \n", color.GreenString("✔"), passwordsUpdated)
  38. }
  39. if basicAuthUpdated > 0 {
  40. logger.Infof("%s Encrypted basic_auth_password field for %d datasources \n", color.GreenString("✔"), basicAuthUpdated)
  41. }
  42. if passwordsUpdated == 0 && basicAuthUpdated == 0 {
  43. logger.Infof("%s All datasources secrets are allready encrypted\n", color.GreenString("✔"))
  44. }
  45. logger.Info("\n")
  46. logger.Warn("Warning: Datasource provisioning files need to be manually changed to prevent overwriting of " +
  47. "the data during provisioning. See https://grafana.com/docs/installation/upgrading/#upgrading-to-v6-2 for " +
  48. "details")
  49. return nil
  50. })
  51. }
  52. func migrateColumn(session *sqlstore.DBSession, column string) (int, error) {
  53. var rows []map[string]string
  54. session.Cols("id", column, "secure_json_data")
  55. session.Table("data_source")
  56. session.In("type", datasourceTypes)
  57. session.Where(column + " IS NOT NULL AND " + column + " != ''")
  58. err := session.Find(&rows)
  59. if err != nil {
  60. return 0, errutil.Wrapf(err, "failed to select column: %s", column)
  61. }
  62. rowsUpdated, err := updateRows(session, rows, column)
  63. return rowsUpdated, errutil.Wrapf(err, "failed to update column: %s", column)
  64. }
  65. func updateRows(session *sqlstore.DBSession, rows []map[string]string, passwordFieldName string) (int, error) {
  66. var rowsUpdated int
  67. for _, row := range rows {
  68. newSecureJSONData, err := getUpdatedSecureJSONData(row, passwordFieldName)
  69. if err != nil {
  70. return 0, err
  71. }
  72. data, err := json.Marshal(newSecureJSONData)
  73. if err != nil {
  74. return 0, errutil.Wrap("marshaling newSecureJsonData failed", err)
  75. }
  76. newRow := map[string]interface{}{"secure_json_data": data, passwordFieldName: ""}
  77. session.Table("data_source")
  78. session.Where("id = ?", row["id"])
  79. // Setting both columns while having value only for secure_json_data should clear the [passwordFieldName] column
  80. session.Cols("secure_json_data", passwordFieldName)
  81. _, err = session.Update(newRow)
  82. if err != nil {
  83. return 0, err
  84. }
  85. rowsUpdated++
  86. }
  87. return rowsUpdated, nil
  88. }
  89. func getUpdatedSecureJSONData(row map[string]string, passwordFieldName string) (map[string]interface{}, error) {
  90. encryptedPassword, err := util.Encrypt([]byte(row[passwordFieldName]), setting.SecretKey)
  91. if err != nil {
  92. return nil, err
  93. }
  94. var secureJSONData map[string]interface{}
  95. if err := json.Unmarshal([]byte(row["secure_json_data"]), &secureJSONData); err != nil {
  96. return nil, err
  97. }
  98. jsonFieldName := util.ToCamelCase(passwordFieldName)
  99. secureJSONData[jsonFieldName] = encryptedPassword
  100. return secureJSONData, nil
  101. }