Merge pull request #4050 from jen20/ssh-agent

builder/amazon: Allow use of local SSH Agent
This commit is contained in:
Matthew Hooker 2016-11-01 17:27:37 -07:00 committed by GitHub
commit 970b37077e
7 changed files with 58 additions and 5 deletions

View File

@ -3,12 +3,15 @@ package common
import (
"errors"
"fmt"
"net"
"os"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep"
packerssh "github.com/mitchellh/packer/communicator/ssh"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
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
// config for connecting to the instance created over SSH using the private key
// 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) {
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")
if hasKey {

View File

@ -13,6 +13,7 @@ import (
type StepKeyPair struct {
Debug bool
SSHAgentAuth bool
DebugKeyPath string
TemporaryKeyPairName string
KeyPairName string
@ -25,7 +26,7 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
if s.PrivateKeyFile != "" {
ui.Say("Using existing ssh private key")
ui.Say("Using existing SSH private key")
privateKeyBytes, err := ioutil.ReadFile(s.PrivateKeyFile)
if err != nil {
state.Put("error", fmt.Errorf(
@ -39,6 +40,17 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
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 == "" {
ui.Say("Not using temporary keypair")
state.Put("keyPair", "")

View File

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

View File

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

View File

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

View File

@ -217,11 +217,20 @@ builder.
`Linux/UNIX (Amazon VPC)`, `SUSE Linux (Amazon VPC)`, `Windows (Amazon VPC)`
- `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
[`ssh_password`](/docs/templates/communicator.html#ssh_password) is used.
[`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
IP if available.

View File

@ -238,8 +238,16 @@ builder.
generate a temporary keypair unless
[`ssh_password`](/docs/templates/communicator.html#ssh_password) is used.
[`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
IP if available.