Correct error handling for external SSH client

In some cases, (e.g. private key not accessible or has incorrect
permissions) docker-machine failed with error "Something went wrong
running an SSH command!". This commit will add the correct debug
messages and show the correct errors for the bad private keys.
Also, due to incorrect handling POSIX file permissions in Windows
some checks should be ignored.

Signed-off-by: Maksim Malchuk <maksim.malchuk@gmail.com>
This commit is contained in:
Maksim Malchuk 2016-04-12 11:43:18 +03:00
parent bcc976ac79
commit be8f469a82
2 changed files with 55 additions and 0 deletions

View File

@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"os/exec"
"runtime"
"strings"
"github.com/docker/docker/pkg/term"
@ -322,6 +323,21 @@ func NewExternalClient(sshBinaryPath, user, host string, port int, auth *Auth) (
// Specify which private keys to use to authorize the SSH request.
for _, privateKeyPath := range auth.Keys {
if privateKeyPath != "" {
// Check each private key before use it
fi, err := os.Stat(privateKeyPath)
if err != nil {
// Abort if key not accessible
return nil, err
}
if runtime.GOOS != "windows" {
mode := fi.Mode()
log.Debugf("Using SSH private key: %s (%s)", privateKeyPath, mode)
// Private key file should have strict permissions
if mode != 0600 {
// Abort with correct message
return nil, fmt.Errorf("Permissions %#o for '%s' are too open.", mode, privateKeyPath)
}
}
args = append(args, "-i", privateKeyPath)
}
}

View File

@ -1,6 +1,7 @@
package ssh
import (
"runtime"
"testing"
"github.com/stretchr/testify/assert"
@ -43,3 +44,41 @@ func TestGetSSHCmdArgs(t *testing.T) {
assert.Equal(t, cmd.Args, c.expectedArgs)
}
}
func TestNewExternalClient(t *testing.T) {
cases := []struct {
sshBinaryPath string
user string
host string
port int
auth *Auth
expectedError string
skipOS string
}{
{
sshBinaryPath: "/usr/local/bin/ssh",
user: "docker",
host: "localhost",
port: 22,
auth: &Auth{Keys: []string{"/tmp/private-key-not-exist"}},
expectedError: "stat /tmp/private-key-not-exist: no such file or directory",
skipOS: "none",
},
{
sshBinaryPath: "/usr/local/bin/ssh",
user: "docker",
host: "localhost",
port: 22,
auth: &Auth{Keys: []string{"/dev/null"}},
expectedError: "Permissions 0410000666 for '/dev/null' are too open.",
skipOS: "windows",
},
}
for _, c := range cases {
if runtime.GOOS != c.skipOS {
_, err := NewExternalClient(c.sshBinaryPath, c.user, c.host, c.port, c.auth)
assert.EqualError(t, err, c.expectedError)
}
}
}