Key | Value |
---|---|
Summary | Create a golden image of Ubuntu Pro 20.04 FIPS with Azure Image Builder |
Categories | azure, cloud, FIPS |
Difficulty | 3 |
Overview
Duration: 2:00
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
- A Microsoft Azure account
- Azure Command-Line Interface/az cli
Credits
This tutorial is based off this previous one for Ubuntu Pro 18.04 with CIS hardening.
Setup your Shared Image Gallery
Duration: 5:00
We will be using some pieces of information repeatedly, so it makes sense to create some variables to store that information. This will make the instructions more efficient and easier to read.
***Then we will create the identity, image definition and gallery that we will need for the image.
Set variables for use throughout the tutorial
We will create a new resource group for this tutorial. The name should be one you are not already using. We will delete the resource group at the end of the tutorial.
Please note that in order to create a custom image, the VM Image Builder must be in the same resource group as the source-managed image.
# Resource group name - we are using ibUbuntuFIPSGalleryRG in this example
sigResourceGroup=ibUbuntuFIPSGalleryRG
# Datacenter location - we are using West US 2 in this example
location=westus2
# Additional region to replicate the image to - we are using East US in this example
additionalregion=eastus
Now we will set variables for the Gallery Name and Image Definition Name. The image will be displayed in the Azure Portal as sigName/imageDefName
.
# Name of the Azure Compute Gallery - myGallery in this example
sigName=myIbGallery
# Name of the image definition to be created - myImageDef in this example
imageDefName=myIbImageDef
# image distribution metadata reference name
runOutputName=aibUbuntuSIG
Create a variable for your subscription ID:
subscriptionID=$(az account show --query id --output tsv)
Now we are going to set variables for the Ubuntu Pro plan we are going to use in this tutorial. If you have an Ubuntu Pro private offer with Canonical that includes 24x7 Technical Support with SLAs, you will have a custom Offer and Sku. If not, we will use the plan name and product for the public Ubuntu Pro 20.04 FIPS from the Azure Marketplace, please note that we are using the gen2 Sku.
# ProPlanPublisher the 'Publisher' field for the Marketplace VM Offer we want to start from
ProPlanPublisher=canonical
# ProPlanOffer the 'Offer' field for the Marketplace VM Offer we want to start from
ProPlanOffer=0001-com-ubuntu-pro-focal-fips
# ProPlanSku the 'Sku' field for the Marketplace VM Offer we want to start from
ProPlanSku=pro-fips-20_04-gen2
Create required resources, identities and permissions
Create the resource group:
az group create -n $sigResourceGroup -l $location --subscription $subscriptionID
Image Builder will use the user-identity provided to inject the image into the Azure Shared Image Gallery (SIG). In this example, you will create an Azure role definition that has the actions needed to distribute the image to the SIG. The role definition will then be assigned to the user-identity.
# create user assigned identity for image builder to access the storage account where the script is located
identityName=aibBuiUserId$(date +'%s')
az identity create -g $sigResourceGroup -n $identityName --subscription $subscriptionID
# get identity id
imgBuilderCliId=$(az identity show -g $sigResourceGroup -n $identityName --subscription $subscriptionID -o json | grep "clientId" | cut -c16- | tr -d '",')
# get the user identity URI, needed for the template
imgBuilderId=/subscriptions/$subscriptionID/resourcegroups/$sigResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$identityName
# this command will download an Azure role definition template, and update the template with the parameters specified earlier.
curl https://raw.githubusercontent.com/Azure/azvmimagebuilder/master/solutions/12_Creating_AIB_Security_Roles/aibRoleImageCreation.json -o aibRoleImageCreation.json
imageRoleDefName="Azure Image Builder Image Def"$(date +'%s')
# update the definition
sed -i -e "s/<subscriptionID>/$subscriptionID/g" aibRoleImageCreation.json
sed -i -e "s/<rgName>/$sigResourceGroup/g" aibRoleImageCreation.json
sed -i -e "s/Azure Image Builder Service Image Creation Role/$imageRoleDefName/g" aibRoleImageCreation.json
# create role definitions
az role definition create --role-definition ./aibRoleImageCreation.json
# grant role definition to the user assigned identity
# If this gives an error, wait a bit longer and try again
az role assignment create \
--assignee $imgBuilderCliId \
--role "$imageRoleDefName" \
--scope /subscriptions/$subscriptionID/resourceGroups/$sigResourceGroup
Create an image definition and gallery
In order to use VM Image Builder with Azure Compute Gallery, you will need to have an existing gallery and image definition. VM Image Builder does not create the gallery and image definition for you.
First, create a gallery:
az sig create \
-g $sigResourceGroup \
--gallery-name $sigName \
--subscription $subscriptionID
Then, create an image definition, note the “hyper-v-generation” flag, this needs to be the same gen as the base image you are using.
az sig image-definition create \
-g $sigResourceGroup \
--gallery-name $sigName \
--gallery-image-definition $imageDefName \
--publisher $ProPlanPublisher \
--offer $ProPlanOffer \
--sku $ProPlanSku \
--os-type Linux \
--plan-name $ProPlanSku \
--plan-product $ProPlanOffer \
--plan-publisher $ProPlanPublisher \
--hyper-v-generation V2 \
--subscription $subscriptionID
Customise a template for our deployment
Duration: 2:00
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
Review the contents of the template file
Duration: 2:00
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"
]
}
Build/Create the image version
Duration: 30:00
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"
}
Create a VM from the shared image gallery from the Portal
Duration: 5:00
Create a VM from the Azure Portal
We will now create a VM from the Azure Portal.
Once you log in, click “Virtual machines”:
Click “Create” > “Virtual machine”
In the “Create a virtual machine” screen, you will need to click “See all images” below the “Image” drop down:
Select “Shared Images” on the left-hand side:
You will see the image created:
You should click this and it will select that as the image type.
Complete the remaining fields as you wish and click “Review + Create” to create a VM
Create and test a VM from the shared image gallery from the AZ CLI
Duration: 5:00
Create a VM from the command line
We are now going to create a VM from the Shared Image Gallery. As we created the image with plan information, we also need to specify that information when launching the instance.
If you already have an SSH key that you want to use, then use the following to launch the VM:
SSHPublicKeyPath=<path to your id_rsa.pub>
az vm create \
--resource-group $sigResourceGroup \
--subscription $subscriptionID \
--name myAibGalleryVM \
--admin-username aibuser \
--location $location \
--image "/subscriptions/$subscriptionID/resourceGroups/$sigResourceGroup/providers/Microsoft.Compute/galleries/$sigName/images/$imageDefName/versions/latest" \
--ssh-key-values $SSHPublicKeyPath \
--plan-name $ProPlanSku \
--plan-product $ProPlanOffer \
--public-ip-sku Standard \
--plan-publisher $ProPlanPublisher
Alternatively, if you do not yet have SSH keys, you can use the following and replace the --ssh-key-values $SSHPublicKeyPath
with --generate-ssh-keys
(note that this may overwrite the ssh keypair “id_rsa” and “id_rsa.pub” under .ssh in your home directory):
az vm create \
--resource-group $sigResourceGroup \
--subscription $subscriptionID \
--name myAibGalleryVM \
--admin-username aibuser \
--location $location \
--image "/subscriptions/$subscriptionID/resourceGroups/$sigResourceGroup/providers/Microsoft.Compute/galleries/$sigName/images/$imageDefName/versions/latest" \
--generate-ssh-keys \
--plan-name $ProPlanSku \
--plan-product $ProPlanOffer \
--public-ip-sku Standard \
--plan-publisher $ProPlanPublisher
When this completes, you should see something like the following:
{
"fqdns": "",
"id": "/subscriptions/50a71625-6dba-43a2-87ad-9eb26e52c9c4/resourceGroups/ibUbuntuFIPSGalleryRG/providers/Microsoft.Compute/virtualMachines/myAibGalleryVM",
"identity": {
"principalId": "632b1fc9-9d93-46da-bbd1-3b32e85f96eb",
"tenantId": "40a524d9-f848-46d4-a96f-be6df491fe15",
"type": "SystemAssigned",
"userAssignedIdentities": null
},
"location": "westus2",
"macAddress": "00-0D-3A-F5-29-B8",
"powerState": "VM running",
"privateIpAddress": "10.0.0.4",
"publicIpAddress": "51.143.126.x",
"resourceGroup": "ibUbuntuFIPSGalleryRG",
"zones": ""
}
Note the publicIpAddress
, which in my case is 51.143.126.x
. This is what you can use to ssh into the machine in the next step.
You can ssh using that IP address and with the command
$ sudo ua status --wait
We can see that this VM is attached to an Ubuntu Pro subscription and is running a FIPS kernel.
Cleanup
Duration: 2:00
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.)
That’s all folks!
Duration: 1:00
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.