From 0ff7c1da875e9c3ef1133ee8fa6512c6e52216e3 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Wed, 22 Aug 2018 17:03:25 +0200 Subject: [PATCH] SSHConfigFunc: append the ssh auth ways --- helper/communicator/config.go | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/helper/communicator/config.go b/helper/communicator/config.go index f2664b192..e2456db7c 100644 --- a/helper/communicator/config.go +++ b/helper/communicator/config.go @@ -3,11 +3,17 @@ package communicator import ( "errors" "fmt" + "io/ioutil" + "net" "os" "time" + packerssh "github.com/hashicorp/packer/communicator/ssh" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/template/interpolate" "github.com/masterzen/winrm" + "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/agent" ) // Config is the common configuration that communicators allow within @@ -52,6 +58,72 @@ type Config struct { WinRMTransportDecorator func() winrm.Transporter } +// 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. +func (c *Config) SSHConfigFunc() func(multistep.StateBag) (*ssh.ClientConfig, error) { + useAgent := c.SSHAgentAuth + username := c.SSHUsername + password := c.SSHPassword + return func(state multistep.StateBag) (*ssh.ClientConfig, error) { + sshConfig := &ssh.ClientConfig{ + User: username, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } + + 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) + } + + sshConfig.Auth = append(sshConfig.Auth, ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)) + } + + var privateKeys [][]byte + if c.SSHPrivateKey != "" { + // key based auth + bytes, err := ioutil.ReadFile(c.SSHPrivateKey) + if err != nil { + return nil, fmt.Errorf("Error setting up SSH config: %s", err) + } + privateKeys = append(privateKeys, bytes) + } + if iKey, hasKey := state.GetOk("privateKey"); hasKey { + privateKeys = append(privateKeys, []byte(iKey.(string))) + } + + if iKey, hasKey := state.GetOk("ssh_private_key"); hasKey { // gcp key + privateKeys = append(privateKeys, []byte(iKey.(string))) + } + //this is what scaleway.sshConfig did + if iKey, hasKey := state.GetOk("private_key"); hasKey { + privateKeys = append(privateKeys, []byte(iKey.(string))) + } + + for _, key := range privateKeys { + signer, err := ssh.ParsePrivateKey(key) + if err != nil { + return nil, fmt.Errorf("Error setting up SSH config: %s", err) + } + sshConfig.Auth = append(sshConfig.Auth, ssh.PublicKeys(signer)) + } + + if password != "" { + sshConfig.Auth = append(sshConfig.Auth, + ssh.Password(password), + ssh.KeyboardInteractive(packerssh.PasswordKeyboardInteractive(password)), + ) + } + return sshConfig, nil + } +} + // Port returns the port that will be used for access based on config. func (c *Config) Port() int { switch c.Type {