diff --git a/Makefile b/Makefile index 87ce242..947b5b0 100644 --- a/Makefile +++ b/Makefile @@ -122,7 +122,8 @@ ssh-server: echo drone-scp:1234 | chpasswd mkdir -p /home/drone-scp/.ssh chmod 700 /home/drone-scp/.ssh - cp tests/.ssh/id_rsa.pub /home/drone-scp/.ssh/authorized_keys + cat tests/.ssh/id_rsa.pub >> /home/drone-scp/.ssh/authorized_keys + cat tests/.ssh/test.pub >> /home/drone-scp/.ssh/authorized_keys chown -R drone-scp /home/drone-scp/.ssh # install ssh and start server apk add --update openssh openrc diff --git a/main.go b/main.go index d27816c..a714afd 100644 --- a/main.go +++ b/main.go @@ -65,9 +65,14 @@ func main() { Value: 10 * time.Minute, }, &cli.StringFlag{ - Name: "key, k", + Name: "ssh-key, k", Usage: "ssh private key", - EnvVars: []string{"PLUGIN_KEY", "SCP_KEY", "SSH_KEY", "KEY", "INPUT_KEY"}, + EnvVars: []string{"PLUGIN_SSH_KEY,", "PLUGIN_KEY", "SCP_KEY", "SSH_KEY", "KEY", "INPUT_KEY"}, + }, + &cli.StringFlag{ + Name: "ssh-passphrase", + Usage: "The purpose of the passphrase is usually to encrypt the private key.", + EnvVars: []string{"PLUGIN_SSH_PASSPHRASE", "PLUGIN_PASSPHRASE", "SSH_PASSPHRASE", "PASSPHRASE", "INPUT_PASSPHRASE"}, }, &cli.StringFlag{ Name: "key-path, i", @@ -151,6 +156,11 @@ func main() { Usage: "private ssh key of proxy", EnvVars: []string{"PLUGIN_PROXY_SSH_KEY", "PLUGIN_PROXY_KEY", "PROXY_SSH_KEY", "PROXY_KEY", "INPUT_PROXY_SSH_KEY"}, }, + &cli.StringFlag{ + Name: "proxy.ssh-passphrase", + Usage: "The purpose of the passphrase is usually to encrypt the private key.", + EnvVars: []string{"PLUGIN_PROXY_SSH_PASSPHRASE", "PLUGIN_PROXY_PASSPHRASE", "PROXY_SSH_PASSPHRASE,PROXY_PASSPHRASE", "INPUT_PROXY_PASSPHRASE"}, + }, &cli.StringFlag{ Name: "proxy.key-path", Usage: "ssh private key path of proxy", @@ -274,9 +284,10 @@ func run(c *cli.Context) error { Port: c.String("port"), Username: c.String("username"), Password: c.String("password"), + Passphrase: c.String("ssh-passphrase"), Timeout: c.Duration("timeout"), CommandTimeout: c.Duration("command.timeout"), - Key: c.String("key"), + Key: c.String("ssh-key"), KeyPath: c.String("key-path"), Target: c.StringSlice("target"), Source: c.StringSlice("source"), @@ -287,13 +298,14 @@ func run(c *cli.Context) error { TarTmpPath: c.String("tar.tmp-path"), Overwrite: c.Bool("overwrite"), Proxy: easyssh.DefaultConfig{ - Key: c.String("proxy.ssh-key"), - KeyPath: c.String("proxy.key-path"), - User: c.String("proxy.username"), - Password: c.String("proxy.password"), - Server: c.String("proxy.host"), - Port: c.String("proxy.port"), - Timeout: c.Duration("proxy.timeout"), + Key: c.String("proxy.ssh-key"), + Passphrase: c.String("proxy.ssh-passphrase"), + KeyPath: c.String("proxy.key-path"), + User: c.String("proxy.username"), + Password: c.String("proxy.password"), + Server: c.String("proxy.host"), + Port: c.String("proxy.port"), + Timeout: c.Duration("proxy.timeout"), }, }, } diff --git a/plugin.go b/plugin.go index 1c726bd..3b9ea2d 100644 --- a/plugin.go +++ b/plugin.go @@ -50,6 +50,7 @@ type ( Username string Password string Key string + Passphrase string KeyPath string Timeout time.Duration CommandTimeout time.Duration @@ -164,21 +165,23 @@ func (p *Plugin) removeDestFile(ssh *easyssh.MakeConfig) error { func (p *Plugin) removeAllDestFile() error { for _, host := range p.Config.Host { ssh := &easyssh.MakeConfig{ - Server: host, - User: p.Config.Username, - Password: p.Config.Password, - Port: p.Config.Port, - Key: p.Config.Key, - KeyPath: p.Config.KeyPath, - Timeout: p.Config.Timeout, + Server: host, + User: p.Config.Username, + Password: p.Config.Password, + Port: p.Config.Port, + Key: p.Config.Key, + KeyPath: p.Config.KeyPath, + Passphrase: p.Config.Passphrase, + Timeout: p.Config.Timeout, Proxy: easyssh.DefaultConfig{ - Server: p.Config.Proxy.Server, - User: p.Config.Proxy.User, - Password: p.Config.Proxy.Password, - Port: p.Config.Proxy.Port, - Key: p.Config.Proxy.Key, - KeyPath: p.Config.Proxy.KeyPath, - Timeout: p.Config.Proxy.Timeout, + Server: p.Config.Proxy.Server, + User: p.Config.Proxy.User, + Password: p.Config.Proxy.Password, + Port: p.Config.Proxy.Port, + Key: p.Config.Proxy.Key, + KeyPath: p.Config.Proxy.KeyPath, + Passphrase: p.Config.Proxy.Passphrase, + Timeout: p.Config.Proxy.Timeout, }, } @@ -272,21 +275,23 @@ func (p *Plugin) Exec() error { go func(host string) { // Create MakeConfig instance with remote username, server address and path to private key. ssh := &easyssh.MakeConfig{ - Server: host, - User: p.Config.Username, - Password: p.Config.Password, - Port: p.Config.Port, - Key: p.Config.Key, - KeyPath: p.Config.KeyPath, - Timeout: p.Config.Timeout, + Server: host, + User: p.Config.Username, + Password: p.Config.Password, + Port: p.Config.Port, + Key: p.Config.Key, + KeyPath: p.Config.KeyPath, + Passphrase: p.Config.Passphrase, + Timeout: p.Config.Timeout, Proxy: easyssh.DefaultConfig{ - Server: p.Config.Proxy.Server, - User: p.Config.Proxy.User, - Password: p.Config.Proxy.Password, - Port: p.Config.Proxy.Port, - Key: p.Config.Proxy.Key, - KeyPath: p.Config.Proxy.KeyPath, - Timeout: p.Config.Proxy.Timeout, + Server: p.Config.Proxy.Server, + User: p.Config.Proxy.User, + Password: p.Config.Proxy.Password, + Port: p.Config.Proxy.Port, + Key: p.Config.Proxy.Key, + KeyPath: p.Config.Proxy.KeyPath, + Passphrase: p.Config.Proxy.Passphrase, + Timeout: p.Config.Proxy.Timeout, }, } diff --git a/plugin_test.go b/plugin_test.go index c432ef7..f2522bc 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -130,6 +130,45 @@ func TestSCPFileFromPublicKey(t *testing.T) { } } +func TestSCPFileFromPublicKeyWithPassphrase(t *testing.T) { + if os.Getenv("SSH_AUTH_SOCK") != "" { + if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil { + t.Fatalf("exec: %v", err) + } + } + + u, err := user.Lookup("drone-scp") + if err != nil { + t.Fatalf("Lookup: %v", err) + } + + plugin := Plugin{ + Config: Config{ + Host: []string{"localhost"}, + Username: "drone-scp", + Port: "22", + KeyPath: "tests/.ssh/test", + Passphrase: "1234", + Source: []string{"tests/a.txt", "tests/b.txt"}, + Target: []string{filepath.Join(u.HomeDir, "/test2")}, + CommandTimeout: 60 * time.Second, + TarExec: "tar", + }, + } + + err = plugin.Exec() + assert.Nil(t, err) + + // check file exist + if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/a.txt")); os.IsNotExist(err) { + t.Fatalf("SCP-error: %v", err) + } + + if _, err := os.Stat(filepath.Join(u.HomeDir, "/test2/tests/b.txt")); os.IsNotExist(err) { + t.Fatalf("SCP-error: %v", err) + } +} + func TestSCPWildcardFileList(t *testing.T) { if os.Getenv("SSH_AUTH_SOCK") != "" { if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil { @@ -389,7 +428,7 @@ func TestGlobList(t *testing.T) { assert.Equal(t, expects, globList(paterns).Source) paterns = []string{"tests/*.txt", "tests/.ssh/*", "abc*"} - expects = []string{"tests/a.txt", "tests/b.txt", "tests/.ssh/id_rsa", "tests/.ssh/id_rsa.pub"} + expects = []string{"tests/a.txt", "tests/b.txt", "tests/.ssh/id_rsa", "tests/.ssh/id_rsa.pub", "tests/.ssh/test", "tests/.ssh/test.pub"} assert.Equal(t, expects, globList(paterns).Source) paterns = []string{"tests/?.txt"} diff --git a/tests/.ssh/test b/tests/.ssh/test new file mode 100644 index 0000000..89cc6ec --- /dev/null +++ b/tests/.ssh/test @@ -0,0 +1,50 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +l4njcaMpg4tpQMHtCBOicGyV0= +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/.ssh/test.pub b/tests/.ssh/test.pub new file mode 100644 index 0000000..559daf2 --- /dev/null +++ b/tests/.ssh/test.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDz6aZ1jY2onnuj2YNHJ/HhfvIu0B973v/+pFFOavnTUOhEEKEy3TASu+s9CkHrYZAtRc+QYIkNZI31mhHBhotdeP/7GoO2UirkFtrzyQKPNJxEcv0RBoG9ssN8jex0PyK6DHIYYFnIWadVBEEOh/H+rK7j7u2/big3oTzYBuFrCwmYFcz5na99MzFeAUhazF44gVBma+zO+1quGeqF51UDIg1SMGvX8I7LNEqrKEBaIUQJKFQcxlOWlRLQsjJCymrOujsXsRrXHAQWcnxDcNevv2ZMOUl0ybvv9yH0BiGbRBd1Hy8/QPILbAQaqu0oQE7fubN8Q8lqb3Jg0loID4x/5GPhSY8WAXpuLcXTOrb93SnCw1JsAgJDNqpuuRFy3BSZ7wBOr1jfeIoo7xk14OHiUjJ0uXDL9cLMkcw6ElWz81mrD2VCkXUz+qFyjJ+G7aGWRtctZoOzKln4yfNfUmwW8/8ra3QnmrMZ2xW2Ylw3ZhO+tLi7jINHYFb54bAdLVPUU1ctIuJns2qkWnjJCxxMiynIqCif20/OU1n8CTJuOWiURmRdmvKOH4PE3JxC2Qnk/3tV3Cf8hp1CH5VjBZ9AjGj5MDMHXyu34VY2WvYo5QyzfS3ySPoT8kCO0G0xpvjwCMHOK+G2RP4kqb/KKZguiKdgintBXuskTlJmD7kcMQ== deploy@easyssh