From b2f8eb68e8f431f803531a87821a3238faf821dc Mon Sep 17 00:00:00 2001 From: Mark Peek Date: Sat, 13 Jun 2015 17:15:49 -0700 Subject: [PATCH] Enable ssh agent forwarding #1066 --- CHANGELOG.md | 2 + communicator/ssh/communicator.go | 50 +++++++++++++++++++ .../docs/provisioners/shell.html.markdown | 27 ++++++++++ 3 files changed, 79 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4391393d0..9e26c7818 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ FEATURES: being built. This should be used for template-relative paths. [GH-54] * **Disable SSH:** Set `communicator` to "none" in any builder to disable SSH connections. Note that provisioners won't work if this is done. [GH-1591] + * **SSH Agent Forwarding:** SSH Agent Forwarding will now be enabled + to allow access to remote servers such as private git repos. [GH-1066] IMPROVEMENTS: diff --git a/communicator/ssh/communicator.go b/communicator/ssh/communicator.go index 217afc940..193ecae42 100644 --- a/communicator/ssh/communicator.go +++ b/communicator/ssh/communicator.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/mitchellh/packer/packer" "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/agent" "io" "io/ioutil" "log" @@ -226,10 +227,59 @@ func (c *comm) reconnect() (err error) { if sshConn != nil { c.client = ssh.NewClient(sshConn, sshChan, req) } + c.connectToAgent() return } +func (c *comm) connectToAgent() { + if c.client == nil { + return + } + + // open connection to the local agent + socketLocation := os.Getenv("SSH_AUTH_SOCK") + if socketLocation == "" { + log.Printf("no local agent socket") + return + } + agentConn, err := net.Dial("unix", socketLocation) + if err != nil { + log.Printf("could not connect to local agent socket: %s", socketLocation) + return + } + + // create agent and add in auth + forwardingAgent := agent.NewClient(agentConn) + if forwardingAgent == nil { + log.Printf("could not create agent client") + agentConn.Close() + return + } + + // add callback for forwarding agent to SSH config + // XXX - might want to handle reconnects appending multiple callbacks + auth := ssh.PublicKeysCallback(forwardingAgent.Signers) + c.config.SSHConfig.Auth = append(c.config.SSHConfig.Auth, auth) + agent.ForwardToAgent(c.client, forwardingAgent) + + // Setup a session to request agent forwarding + session, err := c.newSession() + if err != nil { + return + } + defer session.Close() + + err = agent.RequestAgentForwarding(session) + if err != nil { + log.Printf("RequestAgentForwarding:", err) + return + } + + log.Printf("agent forwarding enabled") + return +} + func (c *comm) scpSession(scpCommand string, f func(io.Writer, *bufio.Reader) error) error { session, err := c.newSession() if err != nil { diff --git a/website/source/docs/provisioners/shell.html.markdown b/website/source/docs/provisioners/shell.html.markdown index e57910cb0..89a442a83 100644 --- a/website/source/docs/provisioners/shell.html.markdown +++ b/website/source/docs/provisioners/shell.html.markdown @@ -146,6 +146,33 @@ on reboot or in your shell script. For example, on Gentoo: /etc/init.d/net.eth0 stop ``` +## SSH Agent Forwarding + +Some provisioning requires connecting to remote SSH servers from within the +packer instance. The below example is for pulling code from a private git +repository utilizing openssh on the client. Make sure you are running +`ssh-agent` and add your git repo ssh keys into it using `ssh-add /path/to/key`. +When the packer instance needs access to the ssh keys the agent will forward +the request back to your `ssh-agent`. + +Note: when provisioning via git you should add the git server keys into +the `~/.ssh/known_hosts` file otherwise the git command could hang awaiting +input. This can be done by copying the file in via the +[file provisioner](/docs/provisioners/file.html) (more secure) +or using `ssh-keyscan` to populate the file (less secure). An example of the +latter accessing github would be: + +``` +{ + "type": "shell", + "inline": [ + "sudo apt-get install -y git", + "ssh-keyscan github.com >> ~/.ssh/known_hosts", + "git clone git@github.com:exampleorg/myprivaterepo.git" + ] +} +``` + ## Troubleshooting *My shell script doesn't work correctly on Ubuntu*