One of OpenShift’s many distinguishing features is the ease with which a group of users may employ projects to enforce least privilege principles. In this blog, I will demonstrate that power by sharing a customized clone of a virtual machine (VM) between project users without adding clutter to (or inadvertently sharing access with) those outside the project.


Start with an OpenShift 4.7 cluster with OpenShift Virtualization 2.6 installed. Next, create a boot source image for Microsoft Windows Server 2019, including the VirtIO drivers and QEMU guest agent. For an automated process to create this boot source from Microsoft’s installation media, see Eran Ifrach’s blog, Automatic Installation of a Windows VM Using OpenShift Virtualization.

Command line access for the virtctl command is helpful for testing the OpenSSH Server functionality, but is not required for the basic procedure outlined here.

I create three regular user accounts: Alice, Bob, and Eve. Alice is the owner of the project “devs,” and Bob is a regular user with edit permissions to that project. Eve is a third-party user who does not have access to the project but opportunistically attempts to see any templates created if they are available.

Though I demonstrate the process using a Microsoft Windows VM, the underlying procedure described here applies to any OpenShift Virtualization-supported Operating System template, like RHEL and Fedora.

Create a Customized VM

Alice creates a new Microsoft Windows Server 2019 VM from the provided template and calls it win2k19-sshd, as this particular VM adds a secure shell server that starts on boot. Once the VM is created, Alice follows the procedure outlined at Microsoft’s website, Installation of OpenSSH For Windows Server, to install the OpenSSH Server component, start it, and set it to start up on boot.

To test the SSH Server functionality, use virtctl to expose port 22 on the VM as NodePort:

virtctl expose vmi win2k19-sshd --name test-ssh --port=22 --type=NodePort

Note: In the next release, this task will be made available from the UI as a checkbox either in the VM creation wizard or in the VM details page.

Find the NodePort assigned to the service:

oc get svc test-ssh

NAME       TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
test-ssh   NodePort   <none>        22:32273/TCP   105s

Make note of the port number, 32273. To  test the SSH functionality, ssh as Administrator to the cluster’s API address using that NodePort:

ssh -p 32273

Warning: Permanently added '[]:32273,[]:32273' (ECDSA) to the list of known hosts.'s password:

Microsoft Windows [Version 10.0.17763.737]
(c) 2018 Microsoft Corporation. All rights reserved.

administrator@WIN-D60L5N3A3L9 C:\Users\Administrator>

With this successful test of the new software install, Alice can use Microsoft Sysprep to generalize the win2k19-ssh VM:

%WINDIR%\system32\sysprep\sysprep.exe /generalize

Alice can now shut down and delete the VM but she must take care to preserve its root disk by unselecting the Delete Disks checkbox:

Create a Customized Template

Now Alice navigates to the Workloads -> Virtualization -> Templates page, and finds the Microsoft Windows Server 2019 VM template. Clicking on the kebab menu, Alice selects Create new Template from:

This will be the template seen only in the devs project, so Alice names it win2k19-sshd to distinguish it from the default win2k19 template. Template provider just serves to distinguish the template from those provided by Red Hat; Alice uses The Devs Group.

Under the Operating System section, Alice unselects checkboxes for “Clone available operating system source …” and “Mount Windows guest tools.” This enables selection of a Boot Source, so Alice selects Clone existing PVC then chooses devs as the Persistent Volume Claim project, then win2k19-sshd-rootdisk for Persistent Volume Claim name. The other values may be left as their defaults, so Alice clicks the Review and Confirm button, double-checks the settings are correct, then clicks Create Virtual Machine Template.

Alice returns to Workloads -> Virtualization -> Templates and confirms the new template by The Devs Group has shown up on the list.

Verify Template Visibility

Now Bob logs in to the console and navigates to Workloads -> Virtualization -> Templates, locates win2k19-sshd, and clicks the Create button on the right. Bob leaves the default settings, and clicks the Create Virtual Machine button.

Once the new VM is running, Bob goes through the same procedure as above to verify ssh access.

In the meantime, Eve logs in. This is the first time Eve has logged in, so the first task is to create a new project. I chose eavesdropper as the project name, as this is the role Eve plays. Eve navigates to the Workloads -> Virtualization -> Templates page, and scrolls through the list of available templates. Only the original admin created Microsoft Windows Server 2019 template and boot source are available, but the win2k19-sshd template does not appear because Eve’s account does not have view permissions on the devs project:

What Is Really Happening Here?

It is helpful to examine what is going on under the console, since so much can be abstracted there. Operating systems templates of the kind we clone and modify here are actually a custom resource defined by OpenShift and are not specific to OpenShift Virtualization like virtual machines (VMs) and virtual machine instances (VMIs). These templates are used to parameterize basic Kubernetes objects which otherwise do not have the ability to accept parameters. Templates are a namespaced resource, and the ones included by OpenShift and OpenShift Virtualization belong to the openshift namespace.


oc get templates -n openshift -o name
 . . . Output Omitted . . .

The templates we are interested in have kubevirt labels; a useful one for filtering is

oc -n openshift get template -l | grep windows
windows10-desktop-large         Template for Microsoft Windows 10 VM. 3 (1 generated)
windows10-desktop-medium        Template for Microsoft Windows 10 VM. 3 (1 generated)
windows2k12r2-server-large      Template for Microsoft Windows Server 2012 R2 VM. 3 (1 generated)
windows2k12r2-server-medium     Template for Microsoft Windows Server 2012 R2 VM. 3 (1 generated)
windows2k16-server-large        Template for Microsoft Windows Server 2016 VM. 3 (1 generated)
windows2k16-server-medium       Template for Microsoft Windows Server 2016 VM. 3 (1 generated) windows2k19-server-large        Template for Microsoft Windows Server 2019 VM. 3 (1 generated)
windows2k19-server-medium       Template for Microsoft Windows Server 2019 VM. 3 (1 generated)
 ( Output adjusted for better readability )

The template cloned in this blog turns out to have been the medium version of windows2k19-server. You may compare the two versions side by side with the command:

sdiff <(oc -n openshift get template windows2k19-server-medium -o yaml ) \
    <(oc -n devs get template win2k19-sshd -o yaml) | less

Most of the two templates are the same; the only major difference is the name of the PVC and its namespace used to clone the server’s root disk. In the global template, these are parameters, SRC_PVC_NAME and SRC_PVC_NAMESPACE respectively. In the cloned template, they are explicitly set to the values described during the template’s creation.


This blog should provide a good foundation for building project-centric virtual machine templates. You can use the basic procedure outlined here to construct complex workflows involving virtual machines that start from a common template and then are customized to the needs of various teams. For more information on virtual machine templates, or OpenShift Virtualization in general, see the OpenShift Documentation.


How-tos, customizations, virtualization, OpenShift Virtualization

< Back to the blog