If you’re rolling out multiple virtual machines, it makes sense to create a clean image that doesn’t contain sensitive information such as SSH host keys, MAC addresses, logs, temporary files, and machine IDs. As a KVM admin, this is the point where virt-sysprep will be your best friend.

The virt-sysprep utility is used to prepare a virtual machine (VM) image for cloning by removing or resetting specific configurations and data. It is a tool provided by libguestfs package. By using virt-sysprep, we ensure that the cloned VM instance do not retain conflicting data.

Some common operations performed by virt-sysprep:

  • Hostname: Reset the hostname.
  • SSH-related: Remove ~/.ssh/ and /etc/ssh/*key*.
  • Logs: Clear log files in /var/log/.
  • User Accounts: Remove user accounts except root.
  • Temporary Files: Remove /tmp/* and /var/tmp/*.
  • Machine ID: Reset /etc/machine-id.
🔥 TRENDING - Our #1 Seller

Mastering KVM Virtualization

From home labs to production clouds - master KVM, Terraform, Vagrant, and cloud automation. Build scalable virtual infrastructure that works whether you're learning at home or deploying enterprise solutions.

Only $10 $20
Get Instant Access →

Before we can use virt-sysprep, ensure it’s installed by checking the version of the software.

virt-sysprep --version

If the virt-sysprep command is not available in your system, then you can get it by installing the libguestfs-tools package.

  • Debian-based OS systems
sudo apt update
sudo apt install libguestfs-tools
  • RHEL-based OS systems
sudo dnf install libguestfs-tools guestfs-tools
  • openSUSE
sudo zypper -n install guestfs-tools
  • Arch-based Linux
sudo pacman -S libguestfs guestfs-tools

Clone VM and run virt-sysprep

Below is a simple example of cloning a guest operating system using virt-clone commands. 

# Set guest names
SOURCE_VM="my-old-vm"
CLONED_VM="my-new-vm"

# Clone a VM
sudo virt-clone \
  --original $SOURCE_VM \
  --name $CLONED_VM \
  --auto-clone

When a VM is cloned, all data from the original guest is carried over to the new one. However, in many cases, we don’t want this and instead aim to create a fresh instance based on a template. In such scenarios, it’s often necessary to clean up the image by removing log files, resetting SSH host keys (to establish a new identity), and performing similar housekeeping tasks to ensure the new VM is truly unique.

This operation is done by running the following after the virt-sysprep command.

sudo virt-sysprep \
  --domain $CLONED_VM \
  --operations machine-id,dhcp-client-state,bash-history,logfiles,customize,ssh-hostkeys \
  --firstboot-command 'dpkg-reconfigure openssh-server && systemctl restart ssh'

The tool modifies the disk image offline, meaning the VM should not be running.

If you don’t specify --operations, all available operations will be executed, which might not be desirable. For instance, you may want to preserve the authorized SSH keys and avoid them being wiped.

To get a full list of virt-sysprep command operations, run the following command:

virt-sysprep --list-operations

Note that the customize operation is required for the --firstboot-command option to function correctly.

Run virt-sysprep on a VM Image

virt-sysprep can also be used to modify an existing VM image directly. This could be an image from an old VM or a cloud image that you want to configure, upload files to, and adjust internal settings before booting.

virt-sysprep --help
1. Specify disk image file

Use -a or --add followed by the disk file to specify the image file.

-a <file>
2. Setting custom root password

To set a custom root user password, use --root-password <SELECTOR>. In this example we are setting root user password to StrongPassw0rd

--root-password password:StrongPassw0rd
3. Setting hostname

Use --hostname <HOSTNAME> to set the hostname.

--hostname dbserver.cloudspinx.com
4. Install software package into VM image

The command options for installing software packages is --install <PKG,PKG..>. Let’s consider and example to install openssh-server, mariadb-server, apache2, and php packages.

--install openssh-server,mariadb-server,apache2,libapache2-mod-php,php-mysql
5. Run command at first guest boot

We can provide the commands that will be run on first boot using --firstboot-command <'CMD+ARGS'>

--firstboot-command 'apt update && apt upgrade -y'
6. Set the default timezone

The default timezone can be set by passing --timezone <TIMEZONE>

--timezone America/Los_Angeles
7. Upload local file to destination

It is possible to upload files from your local machine into the image with --upload <FILE:DEST>

Let’s begin by creating a Hello World Bash script.

echo 'echo "Hello, World!"' > helloworld.sh
chmod +x helloworld.sh

The example below will copy the php script created into /root/ on the VM image.

--upload ./helloworld.sh:/root

Files can also be moved instead of copy by using --move <SOURCE:DEST>

8. Inject SSH public key into the guest

SSH public key can be injected into the guest VM using --ssh-inject <USER[:SELECTOR]>

Generate ssh keys if you don’t have:

ssh-keygen -t rsa -b 4096

The default path location for the SSH public key is ~/.ssh/id_rsa.pub. We can inject this file.

--ssh-inject root:file:/home/$USER/.ssh/id_rsa.pub
  • root is the name of guest OS user account
  • /home/$USER/.ssh/id_rsa.pub is the absolute path to the ssh public key. If using root user account this will be /root/.ssh/id_rsa.pub

The final set of virt-sysprep commands to run in our example is as follows:

sudo virt-sysprep \
-a noble-server-cloudimg-amd64.img \
--root-password password:StrongPassw0rd \
--hostname dbserver.cloudspinx.com \
--network \
--firstboot-command 'apt update && apt upgrade -y' \
--timezone America/Los_Angeles \
--upload ./helloworld.sh:/root \
--ssh-inject root:file:/home/$USER/.ssh/id_rsa.pub

Sample execution output:

[   0.0] Examining the guest ...
[  12.4] Performing "abrt-data" ...
[  12.4] Performing "backup-files" ...
[  12.6] Performing "bash-history" ...
[  12.6] Performing "blkid-tab" ...
[  12.6] Performing "crash-data" ...
[  12.6] Performing "cron-spool" ...
[  12.6] Performing "dhcp-client-state" ...
[  12.6] Performing "dhcp-server-state" ...
[  12.6] Performing "dovecot-data" ...
[  12.6] Performing "ipa-client" ...
[  12.6] Performing "kerberos-hostkeytab" ...
[  12.6] Performing "logfiles" ...
[  12.6] Performing "lvm-system-devices" ...
[  12.6] Performing "machine-id" ...
[  12.7] Performing "mail-spool" ...
[  12.7] Performing "net-hostname" ...
[  12.7] Performing "net-hwaddr" ...
[  12.7] Performing "net-nmconn" ...
[  12.7] Performing "pacct-log" ...
[  12.7] Performing "package-manager-cache" ...
[  12.7] Performing "pam-data" ...
[  12.7] Performing "passwd-backups" ...
[  12.7] Performing "puppet-data-log" ...
[  12.7] Performing "rh-subscription-manager" ...
[  12.7] Performing "rhn-systemid" ...
[  12.7] Performing "rpm-db" ...
[  12.7] Performing "samba-db-log" ...
[  12.7] Performing "script" ...
[  12.7] Performing "smolt-uuid" ...
[  12.7] Performing "ssh-hostkeys" ...
[  12.7] Performing "ssh-userdir" ...
[  12.7] Performing "sssd-db-log" ...
[  12.7] Performing "tmp-files" ...
[  12.7] Performing "udev-persistent-net" ...
[  12.7] Performing "utmp" ...
[  12.8] Performing "yum-uuid" ...
[  12.8] Performing "customize" ...
[  12.8] Setting a random seed
virt-sysprep: warning: random seed could not be set for this type of guest
[  12.8] Setting the machine ID in /etc/machine-id
[  12.8] Setting the hostname: dbserver.cloudspinx.com
[  13.5] Installing firstboot command: apt update && apt upgrade -y
[  13.5] Setting the timezone: America/Los_Angeles
[  13.5] Uploading: ./helloworld.php to /root
[  13.5] SSH key inject: root
[  14.0] Setting passwords
[  14.5] SELinux relabelling
[  14.6] Performing "lvm-uuids" ...
9. Disable SELinux (Valid for RHEL based systems)

The --edit <FILE:EXPR> allows you to edit file using Perl expression. Here is an example that will disable SELinux.

--edit '/etc/selinux/config: s/^SELINUX=.*/SELINUX=disabled/'

Or putting it in permissive mode:

--edit '/etc/selinux/config: s/^SELINUX=.*/SELINUX=permissive/'

For more usage guide of the virt-sysprep command, run:

virt-sysprep --help

The resulting image can be imported to KVM using virt-install commands. Check relevant chapter in the ebook for a step-by-step guidance.

LEAVE A REPLY

Please enter your comment!
Please enter your name here