Skip to content

Commit

Permalink
Merge branch 'LIV2-boot_arg_sshpublickey'
Browse files Browse the repository at this point in the history
  • Loading branch information
nywilken committed Sep 12, 2023
2 parents b189c52 + 047bbac commit a0b9a62
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 6 deletions.
16 changes: 10 additions & 6 deletions builder/vmware/common/step_vnc_boot_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/hashicorp/packer-plugin-sdk/bootcommand"
"github.com/hashicorp/packer-plugin-sdk/communicator"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
Expand All @@ -21,12 +22,14 @@ type StepVNCBootCommand struct {
Config bootcommand.VNCConfig
VMName string
Ctx interpolate.Context
Comm *communicator.Config
}

type VNCBootCommandTemplateData struct {
HTTPIP string
HTTPPort int
Name string
HTTPIP string
HTTPPort int
Name string
SSHPublicKey string
}

func (s *StepVNCBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
Expand Down Expand Up @@ -58,9 +61,10 @@ func (s *StepVNCBootCommand) Run(ctx context.Context, state multistep.StateBag)

hostIP := state.Get("http_ip").(string)
s.Ctx.Data = &VNCBootCommandTemplateData{
HTTPIP: hostIP,
HTTPPort: httpPort,
Name: s.VMName,
HTTPIP: hostIP,
HTTPPort: httpPort,
Name: s.VMName,
SSHPublicKey: string(s.Comm.SSHPublicKey),
}

d := bootcommand.NewVNCDriver(conn, s.Config.BootKeyInterval)
Expand Down
5 changes: 5 additions & 0 deletions builder/vmware/iso/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
&vmwcommon.StepSuppressMessages{},
&vmwcommon.StepHTTPIPDiscover{},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
multistep.If(b.config.Comm.Type == "ssh", &communicator.StepSSHKeyGen{
CommConf: &b.config.Comm,
SSHTemporaryKeyPair: b.config.Comm.SSHTemporaryKeyPair,
}),
&vmwcommon.StepConfigureVNC{
Enabled: !b.config.DisableVNC && !b.config.VNCOverWebsocket,
VNCBindAddress: b.config.VNCBindAddress,
Expand All @@ -149,6 +153,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Config: b.config.VNCConfig,
VMName: b.config.VMName,
Ctx: b.config.ctx,
Comm: &b.config.Comm,
},
&communicator.StepConnect{
Config: &b.config.SSHConfig.Comm,
Expand Down
5 changes: 5 additions & 0 deletions builder/vmware/vmx/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
&vmwcommon.StepSuppressMessages{},
&vmwcommon.StepHTTPIPDiscover{},
commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig),
multistep.If(b.config.Comm.Type == "ssh", &communicator.StepSSHKeyGen{
CommConf: &b.config.Comm,
SSHTemporaryKeyPair: b.config.Comm.SSHTemporaryKeyPair,
}),
&vmwcommon.StepUploadVMX{
RemoteType: b.config.RemoteType,
},
Expand Down Expand Up @@ -143,6 +147,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
Config: b.config.VNCConfig,
VMName: b.config.VMName,
Ctx: b.config.ctx,
Comm: &b.config.Comm,
},
&communicator.StepConnect{
Config: &b.config.SSHConfig.Comm,
Expand Down
73 changes: 73 additions & 0 deletions docs/builders/iso.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ necessary for this build to succeed and can be found further down the page.

@include 'packer-plugin-sdk/communicator/SSH-not-required.mdx'

@include 'packer-plugin-sdk/communicator/SSHTemporaryKeyPair-not-required.mdx'

#### Optional WinRM fields:

@include 'packer-plugin-sdk/communicator/WinRM-not-required.mdx'
Expand Down Expand Up @@ -355,3 +357,74 @@ a different syntax to source a kickstart file from a mounted floppy image.
]
}
```

### SSH key pair automation

The VMware builders can inject the current SSH key pair's public key into
the template using the `SSHPublicKey` template engine. This is the SSH public
key as a line in OpenSSH authorized_keys format.

When a private key is provided using `ssh_private_key_file`, the key's
corresponding public key can be accessed using the above engine.

@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx'

If `ssh_password` and `ssh_private_key_file` are not specified, Packer will
automatically generate en ephemeral key pair. The key pair's public key can
be accessed using the template engine.

For example, the public key can be provided in the boot command as a URL
encoded string by appending `| urlquery` to the variable:

In JSON:

```json
"boot_command": [
"<up><wait><tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg PACKER_USER={{ user `username` }} PACKER_AUTHORIZED_KEY={{ .SSHPublicKey | urlquery }}<enter>"
]
```

In HCL2:

```hcl
boot_command = [
"<up><wait><tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg PACKER_USER={{ user `username` }} PACKER_AUTHORIZED_KEY={{ .SSHPublicKey | urlquery }}<enter>"
]
```

A kickstart could then leverage those fields from the kernel command line by
decoding the URL-encoded public key:

```shell
%post

# Newly created users need the file/folder framework for SSH key authentication.
umask 0077
mkdir /etc/skel/.ssh
touch /etc/skel/.ssh/authorized_keys

# Loop over the command line. Set interesting variables.
for x in $(cat /proc/cmdline)
do
case $x in
PACKER_USER=*)
PACKER_USER="${x#*=}"
;;
PACKER_AUTHORIZED_KEY=*)
# URL decode $encoded into $PACKER_AUTHORIZED_KEY
encoded=$(echo "${x#*=}" | tr '+' ' ')
printf -v PACKER_AUTHORIZED_KEY '%b' "${encoded//%/\\x}"
;;
esac
done

# Create/configure packer user, if any.
if [ -n "$PACKER_USER" ]
then
useradd $PACKER_USER
echo "%$PACKER_USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/$PACKER_USER
[ -n "$PACKER_AUTHORIZED_KEY" ] && echo $PACKER_AUTHORIZED_KEY >> $(eval echo ~"$PACKER_USER")/.ssh/authorized_keys
fi

%end
```
72 changes: 72 additions & 0 deletions docs/builders/vmx.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ necessary for this build to succeed and can be found further down the page.

@include 'packer-plugin-sdk/communicator/SSH-not-required.mdx'

@include 'packer-plugin-sdk/communicator/SSHTemporaryKeyPair-not-required.mdx'

#### Optional WinRM fields:

@include 'packer-plugin-sdk/communicator/WinRM-not-required.mdx'
Expand Down Expand Up @@ -300,3 +302,73 @@ Since ovftool is only capable of password based authentication
- `vnc_disable_password` - This must be set to "true" when using VNC with
ESXi 6.5 or 6.7.

### SSH key pair automation

The VMware builders can inject the current SSH key pair's public key into
the template using the `SSHPublicKey` template engine. This is the SSH public
key as a line in OpenSSH authorized_keys format.

When a private key is provided using `ssh_private_key_file`, the key's
corresponding public key can be accessed using the above engine.

@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx'

If `ssh_password` and `ssh_private_key_file` are not specified, Packer will
automatically generate en ephemeral key pair. The key pair's public key can
be accessed using the template engine.

For example, the public key can be provided in the boot command as a URL
encoded string by appending `| urlquery` to the variable:

In JSON:

```json
"boot_command": [
"<up><wait><tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg PACKER_USER={{ user `username` }} PACKER_AUTHORIZED_KEY={{ .SSHPublicKey | urlquery }}<enter>"
]
```

In HCL2:

```hcl
boot_command = [
"<up><wait><tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg PACKER_USER={{ user `username` }} PACKER_AUTHORIZED_KEY={{ .SSHPublicKey | urlquery }}<enter>"
]
```

A kickstart could then leverage those fields from the kernel command line by
decoding the URL-encoded public key:

```shell
%post

# Newly created users need the file/folder framework for SSH key authentication.
umask 0077
mkdir /etc/skel/.ssh
touch /etc/skel/.ssh/authorized_keys

# Loop over the command line. Set interesting variables.
for x in $(cat /proc/cmdline)
do
case $x in
PACKER_USER=*)
PACKER_USER="${x#*=}"
;;
PACKER_AUTHORIZED_KEY=*)
# URL decode $encoded into $PACKER_AUTHORIZED_KEY
encoded=$(echo "${x#*=}" | tr '+' ' ')
printf -v PACKER_AUTHORIZED_KEY '%b' "${encoded//%/\\x}"
;;
esac
done

# Create/configure packer user, if any.
if [ -n "$PACKER_USER" ]
then
useradd $PACKER_USER
echo "%$PACKER_USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/$PACKER_USER
[ -n "$PACKER_AUTHORIZED_KEY" ] && echo $PACKER_AUTHORIZED_KEY >> $(eval echo ~"$PACKER_USER")/.ssh/authorized_keys
fi

%end
```

0 comments on commit a0b9a62

Please sign in to comment.