Passing custom data to your Azure VMs, a metadata service workaround?!

Sometimes you develop a solution where your VM need to be aware of itself and the information associated with the VM during deployment:

  • What is the Azure identification of me as a VM Instance?
  • What datacenter/region have I been deployed to?
  • What is the Fully Qualified Domain Name, FQDN, for me as a Virtual Machine?

These questions are very easy to answer if you as an administrator take a look into the Azure portal, but it’s not that easy if you want a program or script to do the same, if it runs on top of the provisioned VM. So if I were a script running on the VM how would I figure out these things? A common approach to this problem would be to call out to an internal service built into the cloud platform, and ask: Who am I? Where am I? How can someone reach me? These service are often referred to as metadata services and can provide this kind of metadata for the running instance. At the time of writing this blog post, there are no such service generally available in Azure.

So an option to this approach would instead be to pass in such information at deploy time, into the provisioning VM and saved in a place where it can be reached later on. It’s not a perfect replacement to a metadata service, but it offers a lot of abilities that could be tricky to solve otherwise. In Azure this feature is called “Custom Data” and is text that you can pass in while provisioning your VM either through REST APIs, PowerShell CmdLets, Azure Command Line Interface (CLI) or using an ARM Template.

In this example I’ll show a way to automatically pass in custom data using an ARM Template so that every time your VMs have started up, they know their name, what region they are deployed to and what the associated FQDN is.

The full template can be found on https://github.com/krist00fer/azure-quickstart-templates/tree/master/101-vm-customdata-windows while I do the last fixes to have it incorporated into the full repository of Azure Quick Start Templates at https://github.com/azure/azure-quickstart-templates.

In short, my template has parameters for vmLocation (region to deploy to) and vmName (a name you assign to the azure resource that will be implemented as your VM). There is also a variable called pipName (name of the public IP address) that as following:

"pipName": "[concat(parameters('vmName'), 'pip')]",

i.e. I give my public IP address resource the same name as my VM, but with the prefix 'pip'.

Later down in the template definition you find the actual VM definition and there you find the osProfile property:

"osProfile": { "computerName": "[parameters('vmName')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]", "customData": "[base64(concat(parameters('vmName'), '|', parameters('vmLocation'), '|', reference(variables('pipName')).dnsSettings.fqdn))]" },

You can see that except for computerName, adminUsername and adminPassword, I've also added the property "customData" passing in a base64 encoded string that is the combination of the vmName parameter, the vmLocation parameter and the assigned Fully Qualified Domain Name, FQDN.

Deploying this template will give you a new VM that you could remote into and find a file at:

C:\AzureData\CustomData.bin

This file contains the above sent in customData string, already decoded and ready to use.

Executing the following PowerShell Script in the VM would then parse and separate the passed in values:

$customData = (Get-Content C:\AzureData\CustomData.bin).Split('|') $vmName = $customData[0] $vmLocation = $customData[1] $fqdn = $customData[2]PS C:\> $vmName vm001 PS C:\> $vmLocation North Europe PS C:\> $fqdn customdatavm001.northeurope.cloudapp.azure.com
So there you have it. You can know query the passed in information to understand similar things to what a Metadata Service would give you. It's not entirely bullet proof for all scenarios, but provides a simple solution to many problematic things you might encounter.