Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

builder/amazon: Allow using ssh_private_key_file and ssh_password #3953

Merged
merged 3 commits into from
Oct 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions builder/amazon/common/run_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ type RunConfig struct {
}

func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
// If we are not given an explicit ssh_keypair_name,
// then create a temporary one, but only if the
// temporary_key_pair_name has not been provided.
if c.SSHKeyPairName == "" {
if c.TemporaryKeyPairName == "" {
c.TemporaryKeyPairName = fmt.Sprintf(
"packer_%s", uuid.TimeOrderedUUID())
}
// If we are not given an explicit ssh_keypair_name or
// ssh_private_key_file, then create a temporary one, but only if the
// temporary_key_pair_name has not been provided and we are not using
// ssh_password.
if c.SSHKeyPairName == "" && c.TemporaryKeyPairName == "" &&
c.Comm.SSHPrivateKey == "" && c.Comm.SSHPassword == "" {

c.TemporaryKeyPairName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
}

if c.WindowsPasswordTimeout == 0 {
Expand Down
40 changes: 26 additions & 14 deletions builder/amazon/common/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/aws/aws-sdk-go/service/ec2"
"github.com/mitchellh/multistep"
packerssh "github.com/mitchellh/packer/communicator/ssh"
"golang.org/x/crypto/ssh"
)

Expand Down Expand Up @@ -64,22 +65,33 @@ 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 generated
// private key.
func SSHConfig(username string) func(multistep.StateBag) (*ssh.ClientConfig, error) {
// 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) {
return func(state multistep.StateBag) (*ssh.ClientConfig, error) {
privateKey := state.Get("privateKey").(string)

signer, err := ssh.ParsePrivateKey([]byte(privateKey))
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
privateKey, hasKey := state.GetOk("privateKey")
if hasKey {

return &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
}, nil
signer, err := ssh.ParsePrivateKey([]byte(privateKey.(string)))
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
return &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
}, nil

} else {
return &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.Password(password),
ssh.KeyboardInteractive(
packerssh.PasswordKeyboardInteractive(password)),
}}, nil
}
}
}
12 changes: 10 additions & 2 deletions builder/amazon/common/step_key_pair.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ type StepKeyPair struct {
}

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")
privateKeyBytes, err := ioutil.ReadFile(s.PrivateKeyFile)
if err != nil {
state.Put("error", fmt.Errorf(
Expand All @@ -36,8 +39,13 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue
}

if s.TemporaryKeyPairName == "" {
ui.Say("Not using temporary keypair")
state.Put("keyPair", "")
return multistep.ActionContinue
}

ec2conn := state.Get("ec2").(*ec2.EC2)
ui := state.Get("ui").(packer.Ui)

ui.Say(fmt.Sprintf("Creating temporary keypair: %s", s.TemporaryKeyPairName))
keyResp, err := ec2conn.CreateKeyPair(&ec2.CreateKeyPairInput{
Expand Down Expand Up @@ -87,7 +95,7 @@ func (s *StepKeyPair) Cleanup(state multistep.StateBag) {
// If no key name is set, then we never created it, so just return
// If we used an SSH private key file, do not go about deleting
// keypairs
if s.PrivateKeyFile != "" {
if s.PrivateKeyFile != "" || s.KeyPairName == "" {
return
}

Expand Down
53 changes: 31 additions & 22 deletions builder/amazon/common/step_run_source_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi

if spotPrice == "" || spotPrice == "0" {
runOpts := &ec2.RunInstancesInput{
KeyName: &keyName,
ImageId: &s.SourceAMI,
InstanceType: &s.InstanceType,
UserData: &userData,
Expand All @@ -172,6 +171,10 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
EbsOptimized: &s.EbsOptimized,
}

if keyName != "" {
runOpts.KeyName = &keyName
}

if s.SubnetId != "" && s.AssociatePublicIpAddress {
runOpts.NetworkInterfaces = []*ec2.InstanceNetworkInterfaceSpecification{
&ec2.InstanceNetworkInterfaceSpecification{
Expand Down Expand Up @@ -203,29 +206,35 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
ui.Message(fmt.Sprintf(
"Requesting spot instance '%s' for: %s",
s.InstanceType, spotPrice))
runSpotResp, err := ec2conn.RequestSpotInstances(&ec2.RequestSpotInstancesInput{
SpotPrice: &spotPrice,
LaunchSpecification: &ec2.RequestSpotLaunchSpecification{
KeyName: &keyName,
ImageId: &s.SourceAMI,
InstanceType: &s.InstanceType,
UserData: &userData,
IamInstanceProfile: &ec2.IamInstanceProfileSpecification{Name: &s.IamInstanceProfile},
NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{
&ec2.InstanceNetworkInterfaceSpecification{
DeviceIndex: aws.Int64(0),
AssociatePublicIpAddress: &s.AssociatePublicIpAddress,
SubnetId: &s.SubnetId,
Groups: securityGroupIds,
DeleteOnTermination: aws.Bool(true),
},
},
Placement: &ec2.SpotPlacement{
AvailabilityZone: &availabilityZone,

runOpts := &ec2.RequestSpotLaunchSpecification{
ImageId: &s.SourceAMI,
InstanceType: &s.InstanceType,
UserData: &userData,
IamInstanceProfile: &ec2.IamInstanceProfileSpecification{Name: &s.IamInstanceProfile},
NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{
&ec2.InstanceNetworkInterfaceSpecification{
DeviceIndex: aws.Int64(0),
AssociatePublicIpAddress: &s.AssociatePublicIpAddress,
SubnetId: &s.SubnetId,
Groups: securityGroupIds,
DeleteOnTermination: aws.Bool(true),
},
BlockDeviceMappings: s.BlockDevices.BuildLaunchDevices(),
EbsOptimized: &s.EbsOptimized,
},
Placement: &ec2.SpotPlacement{
AvailabilityZone: &availabilityZone,
},
BlockDeviceMappings: s.BlockDevices.BuildLaunchDevices(),
EbsOptimized: &s.EbsOptimized,
}

if keyName != "" {
runOpts.KeyName = &keyName
}

runSpotResp, err := ec2conn.RequestSpotInstances(&ec2.RequestSpotInstancesInput{
SpotPrice: &spotPrice,
LaunchSpecification: runOpts,
})
if err != nil {
err := fmt.Errorf("Error launching source spot instance: %s", err)
Expand Down
3 changes: 2 additions & 1 deletion builder/amazon/ebs/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ 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.SSHUsername),
b.config.RunConfig.Comm.SSHUsername,
b.config.RunConfig.Comm.SSHPassword),
},
&common.StepProvision{},
&stepStopInstance{
Expand Down
3 changes: 2 additions & 1 deletion builder/amazon/instance/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ 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.SSHUsername),
b.config.RunConfig.Comm.SSHUsername,
b.config.RunConfig.Comm.SSHPassword),
},
&common.StepProvision{},
&StepUploadX509Cert{},
Expand Down
6 changes: 2 additions & 4 deletions website/source/docs/builders/amazon-ebs.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ builder.
- `source_ami` (string) - The initial AMI used as a base for the newly
created machine.

- `ssh_username` (string) - The username to use in order to communicate over
SSH to the running machine.

### Optional:

- `ami_block_device_mappings` (array of block device mappings) - Add the block
Expand Down Expand Up @@ -188,7 +185,8 @@ builder.

- `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
generate a temporary keypair.
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.

Expand Down
6 changes: 2 additions & 4 deletions website/source/docs/builders/amazon-instance.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ builder.
- `source_ami` (string) - The initial AMI used as a base for the newly
created machine.

- `ssh_username` (string) - The username to use in order to communicate over
SSH to the running machine.

- `x509_cert_path` (string) - The local path to a valid X509 certificate for
your AWS account. This is used for bundling the AMI. This X509 certificate
must be registered with your account from the security credentials page in
Expand Down Expand Up @@ -210,7 +207,8 @@ builder.
- `ssh_keypair_name` (string) - If specified, this is the key that will be
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.
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.

Expand Down