From 2164700162f0d636283dde8ecfff55547cf637a0 Mon Sep 17 00:00:00 2001 From: Rickard von Essen Date: Sun, 28 May 2017 14:05:03 +0200 Subject: [PATCH] comm/ssh: Add support for using SSH Agent auth towards a bastion host. Adds `ssh_bastion_agent_auth` Fixes: #4732 --- helper/communicator/config.go | 3 ++- helper/communicator/step_connect_ssh.go | 16 ++++++++++++++++ .../source/docs/templates/communicator.html.md | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/helper/communicator/config.go b/helper/communicator/config.go index 560b061b7..052cfe2ee 100644 --- a/helper/communicator/config.go +++ b/helper/communicator/config.go @@ -28,6 +28,7 @@ type Config struct { SSHHandshakeAttempts int `mapstructure:"ssh_handshake_attempts"` SSHBastionHost string `mapstructure:"ssh_bastion_host"` SSHBastionPort int `mapstructure:"ssh_bastion_port"` + SSHBastionAgentAuth bool `mapstructure:"ssh_bastion_agent_auth"` SSHBastionUsername string `mapstructure:"ssh_bastion_username"` SSHBastionPassword string `mapstructure:"ssh_bastion_password"` SSHBastionPrivateKey string `mapstructure:"ssh_bastion_private_key_file"` @@ -159,7 +160,7 @@ func (c *Config) prepareSSH(ctx *interpolate.Context) []error { } } - if c.SSHBastionHost != "" { + if c.SSHBastionHost != "" && !c.SSHBastionAgentAuth { if c.SSHBastionPassword == "" && c.SSHBastionPrivateKey == "" { errs = append(errs, errors.New( "ssh_bastion_password or ssh_bastion_private_key_file must be specified")) diff --git a/helper/communicator/step_connect_ssh.go b/helper/communicator/step_connect_ssh.go index f3f5c5bdb..ec9ab2184 100644 --- a/helper/communicator/step_connect_ssh.go +++ b/helper/communicator/step_connect_ssh.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "net" + "os" "strings" "time" @@ -13,6 +14,7 @@ import ( "github.com/hashicorp/packer/packer" "github.com/mitchellh/multistep" gossh "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/agent" ) // StepConnectSSH is a step that only connects to SSH. @@ -213,6 +215,20 @@ func sshBastionConfig(config *Config) (*gossh.ClientConfig, error) { auth = append(auth, gossh.PublicKeys(signer)) } + if config.SSHBastionAgentAuth { + authSock := os.Getenv("SSH_AUTH_SOCK") + if authSock == "" { + return nil, fmt.Errorf("SSH_AUTH_SOCK is not set") + } + + sshAgent, err := net.Dial("unix", authSock) + if err != nil { + return nil, fmt.Errorf("Cannot connect to SSH Agent socket %q: %s", authSock, err) + } + + auth = append(auth, gossh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)) + } + return &gossh.ClientConfig{ User: config.SSHBastionUsername, Auth: auth, diff --git a/website/source/docs/templates/communicator.html.md b/website/source/docs/templates/communicator.html.md index f95768ce6..470fdefe9 100644 --- a/website/source/docs/templates/communicator.html.md +++ b/website/source/docs/templates/communicator.html.md @@ -58,6 +58,9 @@ the SSH agent to the remote host. The SSH communicator has the following options: +- `ssh_bastion_agent_auth` (boolean) - If true, the local SSH agent will + be used to authenticate with the bastion host. Defaults to false. + - `ssh_bastion_host` (string) - A bastion host to use for the actual SSH connection.