Merge pull request #1208 from tarrant/master

Add support for SSH Agent
This commit is contained in:
Mitchell Hashimoto 2015-04-01 22:54:50 -07:00
commit 8ee6a03748
5 changed files with 52 additions and 5 deletions

View File

@ -60,6 +60,7 @@ func (p *ResourceProvisioner) copyFiles(conf *helper.SSHConfig, src, dst string)
if err != nil { if err != nil {
return err return err
} }
defer config.CleanupConfig()
// Wait and retry until we establish the SSH connection // Wait and retry until we establish the SSH connection
var comm *helper.SSHCommunicator var comm *helper.SSHCommunicator

View File

@ -172,16 +172,20 @@ func (p *ResourceProvisioner) runScripts(
if err != nil { if err != nil {
return err return err
} }
defer config.CleanupConfig()
o.Output(fmt.Sprintf( o.Output(fmt.Sprintf(
"Connecting to remote host via SSH...\n"+ "Connecting to remote host via SSH...\n"+
" Host: %s\n"+ " Host: %s\n"+
" User: %s\n"+ " User: %s\n"+
" Password: %v\n"+ " Password: %v\n"+
" Private key: %v", " Private key: %v"+
" SSH Agent: %v",
conf.Host, conf.User, conf.Host, conf.User,
conf.Password != "", conf.Password != "",
conf.KeyFile != "")) conf.KeyFile != "",
conf.Agent,
))
// Wait and retry until we establish the SSH connection // Wait and retry until we establish the SSH connection
var comm *helper.SSHCommunicator var comm *helper.SSHCommunicator

View File

@ -97,6 +97,10 @@ type Config struct {
// NoPty, if true, will not request a pty from the remote end. // NoPty, if true, will not request a pty from the remote end.
NoPty bool NoPty bool
// SSHAgentConn is a pointer to the UNIX connection for talking with the
// ssh-agent.
SSHAgentConn net.Conn
} }
// New creates a new packer.Communicator implementation over SSH. This takes // New creates a new packer.Communicator implementation over SSH. This takes

View File

@ -5,12 +5,15 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"net"
"os"
"time" "time"
"golang.org/x/crypto/ssh"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
) )
const ( const (
@ -37,6 +40,7 @@ type SSHConfig struct {
KeyFile string `mapstructure:"key_file"` KeyFile string `mapstructure:"key_file"`
Host string Host string
Port int Port int
Agent bool
Timeout string Timeout string
ScriptPath string `mapstructure:"script_path"` ScriptPath string `mapstructure:"script_path"`
TimeoutVal time.Duration `mapstructure:"-"` TimeoutVal time.Duration `mapstructure:"-"`
@ -99,9 +103,32 @@ func safeDuration(dur string, defaultDur time.Duration) time.Duration {
// PrepareConfig is used to turn the *SSHConfig provided into a // PrepareConfig is used to turn the *SSHConfig provided into a
// usable *Config for client initialization. // usable *Config for client initialization.
func PrepareConfig(conf *SSHConfig) (*Config, error) { func PrepareConfig(conf *SSHConfig) (*Config, error) {
var conn net.Conn
var err error
sshConf := &ssh.ClientConfig{ sshConf := &ssh.ClientConfig{
User: conf.User, User: conf.User,
} }
if conf.Agent {
sshAuthSock := os.Getenv("SSH_AUTH_SOCK")
if sshAuthSock == "" {
return nil, fmt.Errorf("SSH Requested but SSH_AUTH_SOCK not-specified")
}
conn, err = net.Dial("unix", sshAuthSock)
if err != nil {
return nil, fmt.Errorf("Error connecting to SSH_AUTH_SOCK: %v", err)
}
// I need to close this but, later after all connections have been made
// defer conn.Close()
signers, err := agent.NewClient(conn).Signers()
if err != nil {
return nil, fmt.Errorf("Error getting keys from ssh agent: %v", err)
}
sshConf.Auth = append(sshConf.Auth, ssh.PublicKeys(signers...))
}
if conf.KeyFile != "" { if conf.KeyFile != "" {
fullPath, err := homedir.Expand(conf.KeyFile) fullPath, err := homedir.Expand(conf.KeyFile)
if err != nil { if err != nil {
@ -140,8 +167,17 @@ func PrepareConfig(conf *SSHConfig) (*Config, error) {
} }
host := fmt.Sprintf("%s:%d", conf.Host, conf.Port) host := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
config := &Config{ config := &Config{
SSHConfig: sshConf, SSHConfig: sshConf,
Connection: ConnectFunc("tcp", host), Connection: ConnectFunc("tcp", host),
SSHAgentConn: conn,
} }
return config, nil return config, nil
} }
func (c *Config) CleanupConfig() error {
if c.SSHAgentConn != nil {
return c.SSHAgentConn.Close()
}
return nil
}

View File

@ -46,6 +46,8 @@ The following arguments are supported:
* `key_file` - The SSH key to use for the connection. This takes preference over the * `key_file` - The SSH key to use for the connection. This takes preference over the
password if provided. password if provided.
* `agent` - Set to true to enable using ssh-agent to authenticate.
* `host` - The address of the resource to connect to. This is provided by the provider. * `host` - The address of the resource to connect to. This is provided by the provider.
* `port` - The port to connect to. This defaults to 22. * `port` - The port to connect to. This defaults to 22.