How to create a golden image of Ubuntu Pro 20.04 FIPS with Azure Image Builder

1. Overview

In this tutorial, we will use Azure Image Builder to create a Ubuntu Pro 20.04 FIPS “golden” image in an Azure Shared Image Gallery.

Ubuntu 20.04 FIPS includes cryptographic validated modules that enable organisations to run and develop applications for the public sector, including regulated industries such as healthcare and finance.

We will be using a sample .json template to configure the image. To distribute the image to a Shared Image Gallery.

Note: We are using a pre-enabled FIPS image, but you can also use the standard Ubuntu Pro if it better suits your needs.

What you’ll learn

  • How to set up an Azure environment with a Shared Image Gallery and the necessary resources to distribute an image within your environment.
  • How to create an image definition for Ubuntu Pro 20.04 FIPS, customizing the image build JSON for adding any other applications you may want in every Ubuntu VM.
  • How to create an image version in Azure Image Builder service.
  • How to create a VM from the image in the Shared Image Gallery.

What you’ll need

Credits

This tutorial is based off this previous one for Ubuntu Pro 18.04 with CIS hardening.


3. Customise a template for our deployment

We are now going to create a template that contains the build instructions for the “golden” image we want to create.

We can download a template for this from here.

curl https://pastebin.com/raw/fCkQAgAc -o UbuntuProFips2004SIGTemplate.json

We can then customise it to use the values we have set above. The sed commands replace the <variable> placeholders in UbuntuProFips2004SIGTemplate.json with the values for the parameters that we set earlier:

sed -i -e "s/<subscriptionID>/$subscriptionID/g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s/<rgName>/$sigResourceGroup/g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s/<imageDefName>/$imageDefName/g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s/<sharedImageGalName>/$sigName/g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s/<region1>/$location/g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s/<region2>/$additionalregion/g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s/<runOutputName>/$runOutputName/g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s%<imgBuilderId>%$imgBuilderId%g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s/<ProPlanPublisher>/$ProPlanPublisher/g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s/<ProPlanOffer>/$ProPlanOffer/g" UbuntuProFips2004SIGTemplate.json
sed -i -e "s/<ProPlanSku>/$ProPlanSku/g" UbuntuProFips2004SIGTemplate.json

4. Review the contents of the template file

It is worth reviewing the entire (short) file, but we will focus on particular sections in more detail. We likely won’t need to change any of these values.

Note the section below:

        "source": {
            "type": "PlatformImage",
                "publisher": "canonical",
                "offer": "0001-com-ubuntu-pro-focal-fips",
                "sku": "pro-fips-20_04-gen2",
                "version": "latest",
        "planInfo": {
                    "planName": "pro-fips-20_04-gen2",
                    "planProduct": "0001-com-ubuntu-pro-focal-fips",
                    "planPublisher": "canonical"
                }
        },

This will show the plan details for the VM image you are using as a starting point for your golden image, whether it be from the Marketplace or a Private Offer.

The ‘customize’ section allows us to run commands as part of the image building process. The following command waits until Ubuntu’s ua client has attached to its subscription

        "customize": [
            {
            "type": "Shell",
            "name": "WaitForUAtokenAutoAttach",
            "inline": [
                "sudo ua status --wait"
            ]
        },

Next, you can add your own actions, like hardening the image or installing specific software.

        {
            "type": "Shell",
            "name": "Placeholder for custom commands required in each Ubuntu VM",
            "inline": [
                "echo 'Replace me!'"
            ]
        },

The following commands deregister the golden image from Ubuntu Pro and remove the machine-id. This will ensure that VMs generated from the golden image will generate their own unique IDs.

	    {
            "type": "Shell",
            "name": "DetachUA -- images created from this will auto attach themselves with new credentials",
            "inline": [
                "sudo ua detach --assume-yes && sudo rm -rf /var/log/ubuntu-advantage.log"
            ]
     	},

        {
            "type": "Shell",
            "name": "Replace /etc/machine-id with empty file to ensure UA client does not see clones as duplicates",
            "inline": [
                "sudo rm -f /etc/machine-id && sudo touch /etc/machine-id"
            ]
        }

5. Build/Create the image version

We will now create the image version in the gallery.

First, we submit our image configuration to the Azure Image Builder service

az resource create \
    --resource-group $sigResourceGroup \
    --subscription $subscriptionID \
    --properties @UbuntuProFips2004SIGTemplate.json \
    --is-full-object \
    --resource-type Microsoft.VirtualMachineImages/imageTemplates \
    -n UbuntuProFips2004SIG01

Before the subscription can be used, you need to accept the legal terms of the image.

az vm image terms accept --plan $ProPlanSku --offer $ProPlanOffer --publisher $ProPlanPublisher --subscription $subscriptionID

In the next step we will start the image build. This step can take some time (25 mins on my testing), as Azure will actually launch a VM and run the steps we have defined. We need to wait for this to complete before we can create a VM.

az resource invoke-action \
     --resource-group $sigResourceGroup \
     --subscription $subscriptionID \
     --resource-type  Microsoft.VirtualMachineImages/imageTemplates \
     -n UbuntuProFips2004SIG01 \
     --action Run

While we are waiting for the command to run we can see the logs of the AIB build process by going to the storage account inside the resource group created by AIB . (ie. Azure Portal > Resource groups > [IT_ibUbuntuProGalleryRG_*** > Random ID of the storage account > Containers > packerlogs > Random ID of the container > customization.log > Download.

Completing the build process

Once it has completed, it will change from “Running” to show something like:

{
  "endTime": "2022-09-10T23:13:25.9008064Z",
  "name": "37962BEF-34DC-45B1-A1C6-E827CE20F89B",
  "startTime": "2022-09-10T22:48:19.7520483Z",
  "status": "Succeeded"
}

8. Cleanup

You should be able to see the Resource Groups that have been created as part of this tutorial by typing:

az group list --query [].name --output table --subscription $subscriptionID | grep $sigResourceGroup

In my case this returns:

ibUbuntuFIPSGalleryRG
IT_ibUbuntuFIPSGalleryRG_UbuntuProFips2004S_02ecb26b-21f4-4450-b207-e86c7fd6853e

Please confirm that you would like these to be deleted. If so, type:

az group delete --name [the name from above] --subscription $subscriptionID

for each of these Resource Groups

(You may find that deleting the first automatically deletes the second.)


9. That’s all folks!

Great job! You’ve just created a Shared Image Gallery with an Ubuntu Pro 20.04 FIPS image inside, and launched and tested a VM created from this.