Skip to content
This repository has been archived by the owner on Nov 24, 2023. It is now read-only.

feat(encrypt): Support both encrypted and unencrypted passwords for the upstream and downstream database #633

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cmd/dm-ctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import (
//
//Special Commands:
// --encrypt encrypt plaintext to ciphertext
// --decrypt decrypt ciphertext to plaintext
//
//Global Options:
// --V prints version and exit
Expand All @@ -74,10 +75,12 @@ func helpUsage(cfg *common.Config) {
fmt.Println("Special Commands:")
f := cfg.FlagSet.Lookup(common.EncryptCmdName)
fmt.Println(fmt.Sprintf(" --%s %s", f.Name, f.Usage))
f = cfg.FlagSet.Lookup(common.DecryptCmdName)
fmt.Println(fmt.Sprintf(" --%s %s", f.Name, f.Usage))
fmt.Println()
fmt.Println("Global Options:")
cfg.FlagSet.VisitAll(func(flag2 *flag.Flag) {
if flag2.Name == common.EncryptCmdName {
if flag2.Name == common.EncryptCmdName || flag2.Name == common.DecryptCmdName {
return
}
fmt.Println(fmt.Sprintf(" --%s %s", flag2.Name, flag2.Usage))
Expand Down
24 changes: 7 additions & 17 deletions dm/config/source_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,41 +167,31 @@ func (c *SourceConfig) Verify() error {
}
}

_, err = c.DecryptPassword()
if err != nil {
return err
}
c.DecryptPassword()

return nil
}

// DecryptPassword returns a decrypted config replica in config
func (c *SourceConfig) DecryptPassword() (*SourceConfig, error) {
func (c *SourceConfig) DecryptPassword() *SourceConfig {
clone := c.Clone()
var (
pswdFrom string
err error
)
if len(clone.From.Password) > 0 {
pswdFrom, err = utils.Decrypt(clone.From.Password)
if err != nil {
return nil, terror.WithClass(err, terror.ClassDMWorker)
}
pswdFrom = utils.DecryptOrPlaintext(clone.From.Password)
}
clone.From.Password = pswdFrom
return clone, nil
return clone
}

// GenerateDBConfig creates DBConfig for DB
func (c *SourceConfig) GenerateDBConfig() (*DBConfig, error) {
func (c *SourceConfig) GenerateDBConfig() *DBConfig {
// decrypt password
clone, err := c.DecryptPassword()
if err != nil {
return nil, err
}
clone := c.DecryptPassword()
from := &clone.From
from.RawDBCfg = DefaultRawDBConfig().SetReadTimeout(dbReadTimeout)
return from, nil
return from
}

// Adjust flavor and serverid of SourceConfig
Expand Down
35 changes: 28 additions & 7 deletions dm/config/source_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,14 @@ func (t *testConfig) TestConfig(c *C) {
// test decrypt password
clone1.From.Password = "1234"
clone1.ServerID = 101
clone2, err := cfg.DecryptPassword()
c.Assert(err, IsNil)
clone2 := cfg.DecryptPassword()
c.Assert(clone2, DeepEquals, clone1)

cfg.From.Password = "xxx"
_, err = cfg.DecryptPassword()
c.Assert(err, NotNil)
cfg.DecryptPassword()

cfg.From.Password = ""
clone3, err := cfg.DecryptPassword()
c.Assert(err, IsNil)
clone3 := cfg.DecryptPassword()
c.Assert(clone3, DeepEquals, cfg)

// test toml and parse again
Expand Down Expand Up @@ -167,7 +164,31 @@ func (t *testConfig) TestConfigVerify(c *C) {
cfg.From.Password = "not-encrypt"
return cfg
},
"*decode base64 encoded password.*",
"",
},
{
func() *SourceConfig {
cfg := newConfig()
cfg.From.Password = "" // password empty
return cfg
},
"",
},
{
func() *SourceConfig {
cfg := newConfig()
cfg.From.Password = "123456" // plaintext password
return cfg
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about adding test case config with encrypt password?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, i have added a testCase about encrypt password

},
"",
},
{
func() *SourceConfig {
cfg := newConfig()
cfg.From.Password = "/Q7B9DizNLLTTfiZHv9WoEAKamfpIUs=" // encrypt password (123456)
return cfg
},
"",
},
}

Expand Down
12 changes: 3 additions & 9 deletions dm/config/subtask.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

"github.com/BurntSushi/toml"
bf "github.com/pingcap/tidb-tools/pkg/binlog-filter"
column "github.com/pingcap/tidb-tools/pkg/column-mapping"
"github.com/pingcap/tidb-tools/pkg/column-mapping"
"github.com/pingcap/tidb-tools/pkg/filter"
router "github.com/pingcap/tidb-tools/pkg/table-router"
"go.uber.org/zap"
Expand Down Expand Up @@ -352,16 +352,10 @@ func (c *SubTaskConfig) DecryptPassword() (*SubTaskConfig, error) {
pswdFrom string
)
if len(clone.To.Password) > 0 {
pswdTo, err = utils.Decrypt(clone.To.Password)
if err != nil {
return nil, terror.WithScope(terror.ErrConfigDecryptDBPassword.Delegate(err, clone.To.Password), terror.ScopeDownstream)
}
pswdTo = utils.DecryptOrPlaintext(clone.To.Password)
}
if len(clone.From.Password) > 0 {
pswdFrom, err = utils.Decrypt(clone.From.Password)
if err != nil {
return nil, terror.WithScope(terror.ErrConfigDecryptDBPassword.Delegate(err, clone.From.Password), terror.ScopeUpstream)
}
pswdFrom = utils.DecryptOrPlaintext(clone.From.Password)
}
clone.From.Password = pswdFrom
clone.To.Password = pswdTo
Expand Down
4 changes: 2 additions & 2 deletions dm/config/subtask_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ func (t *testConfig) TestSubTask(c *C) {

cfg.From.Password = "xxx"
_, err = cfg.DecryptPassword()
c.Assert(err, NotNil)
c.Assert(err, IsNil)
err = cfg.Adjust(true)
c.Assert(err, NotNil)
c.Assert(err, IsNil)
err = cfg.Adjust(false)
c.Assert(err, IsNil)

Expand Down
13 changes: 13 additions & 0 deletions dm/ctl/common/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const (

// EncryptCmdName is special command
EncryptCmdName = "encrypt"
// DecryptCmdName is special command
DecryptCmdName = "decrypt"
)

// NewConfig creates a new base config for dmctl.
Expand All @@ -47,6 +49,7 @@ func NewConfig() *Config {
fs.StringVar(&cfg.MasterAddr, "master-addr", "", "master API server addr")
fs.StringVar(&cfg.RPCTimeoutStr, "rpc-timeout", defaultRPCTimeout, fmt.Sprintf("rpc timeout, default is %s", defaultRPCTimeout))
fs.StringVar(&cfg.encrypt, EncryptCmdName, "", "encrypt plaintext to ciphertext")
fs.StringVar(&cfg.decrypt, DecryptCmdName, "", "decrypt ciphertext to plaintext")

return cfg
}
Expand All @@ -64,6 +67,7 @@ type Config struct {

printVersion bool
encrypt string // string need to be encrypted
decrypt string // string need to be decrypted
}

func (c *Config) String() string {
Expand Down Expand Up @@ -95,6 +99,15 @@ func (c *Config) Parse(arguments []string) (finish bool, err error) {
return true, nil
}

if len(c.decrypt) > 0 {
plaintext, err1 := utils.Decrypt(c.decrypt)
if err1 != nil {
return true, err1
}
fmt.Println(plaintext)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line should be deleted

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we are shouldn't delete these lines, because the Decrypt method is called instead of DecryptOrPlaintext in L103 , the function may return a error

return true, nil
}

// Load config file if specified.
if c.ConfigFile != "" {
err = c.configFromFile(c.ConfigFile)
Expand Down
10 changes: 2 additions & 8 deletions dm/master/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1171,10 +1171,7 @@ func (s *Server) getSourceConfigs(sources []*config.MySQLInstance) (map[string]c
for _, source := range sources {
if cfg := s.scheduler.GetSourceCfgByID(source.SourceID); cfg != nil {
// check the password
_, err := cfg.DecryptPassword()
if err != nil {
return nil, err
}
cfg.DecryptPassword()
cfgs[source.SourceID] = cfg.From
}
}
Expand Down Expand Up @@ -1243,10 +1240,7 @@ func parseAndAdjustSourceConfig(cfg *config.SourceConfig, content string) error
return err
}

dbConfig, err := cfg.GenerateDBConfig()
if err != nil {
return err
}
dbConfig := cfg.GenerateDBConfig()

fromDB, err := conn.DefaultDBProvider.Apply(*dbConfig)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions dm/master/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,14 +363,14 @@ func (t *testMaster) TestCheckTask(c *check.C) {
c.Assert(resp.Result, check.IsFalse)
clearSchedulerEnv(c, cancel, &wg)

// simulate invalid password returned from scheduler, so cfg.SubTaskConfigs will fail
// simulate invalid password returned from scheduler, but config was supported plaintext mysql password, so cfg.SubTaskConfigs will success
ctx, cancel = context.WithCancel(context.Background())
server.scheduler, _ = testMockScheduler(ctx, &wg, c, sources, workers, "invalid-encrypt-password", t.workerClients)
resp, err = server.CheckTask(context.Background(), &pb.CheckTaskRequest{
Task: taskConfig,
})
c.Assert(err, check.IsNil)
c.Assert(resp.Result, check.IsFalse)
c.Assert(resp.Result, check.IsTrue)
clearSchedulerEnv(c, cancel, &wg)
}

Expand Down
23 changes: 6 additions & 17 deletions dm/portal/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ import (

// for database
_ "github.com/go-sql-driver/mysql"
"github.com/pingcap/dm/dm/config"
"github.com/pingcap/dm/pkg/log"
"github.com/pingcap/dm/pkg/utils"
"github.com/pingcap/errors"
"github.com/pingcap/tidb-tools/pkg/dbutil"
"github.com/pingcap/tidb-tools/pkg/filter"
"github.com/unrolled/render"
"go.uber.org/zap"
yaml "gopkg.in/yaml.v2"
"gopkg.in/yaml.v2"

"github.com/pingcap/dm/dm/config"
"github.com/pingcap/dm/pkg/log"
"github.com/pingcap/dm/pkg/utils"
)

const (
Expand Down Expand Up @@ -341,19 +342,7 @@ func (p *Handler) AnalyzeConfig(w http.ResponseWriter, req *http.Request) {
log.L().Info("analyze config", zap.String("config name", cfg.Name))

// decrypt password
dePwd, err := utils.Decrypt(cfg.TargetDB.Password)
log.L().Error("decrypt password failed", zap.Error(err))
if err != nil {
p.genJSONResp(w, http.StatusBadRequest, AnalyzeResult{
CommonResult: CommonResult{
Result: failed,
Error: err.Error(),
},
Config: DMTaskConfig{},
})
return
}
cfg.TargetDB.Password = dePwd
cfg.TargetDB.Password = utils.DecryptOrPlaintext(cfg.TargetDB.Password)

p.genJSONResp(w, http.StatusOK, AnalyzeResult{
CommonResult: CommonResult{
Expand Down
2 changes: 1 addition & 1 deletion dm/worker/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ type realRelayHolder struct {

// NewRealRelayHolder creates a new RelayHolder
func NewRealRelayHolder(cfg *config.SourceConfig) RelayHolder {
clone, _ := cfg.DecryptPassword()
clone := cfg.DecryptPassword()
relayCfg := &relay.Config{
EnableGTID: clone.EnableGTID,
AutoFixGTID: clone.AutoFixGTID,
Expand Down
2 changes: 1 addition & 1 deletion dm/worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ func (w *Worker) UpdateRelayConfig(ctx context.Context, content string) error {
}

w.l.Info("update config", zap.Stringer("new config", newCfg))
cloneCfg, _ := newCfg.DecryptPassword()
cloneCfg := newCfg.DecryptPassword()

// Update SubTask configure
// NOTE: we only update `DB.Config` in SubTaskConfig now
Expand Down
9 changes: 9 additions & 0 deletions pkg/utils/encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,12 @@ func Decrypt(ciphertextB64 string) (string, error) {
}
return string(plaintext), nil
}

// DecryptOrPlaintext tries to decrypt base64 encoded ciphertext to plaintext or return plaintext
func DecryptOrPlaintext(ciphertextB64 string) string {
plaintext, err := Decrypt(ciphertextB64)
if err != nil {
return ciphertextB64
}
return plaintext
}
2 changes: 1 addition & 1 deletion tests/dm_syncer/conf/source1.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ relay-binlog-gtid = ""
[from]
host = "127.0.0.1"
user = "root"
password = "/Q7B9DizNLLTTfiZHv9WoEAKamfpIUs="
password = "123456"
port = 3306
2 changes: 1 addition & 1 deletion tests/dmctl_basic/conf/source1.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ enable-relay = true
[from]
host = "127.0.0.1"
user = "root"
password = "/Q7B9DizNLLTTfiZHv9WoEAKamfpIUs="
password = "123456"
port = 3306
2 changes: 1 addition & 1 deletion tests/dmctl_command/conf/source1.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ relay-binlog-gtid = ""
[from]
host = "127.0.0.1"
user = "root"
password = "/Q7B9DizNLLTTfiZHv9WoEAKamfpIUs="
password = "123456"
port = 3306

[checker]
Expand Down
2 changes: 1 addition & 1 deletion tests/dmctl_command/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source $cur/../_utils/test_prepare
WORK_DIR=$TEST_DIR/$TEST_NAME

help_cnt=35
help_cnt=36

function run() {
# check dmctl alone output
Expand Down