| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- package datamigrations
- import (
- "context"
- "encoding/json"
- "github.com/fatih/color"
- "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
- "github.com/grafana/grafana/pkg/cmd/grafana-cli/utils"
- "github.com/grafana/grafana/pkg/services/sqlstore"
- "github.com/grafana/grafana/pkg/setting"
- "github.com/grafana/grafana/pkg/util"
- "github.com/grafana/grafana/pkg/util/errutil"
- )
- var (
- datasourceTypes = []string{
- "mysql",
- "influxdb",
- "elasticsearch",
- "graphite",
- "prometheus",
- "opentsdb",
- }
- )
- // EncryptDatasourcePaswords migrates un-encrypted secrets on datasources
- // to the secureJson Column.
- func EncryptDatasourcePaswords(c utils.CommandLine, sqlStore *sqlstore.SqlStore) error {
- return sqlStore.WithDbSession(context.Background(), func(session *sqlstore.DBSession) error {
- passwordsUpdated, err := migrateColumn(session, "password")
- if err != nil {
- return err
- }
- basicAuthUpdated, err := migrateColumn(session, "basic_auth_password")
- if err != nil {
- return err
- }
- logger.Info("\n")
- if passwordsUpdated > 0 {
- logger.Infof("%s Encrypted password field for %d datasources \n", color.GreenString("✔"), passwordsUpdated)
- }
- if basicAuthUpdated > 0 {
- logger.Infof("%s Encrypted basic_auth_password field for %d datasources \n", color.GreenString("✔"), basicAuthUpdated)
- }
- if passwordsUpdated == 0 && basicAuthUpdated == 0 {
- logger.Infof("%s All datasources secrets are allready encrypted\n", color.GreenString("✔"))
- }
- logger.Info("\n")
- logger.Warn("Warning: Datasource provisioning files need to be manually changed to prevent overwriting of " +
- "the data during provisioning. See https://grafana.com/docs/installation/upgrading/#upgrading-to-v6-2 for " +
- "details")
- return nil
- })
- }
- func migrateColumn(session *sqlstore.DBSession, column string) (int, error) {
- var rows []map[string]string
- session.Cols("id", column, "secure_json_data")
- session.Table("data_source")
- session.In("type", datasourceTypes)
- session.Where(column + " IS NOT NULL AND " + column + " != ''")
- err := session.Find(&rows)
- if err != nil {
- return 0, errutil.Wrapf(err, "failed to select column: %s", column)
- }
- rowsUpdated, err := updateRows(session, rows, column)
- return rowsUpdated, errutil.Wrapf(err, "failed to update column: %s", column)
- }
- func updateRows(session *sqlstore.DBSession, rows []map[string]string, passwordFieldName string) (int, error) {
- var rowsUpdated int
- for _, row := range rows {
- newSecureJSONData, err := getUpdatedSecureJSONData(row, passwordFieldName)
- if err != nil {
- return 0, err
- }
- data, err := json.Marshal(newSecureJSONData)
- if err != nil {
- return 0, errutil.Wrap("marshaling newSecureJsonData failed", err)
- }
- newRow := map[string]interface{}{"secure_json_data": data, passwordFieldName: ""}
- session.Table("data_source")
- session.Where("id = ?", row["id"])
- // Setting both columns while having value only for secure_json_data should clear the [passwordFieldName] column
- session.Cols("secure_json_data", passwordFieldName)
- _, err = session.Update(newRow)
- if err != nil {
- return 0, err
- }
- rowsUpdated++
- }
- return rowsUpdated, nil
- }
- func getUpdatedSecureJSONData(row map[string]string, passwordFieldName string) (map[string]interface{}, error) {
- encryptedPassword, err := util.Encrypt([]byte(row[passwordFieldName]), setting.SecretKey)
- if err != nil {
- return nil, err
- }
- var secureJSONData map[string]interface{}
- if err := json.Unmarshal([]byte(row["secure_json_data"]), &secureJSONData); err != nil {
- return nil, err
- }
- jsonFieldName := util.ToCamelCase(passwordFieldName)
- secureJSONData[jsonFieldName] = encryptedPassword
- return secureJSONData, nil
- }
|