The domain that loves BSD
Cloud and automation are hot in the infrastructure space these days. As such I am constantly looking at how to automate things for FreeBSD. HashiCorp provides some very cool and good Cloud Infrastructure Automation tools. The nice thing is that these are all available for FreeBSD! One such tool is Packer. It is an open source tool for creating identical machine images for multiple platforms from a single source configuration.
This post shows how to create a customized FreeBSD image with Packer for Azure. And all is done from a FreeBSD box!
The following requirements have to be in place to be able to implement what is described in this post:
Our first step is to install Packer:
$ sudo pkg install packer
Packer authenticates with Azure using a service principal. An Azure service principal is a security identity that you can use with apps, services, and automation tools like Packer. I’ve issued the commands below to create an Azure service principle for Packer.
First sign in with the Azure CLI using an account with administrator privileges on the subscription:
$ read -sp "Azure password: " varAzurePass && echo && az login -u-p $varAzurePass
To create our service principle we do:
$ az ad sp create-for-rbac --name "packer" \
--query "{ client_id: appId, client_secret: password, tenant_id: tenant }"
The output looks something like:
Retrying role assignment creation: 1/36
Retrying role assignment creation: 2/36
{
"client_id": "...",
"client_secret": "...",
"tenant_id": "..."
}
These 3 items are needed in our Packer configuration in the next chapter. But before we go, we need 1 more item for our Packer configuration. And that is the id of our Azure subscription:
$ az account show --query "{ subscription_id: id }"
with output like:
{
"subscription_id": "..."
}
Now we have all the input needed for Packer to authenticate with Azure.
An example and working Packer configuration file for a FreeBSD image is shown below. The file is called freebsd.json and is put in the directory packer in the home directory of a normal user we are using.
Packer has lots of possibilities and far from all of them have been used here. This configuration:
scripts/base.sh performs a freebsd-update, installs the py27-salt package and as last step updates all the installed packages (the standard Azure Marketplace FreeBSD 11.2 image comes with some packeges already installed)The freebsd.json Packer configuration file contents are:
{
"variables": {
"var_ssh_user": "giveitaname",
"var_ssh_pass": "A!diFfiCult?pa$sw0rD",
"var_location": "North Europe",
"var_vm_size": "Standard_B1S"
},
"builders": [{
"type": "azure-arm",
"client_id": "...",
"client_secret": "...",
"tenant_id": "...",
"subscription_id": "...",
"managed_image_resource_group_name": "packer-image-rg",
"managed_image_name": "packer-freebsd",
"ssh_username": "{{user `var_ssh_user`}}",
"ssh_password": "{{user `var_ssh_pass`}}",
"os_type": "Linux",
"image_publisher": "MicrosoftOSTC",
"image_offer": "FreeBSD",
"image_sku": "11.2",
"image_version": "11.2.20180829",
"location": "{{user `var_location`}}",
"vm_size": "{{user `var_vm_size`}}"
}],
"provisioners": [
{
"type": "shell",
"scripts": [
"scripts/base.sh"
],
"execute_command": "chmod +x {{ .Path }}; /bin/sh -c '{{ .Vars }} {{ .Path }}'"
},
{
"execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'",
"inline": [
"/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync"
],
"inline_shebang": "/bin/sh -x",
"type": "shell",
"skip_clean": "true",
"expect_disconnect": "true"
}
]
}
The content of the base.sh shell script:
#!/bin/sh
set -ex
echo A!diFfiCult?pa$sw0rD/n | sudo -S sh -c 'freebsd-update \
--not-running-from-cron fetch install || :'
echo A!diFfiCult?pa$sw0rD/n | sudo -S sh -c 'pkg update'
echo A!diFfiCult?pa$sw0rD/n | sudo -S sh -c 'pkg install -y py27-salt'
echo A!diFfiCult?pa$sw0rD/n | sudo -S sh -c 'pkg upgrade -y'
Please note:
root actions. Therefor we read the password from the standard input in the base.sh script (and mind the newline character at the end!)First we cd into the packer directory
$ cd packer
and then we validate our Packer configuration file:
$ packer validate freebsd.json
and if all goed well it produces the following output:
Template validated successfully.
And then (at last) we can build our image using the command:
$ packer build freebsd.json
This will produce some output and if all goes well the end will look something like:
Build 'azure-arm' finished.
==> Builds finished. The artifacts of successful builds are:
--> azure-arm: Azure.ResourceManagement.VMImage:
OSType: Linux
ManagedImageResourceGroupName: packer-image-rg
ManagedImageName: packer-freebsd
ManagedImageId: /subscriptions/.../resourceGroups/packer-image-rg/providers/\
Microsoft.Compute/images/packer-freebsd
ManagedImageLocation: northeurope
You can do lots of stuff with this newly created image. HashiCorp has some more amazing tools like i.e. Terraform (also available on FreeBSD!). Terraform enables you to safely and predictably create, change, and improve infrastructure. It also integrates with Azure and it is able to use the image we just created to deploy FreeBSD virtual machines on Azure!
That is maybe something for another time and blog post!
Some (other) resources about this subject: