Skip to main content

Linux VM Provisioning

Here are some steps that need to be done when creating a VM template that will be used multiple times:

Template Usage

See this page to setup a deployed instance from a template VM: Ubuntu v24 Host Setup

References

Here’s a good reference for template generation and cloud-init usage: https://medium.com/@dsykes012/making-a-custom-ubuntu-20-04-lts-focal-fossa-vm-template-that-works-with-cloud-init-2cfffb6783b4

Important Notes

Machine-ID Uniqueness: Anytime you power on a Linux VM template (whether making changes or not), you need to clear its machine-id before shutting it back down. This ensure that any generated clones will get a unique machine-id when the clone boots. If you forget to do this, the template will see that it has a machine-id, and will not generate one as a clone, causing all spawned clones to share the same machine-id.
Follow this section before powering down a template: https://wiki.galaxydump.com/link/391#bkmrk-clear-the-machine-id

Host Template Setup

Here are steps for creating a golden template VM.

Create Template VM

Create a VM guest instance with minimal CPU, memory, and hard disk space for the template.

We go with minimal resources, as it’s easier to script additional resources, than it is to reduce them.

For example, it’s much faster and less risk to expand a drive than reducing one.

Assign the VM’s NIC to the provisioning VLAN, as this allows us to easily access and setup deployed clones.

DHCP Addressing

Setup the template with DHCP, so we don’t worry about address collisions when spawning multiple clones at once.

Perform Updates and Upgrades

To speed up the process of clone setup, we will do any updates and upgrades on the template.
Do this:

apt update && apt -y upgrade && apt -y autoremove && apt clean

SSH Server

Install the openssh server.

Configure it to listen on port 22 of all adapters.

Disable password authentication over SSH.

Firewall

Setup the ufw firewall rules with 22 as allowed.

Don’t enable the firewall on the template. We can script this as use cases require.

Provisioning User Account

Create User

Create a provisioning user on the VM template.

NOTE: If not running as root, you will need to prepend these commands with 'sudo'.

NOTE: By default, we use the username 'provisioner'.

Run this to create the user with a password:

useradd -m provisioner

NOTE: We included the '-m' switch, to give the user a home directory.
This is done, so that our user can authenticate with SSH keys, which need a .ssh folder under the user's home directory.

Once created, add the provisioner account to the sudo group, so it can run elevated commands:

usermod -aG sudo provisioner

NOTE: The -aG option tells usermod to add the user to the listed groups.

User Shell

If you want the provisioner user to have shell access, set the shell with this:

sudo chsh -s /bin/bash provisioner

See this page for details: Linux: Shell Appearance

NOTE: It may not be necessary for an automation account to have a shell.
But, it does help when troubleshooting.

Account Password

You need to choose if you want the provisioner account to have a password or not.

NOTE: You don't really have to create a password for a provisioning user account if:
 - You will use SSH keys for authentication,
 - You will be bypassing sudo checks for this user

If you want it to have a password, use this to create one:

passwd provisioner

If you don't want the user to have a password, run this:

passwd -l provisioner

The above will lock the password, making login via password impossible.

Sudo Bypass

We will allow the provisioner user to skip any sudo challenge checks.
We do this, so that we don't have to manage passwords in the deployment scripting.

Follow this page for how to do that: Linux: Allow User to Skip Sudo Challenge

Edit the visudo file with this:

visudo -f /etc/sudoers

And, add this line above the includedir line:

provisioner ALL=(ALL) NOPASSWD: ALL

SSH Key Installation

Install an SSH key for the user.

NOTE: If you are just setting up this user, it may not yet have an authorized_keys file, or an .ssh folder in its profile.

If the .ssh folder is missing, follow this: Linux: Missing .SSH Folder

To do so, locate the authorized_keys file for the provisioner user at: /home/provisioner/.ssh/authorized_keys.
And, add the public key of the provisioner account.

You can open it with this:

sudo nano /home/provisioner/.ssh/authorized_keys

Save and close when done.

Verify SSH Access

Once the SSH key is loaded, you can verify SSH authentication with this:

ssh -i /path/to/privatekeyfile provisioner@hostname

To test access with the provisioner's current SSH key file, use something like this:

ssh -i /mnt/secshare/oga/keys/provisioner_user/ecdsa-key-provisioner-buildserver01-20250803.key provisioner@hostname

LoginUser as Provisioning UserCleanup

Log into the template VM as root.

This allows us to scrub unnecessary users and groups from the system.

Reset Hostname

Every host needs a unique name in your network.

So, we will clear an default the hostname of a template.
The following will erase it:

truncate -s0 /etc/hostname

And, this will set it to 'localhost':

hostnamectl set-hostname localhost

Clear the Machine-Id

Machine-Id is a string value that uniquely identifies a linux host, similar to how a Windows VM is uniquely identified by its machine sid.

Linux stores the machine-id is stored in a file at: /etc/machine-id.

So. If you are cloning VMs, you need to make sure this value is different for each VM clone.
The following will erase the machine-id, and any symbolic links to it:

truncate -s0 /etc/machine-id
rm /var/lib/dbus/machine-id
ln -s /etc/machine-id /var/lib/dbus/machine-id

The next time the VM reboots, the OS will generate a new machine-id during the boot process.

NOTE: Each time you boot the template, creates a new machine Id.
So, you will need to re-execute the above, after each time you boot the template VM for updates or changes.