Skip to content

Commit

Permalink
Use SDK communicator to generate SSH key pair (hetznercloud#39)
Browse files Browse the repository at this point in the history
* set 'ssh_username' (required by SSH communicator) in acceptance test

* * use packer-plugin-sdk to manage temporary ssh keys
* support ecdsa, ed25519 temporary key algos via `temporary_key_pair_type` config
* clean up unused properties

* use Ubuntu 22.04 LTS base image in acceptance test
(OpenSSH>=8.2 deprecates `ssh-rsa` pub key algorithm,
see hashicorp/packer#10074 hashicorp/packer#8609),
change docs accordingly
  • Loading branch information
Feder1co5oave authored Aug 3, 2022
1 parent 11dedb5 commit a49b4ce
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 65 deletions.
13 changes: 10 additions & 3 deletions builder/hcloud/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,17 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Force: b.config.PackerForce,
SnapshotName: b.config.SnapshotName,
},
&stepCreateSSHKey{
Debug: b.config.PackerDebug,
DebugKeyPath: fmt.Sprintf("ssh_key_%s.pem", b.config.PackerBuildName),
&communicator.StepSSHKeyGen{
CommConf: &b.config.Comm,
SSHTemporaryKeyPair: b.config.Comm.SSH.SSHTemporaryKeyPair,
},
multistep.If(b.config.PackerDebug && b.config.Comm.SSHPrivateKeyFile == "",
&communicator.StepDumpSSHKey{
Path: fmt.Sprintf("ssh_key_%s.pem", b.config.PackerBuildName),
SSH: &b.config.Comm.SSH,
},
),
&stepCreateSSHKey{},
&stepCreateServer{},
&communicator.StepConnect{
Config: &b.config.Comm,
Expand Down
5 changes: 3 additions & 2 deletions builder/hcloud/builder_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ const testBuilderAccBasic = `
"type": "test",
"location": "nbg1",
"server_type": "cx11",
"image": "ubuntu-18.04",
"image": "ubuntu-22.04",
"user_data": "",
"user_data_file": ""
"user_data_file": "",
"ssh_username": "root"
}]
}
`
62 changes: 3 additions & 59 deletions builder/hcloud/step_create_sshkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,16 @@ package hcloud

import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"os"
"runtime"

"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/uuid"
"github.com/hetznercloud/hcloud-go/hcloud"
"golang.org/x/crypto/ssh"
)

type stepCreateSSHKey struct {
Debug bool
DebugKeyPath string

keyId int
}

Expand All @@ -31,40 +21,18 @@ func (s *stepCreateSSHKey) Run(ctx context.Context, state multistep.StateBag) mu
c := state.Get("config").(*Config)
ui.Say("Creating temporary ssh key for server...")

priv, err := rsa.GenerateKey(rand.Reader, 2014)
if err != nil {
state.Put("error", fmt.Errorf("Error generating RSA key: %s", err))
ui.Error(err.Error())
return multistep.ActionHalt
}
// ASN.1 DER encoded form
privDER := x509.MarshalPKCS1PrivateKey(priv)
privBLK := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: privDER,
}

// Set the private key in the config for later
c.Comm.SSHPrivateKey = pem.EncodeToMemory(&privBLK)

// Marshal the public key into SSH compatible format
pub, err := ssh.NewPublicKey(&priv.PublicKey)
if err != nil {
state.Put("error", fmt.Errorf("Error generating public key: %s", err))
ui.Error(err.Error())
if c.Comm.SSHPublicKey == nil {
ui.Say("No public SSH key found")
return multistep.ActionHalt
}

pubSSHFormat := string(ssh.MarshalAuthorizedKey(pub))

// The name of the public key on the Hetzner Cloud
name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())

// Create the key!
key, _, err := client.SSHKey.Create(ctx, hcloud.SSHKeyCreateOpts{
Name: name,
PublicKey: pubSSHFormat,
PublicKey: string(c.Comm.SSHPublicKey),
})
if err != nil {
err := fmt.Errorf("Error creating temporary SSH key: %s", err)
Expand All @@ -81,30 +49,6 @@ func (s *stepCreateSSHKey) Run(ctx context.Context, state multistep.StateBag) mu
// Remember some state for the future
state.Put("ssh_key_id", key.ID)

// If we're in debug mode, output the private key to the working directory.
if s.Debug {
ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
f, err := os.Create(s.DebugKeyPath)
if err != nil {
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
return multistep.ActionHalt
}
defer f.Close()

// Write the key out
if _, err := f.Write(pem.EncodeToMemory(&privBLK)); err != nil {
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
return multistep.ActionHalt
}

// Chmod it so that it is SSH ready
if runtime.GOOS != "windows" {
if err := f.Chmod(0600); err != nil {
state.Put("error", fmt.Errorf("Error setting permissions of debug key: %s", err))
return multistep.ActionHalt
}
}
}
return multistep.ActionContinue
}

Expand Down
2 changes: 1 addition & 1 deletion docs/builders/hetzner-cloud.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ access tokens:
{
"type": "hcloud",
"token": "YOUR API KEY",
"image": "ubuntu-18.04",
"image": "ubuntu-22.04",
"location": "nbg1",
"server_type": "cx11",
"ssh_username": "root"
Expand Down

0 comments on commit a49b4ce

Please sign in to comment.