builder/amazon: Allow use of local SSH Agent

This commit adds an option to use the local SSH Agent to authenticate
connections to source instances started by the the EBS and Instance
Store builders.

This is of use when the source AMI _already_ has configuration for
authorized SSH keys - for example if one uses an SSH certificate
authority.

A further extension (not implemented in this commit) is to allow SSH
agent use with a pre-defined key pair, in order to allow keys with
passphrases to be used without giving the passphrase to Packer.
This commit is contained in:
James Nugent 2016-10-23 21:43:47 -05:00
parent 8e7f3778b2
commit 7425fef2c7
7 changed files with 43 additions and 1 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
@ -24,6 +25,11 @@ type StepKeyPair struct {
func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
if s.SSHAgentAuth {
ui.Say("Using SSH Agent")
return multistep.ActionContinue
}
if s.PrivateKeyFile != "" {
ui.Say("Using existing ssh private key")
privateKeyBytes, err := ioutil.ReadFile(s.PrivateKeyFile)

View File

@ -148,6 +148,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

@ -230,6 +230,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

@ -194,6 +194,12 @@ builder.
[`ssh_private_key_file`](/docs/templates/communicator.html#ssh_private_key_file)
must be specified with this.
- `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. This is suitable for use if the source AMI already has authorized
keys configured.
- `ssh_private_ip` (boolean) - If true, then SSH will always use the private
IP if available.

View File

@ -212,6 +212,12 @@ builder.
[`ssh_private_key_file`](/docs/templates/communicator.html#ssh_private_key_file)
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. This is suitable for use if the source AMI already has authorized
keys configured.
- `ssh_private_ip` (boolean) - If true, then SSH will always use the private
IP if available.