Merge pull request #6946 from gmmephisto/pr-master-expand-user

communicator/ssh: expand user path for SSH private key
This commit is contained in:
Adrien Delorme 2018-11-08 13:07:44 +01:00 committed by GitHub
commit 662fbf127b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 74 additions and 43 deletions

View File

@ -3,7 +3,6 @@ package ecs
import (
"context"
"fmt"
"io/ioutil"
"os"
"runtime"
@ -28,10 +27,9 @@ func (s *stepConfigAlicloudKeyPair) Run(_ context.Context, state multistep.State
if s.Comm.SSHPrivateKeyFile != "" {
ui.Say("Using existing SSH private key")
privateKeyBytes, err := ioutil.ReadFile(s.Comm.SSHPrivateKeyFile)
privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile()
if err != nil {
state.Put("error", fmt.Errorf(
"Error loading configured private key file: %s", err))
state.Put("error", err)
return multistep.ActionHalt
}

View File

@ -3,7 +3,6 @@ package common
import (
"context"
"fmt"
"io/ioutil"
"os"
"runtime"
@ -26,10 +25,9 @@ func (s *StepKeyPair) Run(_ context.Context, state multistep.StateBag) multistep
if s.Comm.SSHPrivateKeyFile != "" {
ui.Say("Using existing SSH private key")
privateKeyBytes, err := ioutil.ReadFile(s.Comm.SSHPrivateKeyFile)
privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile()
if err != nil {
state.Put("error", fmt.Errorf(
"Error loading configured private key file: %s", err))
state.Put("error", err)
return multistep.ActionHalt
}

View File

@ -326,7 +326,7 @@ func setSshValues(c *Config) error {
}
if c.Comm.SSHPrivateKeyFile != "" {
privateKeyBytes, err := ioutil.ReadFile(c.Comm.SSHPrivateKeyFile)
privateKeyBytes, err := c.Comm.ReadSSHPrivateKeyFile()
if err != nil {
return err
}

View File

@ -3,7 +3,6 @@ package cloudstack
import (
"context"
"fmt"
"io/ioutil"
"os"
"runtime"
@ -23,10 +22,10 @@ func (s *stepKeypair) Run(_ context.Context, state multistep.StateBag) multistep
ui := state.Get("ui").(packer.Ui)
if s.Comm.SSHPrivateKeyFile != "" {
privateKeyBytes, err := ioutil.ReadFile(s.Comm.SSHPrivateKeyFile)
ui.Say("Using existing SSH private key")
privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile()
if err != nil {
state.Put("error", fmt.Errorf(
"Error loading configured private key file: %s", err))
state.Put("error", err)
return multistep.ActionHalt
}

View File

@ -7,7 +7,6 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"os"
"github.com/hashicorp/packer/helper/multistep"
@ -29,10 +28,9 @@ func (s *StepCreateSSHKey) Run(_ context.Context, state multistep.StateBag) mult
if config.Comm.SSHPrivateKeyFile != "" {
ui.Say("Using existing SSH private key")
privateKeyBytes, err := ioutil.ReadFile(config.Comm.SSHPrivateKeyFile)
privateKeyBytes, err := config.Comm.ReadSSHPrivateKeyFile()
if err != nil {
state.Put("error", fmt.Errorf(
"Error loading configured private key file: %s", err))
state.Put("error", err)
return multistep.ActionHalt
}

View File

@ -28,10 +28,10 @@ func (s *StepKeyPair) Run(_ context.Context, state multistep.StateBag) multistep
ui := state.Get("ui").(packer.Ui)
if s.Comm.SSHPrivateKeyFile != "" {
privateKeyBytes, err := ioutil.ReadFile(s.Comm.SSHPrivateKeyFile)
ui.Say("Using existing SSH private key")
privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile()
if err != nil {
state.Put("error", fmt.Errorf(
"Error loading configured private key file: %s", err))
state.Put("error", err)
return multistep.ActionHalt
}

View File

@ -7,7 +7,6 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"os"
"runtime"
@ -27,9 +26,9 @@ func (s *StepKeyPair) Run(_ context.Context, state multistep.StateBag) multistep
ui := state.Get("ui").(packer.Ui)
if s.Comm.SSHPrivateKeyFile != "" {
privateKeyBytes, err := ioutil.ReadFile(s.Comm.SSHPrivateKeyFile)
ui.Say("Using existing SSH private key")
privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile()
if err != nil {
err = fmt.Errorf("Error loading configured private key file: %s", err)
ui.Error(err.Error())
state.Put("error", err)
return multistep.ActionHalt

View File

@ -5,7 +5,6 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
@ -22,9 +21,9 @@ func (s *StepCreateSSHKey) Run(_ context.Context, state multistep.StateBag) mult
c := state.Get("config").(*Config)
if c.Comm.SSHPrivateKeyFile != "" {
pemBytes, err := ioutil.ReadFile(c.Comm.SSHPrivateKeyFile)
pemBytes, err := c.Comm.ReadSSHPrivateKeyFile()
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}

View File

@ -7,7 +7,6 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
"os"
"runtime"
@ -28,10 +27,9 @@ func (s *stepCreateSSHKey) Run(_ context.Context, state multistep.StateBag) mult
if config.Comm.SSHPrivateKeyFile != "" {
ui.Say("Using existing SSH private key")
privateKeyBytes, err := ioutil.ReadFile(config.Comm.SSHPrivateKeyFile)
privateKeyBytes, err := config.Comm.ReadSSHPrivateKeyFile()
if err != nil {
state.Put("error", fmt.Errorf(
"Error loading configured private key file: %s", err))
state.Put("error", err)
return multistep.ActionHalt
}

View File

@ -13,6 +13,7 @@ import (
helperssh "github.com/hashicorp/packer/helper/ssh"
"github.com/hashicorp/packer/template/interpolate"
"github.com/masterzen/winrm"
"github.com/mitchellh/go-homedir"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
@ -27,8 +28,6 @@ type Config struct {
SSHPort int `mapstructure:"ssh_port"`
SSHUsername string `mapstructure:"ssh_username"`
SSHPassword string `mapstructure:"ssh_password"`
SSHPublicKey []byte `mapstructure:"ssh_public_key"`
SSHPrivateKey []byte `mapstructure:"ssh_private_key"`
SSHKeyPairName string `mapstructure:"ssh_keypair_name"`
SSHTemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"`
SSHClearAuthorizedKeys bool `mapstructure:"ssh_clear_authorized_keys"`
@ -53,6 +52,9 @@ type Config struct {
SSHProxyPassword string `mapstructure:"ssh_proxy_password"`
SSHKeepAliveInterval time.Duration `mapstructure:"ssh_keep_alive_interval"`
SSHReadWriteTimeout time.Duration `mapstructure:"ssh_read_write_timeout"`
// SSH Internals
SSHPublicKey []byte
SSHPrivateKey []byte
// WinRM
WinRMUser string `mapstructure:"winrm_username"`
@ -66,6 +68,23 @@ type Config struct {
WinRMTransportDecorator func() winrm.Transporter
}
// ReadSSHPrivateKeyFile returns the SSH private key bytes
func (c *Config) ReadSSHPrivateKeyFile() ([]byte, error) {
var privateKey []byte
if c.SSHPrivateKeyFile != "" {
keyPath, err := homedir.Expand(c.SSHPrivateKeyFile)
if err != nil {
return privateKey, fmt.Errorf("Error expanding path for SSH private key: %s", err)
}
privateKey, err = ioutil.ReadFile(keyPath)
if err != nil {
return privateKey, fmt.Errorf("Error on reading SSH private key: %s", err)
}
}
return privateKey, nil
}
// SSHConfigFunc 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.
@ -92,12 +111,11 @@ func (c *Config) SSHConfigFunc() func(multistep.StateBag) (*ssh.ClientConfig, er
var privateKeys [][]byte
if c.SSHPrivateKeyFile != "" {
// key based auth
bytes, err := ioutil.ReadFile(c.SSHPrivateKeyFile)
privateKey, err := c.ReadSSHPrivateKeyFile()
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
return nil, err
}
privateKeys = append(privateKeys, bytes)
privateKeys = append(privateKeys, privateKey)
}
// aws,alicloud,cloudstack,digitalOcean,oneAndOne,openstack,oracle & profitbricks key
@ -112,7 +130,7 @@ func (c *Config) SSHConfigFunc() func(multistep.StateBag) (*ssh.ClientConfig, er
for _, key := range privateKeys {
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
return nil, fmt.Errorf("Error on parsing SSH private key: %s", err)
}
sshConfig.Auth = append(sshConfig.Auth, ssh.PublicKeys(signer))
}
@ -243,10 +261,14 @@ func (c *Config) prepareSSH(ctx *interpolate.Context) []error {
}
if c.SSHPrivateKeyFile != "" {
if _, err := os.Stat(c.SSHPrivateKeyFile); err != nil {
path, err := homedir.Expand(c.SSHPrivateKeyFile)
if err != nil {
errs = append(errs, fmt.Errorf(
"ssh_private_key_file is invalid: %s", err))
} else if _, err := helperssh.FileSigner(c.SSHPrivateKeyFile); err != nil {
} else if _, err := os.Stat(path); err != nil {
errs = append(errs, fmt.Errorf(
"ssh_private_key_file is invalid: %s", err))
} else if _, err := helperssh.FileSigner(path); err != nil {
errs = append(errs, fmt.Errorf(
"ssh_private_key_file is invalid: %s", err))
}
@ -256,6 +278,18 @@ func (c *Config) prepareSSH(ctx *interpolate.Context) []error {
if c.SSHBastionPassword == "" && c.SSHBastionPrivateKeyFile == "" {
errs = append(errs, errors.New(
"ssh_bastion_password or ssh_bastion_private_key_file must be specified"))
} else if c.SSHBastionPrivateKeyFile != "" {
path, err := homedir.Expand(c.SSHBastionPrivateKeyFile)
if err != nil {
errs = append(errs, fmt.Errorf(
"ssh_bastion_private_key_file is invalid: %s", err))
} else if _, err := os.Stat(path); err != nil {
errs = append(errs, fmt.Errorf(
"ssh_bastion_private_key_file is invalid: %s", err))
} else if _, err := helperssh.FileSigner(path); err != nil {
errs = append(errs, fmt.Errorf(
"ssh_bastion_private_key_file is invalid: %s", err))
}
}
}

View File

@ -14,6 +14,7 @@ import (
"github.com/hashicorp/packer/helper/multistep"
helperssh "github.com/hashicorp/packer/helper/ssh"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/go-homedir"
gossh "golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"golang.org/x/net/proxy"
@ -226,7 +227,12 @@ func sshBastionConfig(config *Config) (*gossh.ClientConfig, error) {
}
if config.SSHBastionPrivateKeyFile != "" {
signer, err := helperssh.FileSigner(config.SSHBastionPrivateKeyFile)
path, err := homedir.Expand(config.SSHBastionPrivateKeyFile)
if err != nil {
return nil, fmt.Errorf(
"Error expanding path for SSH bastion private key: %s", err)
}
signer, err := helperssh.FileSigner(path)
if err != nil {
return nil, err
}

View File

@ -75,8 +75,9 @@ The SSH communicator has the following options:
- `ssh_bastion_port` (number) - The port of the bastion host. Defaults to
`22`.
- `ssh_bastion_private_key_file` (string) - A private key file to use to
authenticate with the bastion host.
- `ssh_bastion_private_key_file` (string) - Path to a PEM encoded private
key file to use to authenticate with the bastion host. The `~` can be used
in path and will be expanded to the home directory of current user.
- `ssh_bastion_username` (string) - The username to connect to the bastion
host.
@ -111,7 +112,8 @@ The SSH communicator has the following options:
- `ssh_port` (number) - The port to connect to SSH. This defaults to `22`.
- `ssh_private_key_file` (string) - Path to a PEM encoded private key file to
use to authenticate with SSH.
use to authenticate with SSH. The `~` can be used in path and will be
expanded to the home directory of current user.
- `ssh_proxy_host` (string) - A SOCKS proxy host to use for SSH connection