diff --git a/main.go b/main.go index 8d1c0a6..847396f 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,11 @@ func main() { Usage: "private ssh key", EnvVar: "PLUGIN_SSH_KEY,PLUGIN_KEY,SSH_KEY", }, + cli.StringFlag{ + Name: "key-path", + Usage: "ssh private key path", + EnvVar: "PLUGIN_KEY_PATH,SSH_KEY_PATH", + }, cli.StringFlag{ Name: "user", Usage: "connect as user", @@ -117,6 +122,7 @@ func run(c *cli.Context) error { plugin := Plugin{ Config: Config{ Key: c.String("ssh-key"), + KeyPath: c.String("key-path"), User: c.String("user"), Password: c.String("password"), Host: c.StringSlice("host"), diff --git a/plugin.go b/plugin.go index d692d21..e56bb84 100644 --- a/plugin.go +++ b/plugin.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "io/ioutil" "log" "net" "os" @@ -17,12 +18,14 @@ const ( missingPasswordOrKey = "Error: can't connect without a private SSH key or password" unableConnectServer = "Error: Failed to start a SSH session" failParsePrivateKey = "Error: Failed to parse private key" + sshKeyNotFound = "ssh: no key found" ) type ( // Config for the plugin. Config struct { Key string + KeyPath string User string Password string Host []string @@ -38,13 +41,29 @@ type ( } ) +// returns ssh.Signer from user you running app home path + cutted key path. +// (ex. pubkey,err := getKeyFile("/.ssh/id_rsa") ) +func getKeyFile(keypath string) (ssh.Signer, error) { + buf, err := ioutil.ReadFile(keypath) + if err != nil { + return nil, err + } + + pubkey, err := ssh.ParsePrivateKey(buf) + if err != nil { + return nil, err + } + + return pubkey, nil +} + // Exec executes the plugin. func (p Plugin) Exec() error { if len(p.Config.Host) == 0 && p.Config.User == "" { return fmt.Errorf(missingHostOrUser) } - if p.Config.Key == "" && p.Config.Password == "" { + if p.Config.Key == "" && p.Config.Password == "" && p.Config.KeyPath == "" { return fmt.Errorf(missingPasswordOrKey) } @@ -57,6 +76,16 @@ func (p Plugin) Exec() error { // auths holds the detected ssh auth methods auths := []ssh.AuthMethod{} + if p.Config.KeyPath != "" { + pubkey, err := getKeyFile(p.Config.KeyPath) + + if err != nil { + return err + } + + auths = append(auths, ssh.PublicKeys(pubkey)) + } + if p.Config.Key != "" { signer, err := ssh.ParsePrivateKey([]byte(p.Config.Key)) diff --git a/plugin_test.go b/plugin_test.go index 2516571..10f934a 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -61,7 +61,7 @@ func TestFailParsePrivateKey(t *testing.T) { assert.Equal(t, failParsePrivateKey, err.Error()) } -func TestSSHScript(t *testing.T) { +func TestSSHScriptFromRawKey(t *testing.T) { plugin := Plugin{ Config: Config{ Host: []string{"localhost"}, @@ -102,3 +102,50 @@ ib4KbP5ovZlrjL++akMQ7V2fHzuQIFWnCkDA5c2ZAqzlM+ZN+HRG7gWur7Bt4XH1 err := plugin.Exec() assert.Nil(t, err) } + +func TestWrongKeyPath(t *testing.T) { + plugin := Plugin{ + Config: Config{ + Host: []string{"localhost"}, + User: "drone-scp", + Port: 22, + KeyPath: "/appleboy", + Script: []string{"whoami"}, + }, + } + + err := plugin.Exec() + assert.NotNil(t, err) + assert.Equal(t, "open /appleboy: no such file or directory", err.Error()) +} + +func TestWrongKeyFormat(t *testing.T) { + plugin := Plugin{ + Config: Config{ + Host: []string{"localhost"}, + User: "drone-scp", + Port: 22, + KeyPath: "./tests/.ssh/id_rsa.pub", + Script: []string{"whoami"}, + }, + } + + err := plugin.Exec() + assert.NotNil(t, err) + assert.Equal(t, sshKeyNotFound, err.Error()) +} + +func TestSSHScriptFromKeyFile(t *testing.T) { + plugin := Plugin{ + Config: Config{ + Host: []string{"localhost"}, + User: "drone-scp", + Port: 22, + KeyPath: "./tests/.ssh/id_rsa", + Script: []string{"whoami"}, + }, + } + + err := plugin.Exec() + assert.Nil(t, err) +}