Merge pull request #4050 from jen20/ssh-agent

builder/amazon: Allow use of local SSH Agent
pull/4099/head
Matthew Hooker 10 years ago committed by GitHub
commit 970b37077e

@ -3,12 +3,15 @@ package common
import ( import (
"errors" "errors"
"fmt" "fmt"
"net"
"os"
"time" "time"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
packerssh "github.com/mitchellh/packer/communicator/ssh" packerssh "github.com/mitchellh/packer/communicator/ssh"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
) )
type ec2Describer interface { type ec2Describer interface {
@ -67,8 +70,26 @@ func SSHHost(e ec2Describer, private bool) func(multistep.StateBag) (string, err
// SSHConfig returns a function that can be used for the SSH communicator // SSHConfig returns a function that can be used for the SSH communicator
// config for connecting to the instance created over SSH using the private key // config for connecting to the instance created over SSH using the private key
// or password. // or password.
func SSHConfig(username, password string) func(multistep.StateBag) (*ssh.ClientConfig, error) { func SSHConfig(useAgent bool, username, password string) func(multistep.StateBag) (*ssh.ClientConfig, error) {
return func(state multistep.StateBag) (*ssh.ClientConfig, error) { return func(state multistep.StateBag) (*ssh.ClientConfig, error) {
if useAgent {
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)
}
return &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers),
},
}, nil
}
privateKey, hasKey := state.GetOk("privateKey") privateKey, hasKey := state.GetOk("privateKey")
if hasKey { if hasKey {

@ -13,6 +13,7 @@ import (
type StepKeyPair struct { type StepKeyPair struct {
Debug bool Debug bool
SSHAgentAuth bool
DebugKeyPath string DebugKeyPath string
TemporaryKeyPairName string TemporaryKeyPairName string
KeyPairName string KeyPairName string
@ -25,7 +26,7 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
if s.PrivateKeyFile != "" { if s.PrivateKeyFile != "" {
ui.Say("Using existing ssh private key") ui.Say("Using existing SSH private key")
privateKeyBytes, err := ioutil.ReadFile(s.PrivateKeyFile) privateKeyBytes, err := ioutil.ReadFile(s.PrivateKeyFile)
if err != nil { if err != nil {
state.Put("error", fmt.Errorf( state.Put("error", fmt.Errorf(
@ -39,6 +40,17 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
if s.SSHAgentAuth && s.KeyPairName == "" {
ui.Say("Using SSH Agent with key pair in Source AMI")
return multistep.ActionContinue
}
if s.SSHAgentAuth && s.KeyPairName != "" {
ui.Say(fmt.Sprintf("Using SSH Agent for existing key pair %s", s.KeyPairName))
state.Put("keyPair", s.KeyPairName)
return multistep.ActionContinue
}
if s.TemporaryKeyPairName == "" { if s.TemporaryKeyPairName == "" {
ui.Say("Not using temporary keypair") ui.Say("Not using temporary keypair")
state.Put("keyPair", "") state.Put("keyPair", "")

@ -149,6 +149,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
ec2conn, ec2conn,
b.config.SSHPrivateIp), b.config.SSHPrivateIp),
SSHConfig: awscommon.SSHConfig( SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername, b.config.RunConfig.Comm.SSHUsername,
b.config.RunConfig.Comm.SSHPassword), b.config.RunConfig.Comm.SSHPassword),
}, },

@ -231,6 +231,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
ec2conn, ec2conn,
b.config.SSHPrivateIp), b.config.SSHPrivateIp),
SSHConfig: awscommon.SSHConfig( SSHConfig: awscommon.SSHConfig(
b.config.RunConfig.Comm.SSHAgentAuth,
b.config.RunConfig.Comm.SSHUsername, b.config.RunConfig.Comm.SSHUsername,
b.config.RunConfig.Comm.SSHPassword), b.config.RunConfig.Comm.SSHPassword),
}, },

@ -23,6 +23,7 @@ type Config struct {
SSHPrivateKey string `mapstructure:"ssh_private_key_file"` SSHPrivateKey string `mapstructure:"ssh_private_key_file"`
SSHPty bool `mapstructure:"ssh_pty"` SSHPty bool `mapstructure:"ssh_pty"`
SSHTimeout time.Duration `mapstructure:"ssh_timeout"` SSHTimeout time.Duration `mapstructure:"ssh_timeout"`
SSHAgentAuth bool `mapstructure:"ssh_agent_auth"`
SSHDisableAgent bool `mapstructure:"ssh_disable_agent"` SSHDisableAgent bool `mapstructure:"ssh_disable_agent"`
SSHHandshakeAttempts int `mapstructure:"ssh_handshake_attempts"` SSHHandshakeAttempts int `mapstructure:"ssh_handshake_attempts"`
SSHBastionHost string `mapstructure:"ssh_bastion_host"` SSHBastionHost string `mapstructure:"ssh_bastion_host"`

@ -217,11 +217,20 @@ builder.
`Linux/UNIX (Amazon VPC)`, `SUSE Linux (Amazon VPC)`, `Windows (Amazon VPC)` `Linux/UNIX (Amazon VPC)`, `SUSE Linux (Amazon VPC)`, `Windows (Amazon VPC)`
- `ssh_keypair_name` (string) - If specified, this is the key that will be - `ssh_keypair_name` (string) - If specified, this is the key that will be
used for SSH with the machine. By default, this is blank, and Packer will used for SSH with the machine. The key must match a key pair name loaded
up into Amazon EC2. By default, this is blank, and Packer will
generate a temporary keypair unless generate a temporary keypair unless
[`ssh_password`](/docs/templates/communicator.html#ssh_password) is used. [`ssh_password`](/docs/templates/communicator.html#ssh_password) is used.
[`ssh_private_key_file`](/docs/templates/communicator.html#ssh_private_key_file) [`ssh_private_key_file`](/docs/templates/communicator.html#ssh_private_key_file)
must be specified with this. or `ssh_agent_auth` must be specified when `ssh_keypair_name` is utilized.
- `ssh_agent_auth` (boolean) - If true, the local SSH agent will be used to
authenticate connections to the source instance. No temporary keypair will
be created, and the values of `ssh_password` and `ssh_private_key_file` will
be ignored. To use this option with a key pair already configured in the source
AMI, leave the `ssh_keypair_name` blank. To associate an existing key pair
in AWS with the source instance, set the `ssh_keypair_name` field to the name
of the key pair.
- `ssh_private_ip` (boolean) - If true, then SSH will always use the private - `ssh_private_ip` (boolean) - If true, then SSH will always use the private
IP if available. IP if available.

@ -238,8 +238,16 @@ builder.
generate a temporary keypair unless generate a temporary keypair unless
[`ssh_password`](/docs/templates/communicator.html#ssh_password) is used. [`ssh_password`](/docs/templates/communicator.html#ssh_password) is used.
[`ssh_private_key_file`](/docs/templates/communicator.html#ssh_private_key_file) [`ssh_private_key_file`](/docs/templates/communicator.html#ssh_private_key_file)
must be specified when `ssh_keypair_name` is utilized. or `ssh_agent_auth` must be specified when `ssh_keypair_name` is utilized.
- `ssh_agent_auth` (boolean) - If true, the local SSH agent will be used to
authenticate connections to the source instance. No temporary keypair will
be created, and the values of `ssh_password` and `ssh_private_key_file` will
be ignored. To use this option with a key pair already configured in the source
AMI, leave the `ssh_keypair_name` blank. To associate an existing key pair
in AWS with the source instance, set the `ssh_keypair_name` field to the name
of the key pair.
- `ssh_private_ip` (boolean) - If true, then SSH will always use the private - `ssh_private_ip` (boolean) - If true, then SSH will always use the private
IP if available. IP if available.

Loading…
Cancel
Save