cloudstack: Add support for ssh_agent_auth

This commit is contained in:
Rickard von Essen 2017-07-14 21:25:20 +02:00
parent 24a53b7ee5
commit f47c41372e
No known key found for this signature in database
GPG Key ID: E0C0327388876CBA
4 changed files with 69 additions and 26 deletions

View File

@ -66,9 +66,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
},
&stepSetupNetworking{},
&communicator.StepConnect{
Config: &b.config.Comm,
Host: commHost,
SSHConfig: sshConfig,
Config: &b.config.Comm,
Host: commHost,
SSHConfig: SSHConfig(
b.config.Comm.SSHAgentAuth,
b.config.Comm.SSHUsername,
b.config.Comm.SSHPassword),
},
&common.StepProvision{},
&stepShutdownInstance{},

View File

@ -2,12 +2,14 @@ package cloudstack
import (
"fmt"
"io/ioutil"
"net"
"os"
packerssh "github.com/hashicorp/packer/communicator/ssh"
"github.com/mitchellh/multistep"
"github.com/xanzy/go-cloudstack/cloudstack"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
func commHost(state multistep.StateBag) (string, error) {
@ -26,32 +28,54 @@ func commHost(state multistep.StateBag) (string, error) {
return config.hostAddress, nil
}
func sshConfig(state multistep.StateBag) (*ssh.ClientConfig, error) {
config := state.Get("config").(*Config)
func SSHConfig(useAgent bool, username, password string) func(state 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")
}
clientConfig := &ssh.ClientConfig{
User: config.Comm.SSHUsername,
Auth: []ssh.AuthMethod{
ssh.Password(config.Comm.SSHPassword),
ssh.KeyboardInteractive(
packerssh.PasswordKeyboardInteractive(config.Comm.SSHPassword)),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
sshAgent, err := net.Dial("unix", authSock)
if err != nil {
return nil, fmt.Errorf("Cannot connect to SSH Agent socket %q: %s", authSock, err)
}
if config.Comm.SSHPrivateKey != "" {
privateKey, err := ioutil.ReadFile(config.Comm.SSHPrivateKey)
if err != nil {
return nil, fmt.Errorf("Error loading configured private key file: %s", err)
return &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}, nil
}
signer, err := ssh.ParsePrivateKey(privateKey)
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
privateKey, hasKey := state.GetOk("privateKey")
if hasKey {
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),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}, nil
} else {
return &ssh.ClientConfig{
User: username,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Auth: []ssh.AuthMethod{
ssh.Password(password),
ssh.KeyboardInteractive(
packerssh.PasswordKeyboardInteractive(password)),
}}, nil
}
clientConfig.Auth = []ssh.AuthMethod{ssh.PublicKeys(signer)}
}
return clientConfig, nil
}

View File

@ -22,6 +22,15 @@ func (s *stepPrepareConfig) Run(state multistep.StateBag) multistep.StepAction {
var err error
var errs *packer.MultiError
if config.Comm.SSHPrivateKey != "" {
privateKey, err := ioutil.ReadFile(config.Comm.SSHPrivateKey)
if err != nil {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Error loading configured private key file: %s", err))
}
state.Put("privateKey", privateKey)
}
// First get the project and zone UUID's so we can use them in other calls when needed.
if config.Project != "" && !isUUID(config.Project) {
config.Project, _, err = client.Project.GetProjectID(config.Project)

View File

@ -123,6 +123,13 @@ builder.
connecting any provisioners to. If not provided, a temporary public IP
address will be associated and released during the Packer run.
- `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
image, leave the `keypair` blank. To associate an existing key pair
with the source instance, set the `keypair` field to the name of the key pair.
- `ssl_no_verify` (boolean) - Set to `true` to skip SSL verification. Defaults
to `false`.