mirror of https://github.com/docker/docs.git
Allowing generic driver to use ssh-agent to get identities
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
This commit is contained in:
parent
c2ed9e3f1c
commit
cf6136fed0
|
|
@ -33,9 +33,20 @@ Options:
|
||||||
|
|
||||||
Environment variables and default values:
|
Environment variables and default values:
|
||||||
|
|
||||||
| CLI option | Environment variable | Default |
|
| CLI option | Environment variable | Default |
|
||||||
| -------------------------- | -------------------- | ------------------- |
|
|----------------------------|----------------------|---------------------------|
|
||||||
| **`--generic-ip-address`** | `GENERIC_IP_ADDRESS` | - |
|
| **`--generic-ip-address`** | `GENERIC_IP_ADDRESS` | - |
|
||||||
| `--generic-ssh-key` | `GENERIC_SSH_KEY` | `$HOME/.ssh/id_rsa` |
|
| `--generic-ssh-key` | `GENERIC_SSH_KEY` | _(defers to `ssh-agent`)_ |
|
||||||
| `--generic-ssh-user` | `GENERIC_SSH_USER` | `root` |
|
| `--generic-ssh-user` | `GENERIC_SSH_USER` | `root` |
|
||||||
| `--generic-ssh-port` | `GENERIC_SSH_PORT` | `22` |
|
| `--generic-ssh-port` | `GENERIC_SSH_PORT` | `22` |
|
||||||
|
|
||||||
|
##### Interaction with SSH Agents
|
||||||
|
|
||||||
|
When an SSH identity is not provided (with the `--generic-ssh-key` flag),
|
||||||
|
the SSH agent (if running) will be consulted. This makes it possible to
|
||||||
|
easily use password-protected SSH keys.
|
||||||
|
|
||||||
|
Note that this usage is _only_ supported if you're using the external SSH client,
|
||||||
|
which is the default behaviour when the `ssh` binary is available. If you're
|
||||||
|
using the native client (with `--native-ssh`), using the SSH agent is not yet
|
||||||
|
supported.
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -25,10 +24,6 @@ const (
|
||||||
defaultTimeout = 1 * time.Second
|
defaultTimeout = 1 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
defaultSourceSSHKey = filepath.Join(mcnutils.GetHomeDir(), ".ssh", "id_rsa")
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetCreateFlags registers the flags this driver adds to
|
// GetCreateFlags registers the flags this driver adds to
|
||||||
// "docker hosts create"
|
// "docker hosts create"
|
||||||
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
|
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
|
||||||
|
|
@ -46,8 +41,8 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
|
||||||
},
|
},
|
||||||
mcnflag.StringFlag{
|
mcnflag.StringFlag{
|
||||||
Name: "generic-ssh-key",
|
Name: "generic-ssh-key",
|
||||||
Usage: "SSH private key path",
|
Usage: "SSH private key path (if not provided, identities in ssh-agent will be used)",
|
||||||
Value: defaultSourceSSHKey,
|
Value: "",
|
||||||
EnvVar: "GENERIC_SSH_KEY",
|
EnvVar: "GENERIC_SSH_KEY",
|
||||||
},
|
},
|
||||||
mcnflag.IntFlag{
|
mcnflag.IntFlag{
|
||||||
|
|
@ -66,7 +61,6 @@ func NewDriver(hostName, storePath string) drivers.Driver {
|
||||||
MachineName: hostName,
|
MachineName: hostName,
|
||||||
StorePath: storePath,
|
StorePath: storePath,
|
||||||
},
|
},
|
||||||
SSHKey: defaultSourceSSHKey,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,6 +77,17 @@ func (d *Driver) GetSSHUsername() string {
|
||||||
return d.SSHUser
|
return d.SSHUser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Driver) GetSSHKeyPath() string {
|
||||||
|
if d.SSHKey == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.SSHKeyPath == "" {
|
||||||
|
d.SSHKeyPath = d.ResolveStorePath("id_rsa")
|
||||||
|
}
|
||||||
|
return d.SSHKeyPath
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
|
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
|
||||||
d.IPAddress = flags.String("generic-ip-address")
|
d.IPAddress = flags.String("generic-ip-address")
|
||||||
d.SSHUser = flags.String("generic-ssh-user")
|
d.SSHUser = flags.String("generic-ssh-user")
|
||||||
|
|
@ -93,31 +98,33 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
|
||||||
return errors.New("generic driver requires the --generic-ip-address option")
|
return errors.New("generic driver requires the --generic-ip-address option")
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.SSHKey == "" {
|
|
||||||
return errors.New("generic driver requires the --generic-ssh-key option")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) PreCreateCheck() error {
|
func (d *Driver) PreCreateCheck() error {
|
||||||
if _, err := os.Stat(d.SSHKey); os.IsNotExist(err) {
|
if d.SSHKey != "" {
|
||||||
return fmt.Errorf("Ssh key does not exist: %q", d.SSHKey)
|
if _, err := os.Stat(d.SSHKey); os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("Ssh key does not exist: %q", d.SSHKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) Create() error {
|
func (d *Driver) Create() error {
|
||||||
log.Info("Importing SSH key...")
|
if d.SSHKey == "" {
|
||||||
|
log.Info("No SSH key specified. Connecting to this machine now and in the" +
|
||||||
|
" future will require the ssh agent to contain the appropriate key.")
|
||||||
|
} else {
|
||||||
|
log.Info("Importing SSH key...")
|
||||||
|
// TODO: validate the key is a valid key
|
||||||
|
if err := mcnutils.CopyFile(d.SSHKey, d.GetSSHKeyPath()); err != nil {
|
||||||
|
return fmt.Errorf("unable to copy ssh key: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: validate the key is a valid key
|
if err := os.Chmod(d.GetSSHKeyPath(), 0600); err != nil {
|
||||||
if err := mcnutils.CopyFile(d.SSHKey, d.GetSSHKeyPath()); err != nil {
|
return fmt.Errorf("unable to set permissions on the ssh key: %s", err)
|
||||||
return fmt.Errorf("unable to copy ssh key: %s", err)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Chmod(d.GetSSHKeyPath(), 0600); err != nil {
|
|
||||||
return fmt.Errorf("unable to set permissions on the ssh key: %s", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("IP: %s", d.IPAddress)
|
log.Debugf("IP: %s", d.IPAddress)
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,13 @@ func GetSSHClientFromDriver(d Driver) (ssh.Client, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
auth := &ssh.Auth{
|
var auth *ssh.Auth
|
||||||
Keys: []string{d.GetSSHKeyPath()},
|
if d.GetSSHKeyPath() == "" {
|
||||||
|
auth = &ssh.Auth{}
|
||||||
|
} else {
|
||||||
|
auth = &ssh.Auth{
|
||||||
|
Keys: []string{d.GetSSHKeyPath()},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := ssh.NewClient(d.GetSSHUsername(), address, port, auth)
|
client, err := ssh.NewClient(d.GetSSHUsername(), address, port, auth)
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,13 @@ func (h *Host) CreateSSHClient() (ssh.Client, error) {
|
||||||
return ssh.ExternalClient{}, err
|
return ssh.ExternalClient{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
auth := &ssh.Auth{
|
var auth *ssh.Auth
|
||||||
Keys: []string{h.Driver.GetSSHKeyPath()},
|
if h.Driver.GetSSHKeyPath() == "" {
|
||||||
|
auth = &ssh.Auth{}
|
||||||
|
} else {
|
||||||
|
auth = &ssh.Auth{
|
||||||
|
Keys: []string{h.Driver.GetSSHKeyPath()},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ssh.NewClient(h.Driver.GetSSHUsername(), addr, port, auth)
|
return ssh.NewClient(h.Driver.GetSSHUsername(), addr, port, auth)
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@ const (
|
||||||
var (
|
var (
|
||||||
baseSSHArgs = []string{
|
baseSSHArgs = []string{
|
||||||
"-o", "PasswordAuthentication=no",
|
"-o", "PasswordAuthentication=no",
|
||||||
"-o", "IdentitiesOnly=yes",
|
|
||||||
"-o", "StrictHostKeyChecking=no",
|
"-o", "StrictHostKeyChecking=no",
|
||||||
"-o", "UserKnownHostsFile=/dev/null",
|
"-o", "UserKnownHostsFile=/dev/null",
|
||||||
"-o", "LogLevel=quiet", // suppress "Warning: Permanently added '[localhost]:2022' (ECDSA) to the list of known hosts."
|
"-o", "LogLevel=quiet", // suppress "Warning: Permanently added '[localhost]:2022' (ECDSA) to the list of known hosts."
|
||||||
|
|
@ -262,9 +261,17 @@ func NewExternalClient(sshBinaryPath, user, host string, port int, auth *Auth) (
|
||||||
|
|
||||||
args := append(baseSSHArgs, fmt.Sprintf("%s@%s", user, host))
|
args := append(baseSSHArgs, fmt.Sprintf("%s@%s", user, host))
|
||||||
|
|
||||||
|
// If no identities are explicitly provided, also look at the identities
|
||||||
|
// offered by ssh-agent
|
||||||
|
if len(auth.Keys) > 0 {
|
||||||
|
args = append(args, "-o", "IdentitiesOnly=yes")
|
||||||
|
}
|
||||||
|
|
||||||
// Specify which private keys to use to authorize the SSH request.
|
// Specify which private keys to use to authorize the SSH request.
|
||||||
for _, privateKeyPath := range auth.Keys {
|
for _, privateKeyPath := range auth.Keys {
|
||||||
args = append(args, "-i", privateKeyPath)
|
if privateKeyPath != "" {
|
||||||
|
args = append(args, "-i", privateKeyPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set which port to use for SSH.
|
// Set which port to use for SSH.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue