From ae4e198ee464cde37e77b9543b06c3bc16ac9ed4 Mon Sep 17 00:00:00 2001 From: Matt Harlum Date: Mon, 19 Sep 2022 20:58:24 +0200 Subject: [PATCH 1/4] Add SSHKeyGen step This makes use of the SSH communicators temporary key generation The builders already referenced "StepCleanupTempKeys" but since none were created it did nothing --- builder/vmware/iso/builder.go | 4 ++++ builder/vmware/vmx/builder.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/builder/vmware/iso/builder.go b/builder/vmware/iso/builder.go index 734efe98..67fae5ee 100644 --- a/builder/vmware/iso/builder.go +++ b/builder/vmware/iso/builder.go @@ -120,6 +120,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) &vmwcommon.StepSuppressMessages{}, &vmwcommon.StepHTTPIPDiscover{}, commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), + &communicator.StepSSHKeyGen{ + CommConf: &b.config.Comm, + SSHTemporaryKeyPair: b.config.Comm.SSHTemporaryKeyPair, + }, &vmwcommon.StepConfigureVNC{ Enabled: !b.config.DisableVNC && !b.config.VNCOverWebsocket, VNCBindAddress: b.config.VNCBindAddress, diff --git a/builder/vmware/vmx/builder.go b/builder/vmware/vmx/builder.go index e09adad6..9adee1e6 100644 --- a/builder/vmware/vmx/builder.go +++ b/builder/vmware/vmx/builder.go @@ -111,6 +111,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) &vmwcommon.StepSuppressMessages{}, &vmwcommon.StepHTTPIPDiscover{}, commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), + &communicator.StepSSHKeyGen{ + CommConf: &b.config.Comm, + SSHTemporaryKeyPair: b.config.Comm.SSHTemporaryKeyPair, + }, &vmwcommon.StepUploadVMX{ RemoteType: b.config.RemoteType, }, From f963b337dc674afa9a8fb60eee232dd96f2b213f Mon Sep 17 00:00:00 2001 From: Matt Harlum Date: Mon, 19 Sep 2022 19:12:19 +0200 Subject: [PATCH 2/4] Copy ability to use SSHPublicKey var in boot_command from virtualbox plugin --- .../vmware/common/step_vnc_boot_command.go | 16 +++-- builder/vmware/iso/builder.go | 1 + builder/vmware/vmx/builder.go | 1 + docs/builders/iso.mdx | 71 +++++++++++++++++++ docs/builders/vmx.mdx | 70 ++++++++++++++++++ 5 files changed, 153 insertions(+), 6 deletions(-) diff --git a/builder/vmware/common/step_vnc_boot_command.go b/builder/vmware/common/step_vnc_boot_command.go index f7bafa4c..a068d6c7 100644 --- a/builder/vmware/common/step_vnc_boot_command.go +++ b/builder/vmware/common/step_vnc_boot_command.go @@ -7,6 +7,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" @@ -18,12 +19,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 { @@ -55,9 +58,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) diff --git a/builder/vmware/iso/builder.go b/builder/vmware/iso/builder.go index 67fae5ee..74543793 100644 --- a/builder/vmware/iso/builder.go +++ b/builder/vmware/iso/builder.go @@ -150,6 +150,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, diff --git a/builder/vmware/vmx/builder.go b/builder/vmware/vmx/builder.go index 9adee1e6..c6313225 100644 --- a/builder/vmware/vmx/builder.go +++ b/builder/vmware/vmx/builder.go @@ -144,6 +144,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, diff --git a/docs/builders/iso.mdx b/docs/builders/iso.mdx index f944c7c9..3268caf5 100644 --- a/docs/builders/iso.mdx +++ b/docs/builders/iso.mdx @@ -359,3 +359,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": [ + " text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg PACKER_USER={{ user `username` }} PACKER_AUTHORIZED_KEY={{ .SSHPublicKey | urlquery }}" +] +``` + +In HCL2: + +```hcl +boot_command = [ + " text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg PACKER_USER={{ user `username` }} PACKER_AUTHORIZED_KEY={{ .SSHPublicKey | urlquery }}" +] +``` + +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 +``` diff --git a/docs/builders/vmx.mdx b/docs/builders/vmx.mdx index 223e8338..08a52d2e 100644 --- a/docs/builders/vmx.mdx +++ b/docs/builders/vmx.mdx @@ -304,3 +304,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": [ + " text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg PACKER_USER={{ user `username` }} PACKER_AUTHORIZED_KEY={{ .SSHPublicKey | urlquery }}" +] +``` + +In HCL2: + +```hcl +boot_command = [ + " text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg PACKER_USER={{ user `username` }} PACKER_AUTHORIZED_KEY={{ .SSHPublicKey | urlquery }}" +] +``` + +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 +``` From 092609fcff469213711b6c2260b271d67f44fb96 Mon Sep 17 00:00:00 2001 From: Matt Harlum Date: Tue, 20 Sep 2022 16:01:04 +0200 Subject: [PATCH 3/4] Include temporary keypair docs --- docs/builders/iso.mdx | 2 ++ docs/builders/vmx.mdx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/builders/iso.mdx b/docs/builders/iso.mdx index 3268caf5..71fd2ca2 100644 --- a/docs/builders/iso.mdx +++ b/docs/builders/iso.mdx @@ -195,6 +195,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' diff --git a/docs/builders/vmx.mdx b/docs/builders/vmx.mdx index 08a52d2e..114a2101 100644 --- a/docs/builders/vmx.mdx +++ b/docs/builders/vmx.mdx @@ -176,6 +176,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' From 047bbacbb07690ab121f3ba33aad50a00e967d6c Mon Sep 17 00:00:00 2001 From: Wilken Rivera Date: Tue, 12 Sep 2023 14:43:07 -0400 Subject: [PATCH 4/4] Update StepSSHKeyGen logic SSH key generation should only occur when using the SSH communicator. While there is no issue generating just to generating, it feels like an extra step that can lead to confusion if the communicator in use is not "ssh". --- builder/vmware/iso/builder.go | 4 ++-- builder/vmware/vmx/builder.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/builder/vmware/iso/builder.go b/builder/vmware/iso/builder.go index 89b617f3..e377c7d7 100644 --- a/builder/vmware/iso/builder.go +++ b/builder/vmware/iso/builder.go @@ -123,10 +123,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) &vmwcommon.StepSuppressMessages{}, &vmwcommon.StepHTTPIPDiscover{}, commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), - &communicator.StepSSHKeyGen{ + 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, diff --git a/builder/vmware/vmx/builder.go b/builder/vmware/vmx/builder.go index 9aa84bae..599f4ea4 100644 --- a/builder/vmware/vmx/builder.go +++ b/builder/vmware/vmx/builder.go @@ -114,10 +114,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) &vmwcommon.StepSuppressMessages{}, &vmwcommon.StepHTTPIPDiscover{}, commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), - &communicator.StepSSHKeyGen{ + multistep.If(b.config.Comm.Type == "ssh", &communicator.StepSSHKeyGen{ CommConf: &b.config.Comm, SSHTemporaryKeyPair: b.config.Comm.SSHTemporaryKeyPair, - }, + }), &vmwcommon.StepUploadVMX{ RemoteType: b.config.RemoteType, },