Lab Walkthrough - Create a Virtual Machine using ARM
In our lab walkthrough series, we go through selected lab exercises on our INE Platform. Subscribe or sign up for a 7-day, risk-free trial with INE and access this lab and a robust library covering the latest in Cyber Security, Networking, Cloud, and Data Science!
Azure is Microsoft’s cloud computing platform. Microsoft Azure Resource Manager or simply Azure Resource Manager (ARM) is a service that allows you to deploy and manage resources in your Azure account.
Lab Scenario
We have set up the below scenario in our INE labs for our students to practice. The screenshots have been taken from our online lab environment.
In this lab, you will be automatically provided with the credentials to log in to the Azure portal where you can then perform the task discussed below.
Challenge Statement
The objective is to create an instance of B1s virtual machine (Ubuntu 18.04) using ARM.
Solution
Before getting started, you need to have Azure CLI installed on your local machine. The installation steps have been discussed at the end.
Step 1: Once you log in to your Azure account, the Azure portal dashboard should be available to you along with the empty Resource Group.
Step 2: Open PowerShell or CMD (Command Prompt) and login into your Azure account, using the following command:
az login
This will open a new window in the browser where you will have to choose the account to sign in (select the one used in Step 1). After successful login, you will see the below output in PowerShell.
Step 3: To create a virtual machine, of the following specifications, you need to create an ARM file.
1.OS : Ubuntu (18.04)
2.Size : Standard_B1s
3.Resource group : user_9TSIWATV5B_ResourceGroup
4.Name : VM
5.Admin username of the machine : admin1234
6.Admin password of the machine : password@A1
Note: The Resource group name might vary across commands and screenshots used in this article. Make sure you use your correct Resource group name in all the commands.
ARM Template is used to implement infrastructure as code for your Azure solutions. The template is a JavaScript Object Notation (JSON) file.
Save it as arm_template.json
and generate arm_template.parameters.json
file from it.
Note: In ARM, values of parameters and configuration of resources are kept separate.
ARM template file consists of parameter definitions and the resource configuration.
For instance, the vmName (name of the virtual machine) parameter in which the constraints for its values such as type, default value, etc. are passed.
{
"vmName": {
"type": "string",
"defaultValue": "simpleLinuxVM",
"metadata": {
"description": "The name of you Virtual Machine."
}
}
Resources and their configuration can be defined as below:
"resources": [
{
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2021-05-01",
"name": "[variables('networkInterfaceName')]",
"location": "[parameters('location')]",
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]"
},
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]"
}
}
}
By combining all the components, we get the final ARM template file.
arm_template.json content
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.5.6.12127",
"templateHash": "6759226889218242060"
}
},
"parameters": {
"vmName": {
"type": "string",
"defaultValue": "simpleLinuxVM",
"metadata": {
"description": "The name of you Virtual Machine."
}
},
"adminUsername": {
"type": "string",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"authenticationType": {
"type": "string",
"defaultValue": "password",
"allowedValues": [
"sshPublicKey",
"password"
],
"metadata": {
"description": "Type of authentication to use on the Virtual Machine. SSH key is recommended."
}
},
"adminPasswordOrKey": {
"type": "secureString",
"metadata": {
"description": "SSH Key or password for the Virtual Machine. SSH key is recommended."
}
},
"dnsLabelPrefix": {
"type": "string",
"defaultValue": "[toLower(format('{0}-{1}', parameters('vmName'), uniqueString(resourceGroup().id)))]",
"metadata": {
"description": "Unique DNS Name for the Public IP used to access the Virtual Machine."
}
},
"ubuntuOSVersion": {
"type": "string",
"defaultValue": "18.04-LTS",
"allowedValues": [
"12.04.5-LTS",
"14.04.5-LTS",
"16.04.0-LTS",
"18.04-LTS"
],
"metadata": {
"description": "The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_B2s",
"metadata": {
"description": "The size of the VM"
}
},
"virtualNetworkName": {
"type": "string",
"defaultValue": "vNet",
"metadata": {
"description": "Name of the VNET"
}
},
"subnetName": {
"type": "string",
"defaultValue": "Subnet",
"metadata": {
"description": "Name of the subnet in the virtual network"
}
},
"networkSecurityGroupName": {
"type": "string",
"defaultValue": "SecGroupNet",
"metadata": {
"description": "Name of the Network Security Group"
}
}
},
"variables": {
"publicIPAddressName": "[format('{0}PublicIP', parameters('vmName'))]",
"networkInterfaceName": "[format('{0}NetInt', parameters('vmName'))]",
"osDiskType": "Standard_LRS",
"subnetAddressPrefix": "10.1.0.0/24",
"addressPrefix": "10.1.0.0/16",
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
"publicKeys": [
{
"path": "[format('/home/{0}/.ssh/authorized_keys', parameters('adminUsername'))]",
"keyData": "[parameters('adminPasswordOrKey')]"
}
]
}
}
},
"resources": [
{
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2021-05-01",
"name": "[variables('networkInterfaceName')]",
"location": "[parameters('location')]",
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]"
},
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]"
}
}
}
],
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))]"
}
},
"dependsOn": [
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))]",
"[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]",
"[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]"
]
},
{
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2021-05-01",
"name": "[parameters('networkSecurityGroupName')]",
"location": "[parameters('location')]",
"properties": {
"securityRules": [
{
"name": "SSH",
"properties": {
"priority": 1000,
"protocol": "Tcp",
"access": "Allow",
"direction": "Inbound",
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "*",
"destinationPortRange": "22"
}
}
]
}
},
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2021-05-01",
"name": "[parameters('virtualNetworkName')]",
"location": "[parameters('location')]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
}
}
},
{
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2021-05-01",
"name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('subnetName'))]",
"properties": {
"addressPrefix": "[variables('subnetAddressPrefix')]",
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
},
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]"
]
},
{
"type": "Microsoft.Network/publicIPAddresses",
"apiVersion": "2021-05-01",
"name": "[variables('publicIPAddressName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Basic"
},
"properties": {
"publicIPAllocationMethod": "Dynamic",
"publicIPAddressVersion": "IPv4",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
},
"idleTimeoutInMinutes": 4
}
},
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2021-11-01",
"name": "[parameters('vmName')]",
"location": "[parameters('location')]",
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"storageProfile": {
"osDisk": {
"createOption": "FromImage",
"managedDisk": {
"storageAccountType": "[variables('osDiskType')]"
}
},
"imageReference": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "[parameters('ubuntuOSVersion')]",
"version": "latest"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
}
]
},
"osProfile": {
"computerName": "[parameters('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPasswordOrKey')]",
"linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), null(), variables('linuxConfiguration'))]"
}
},
"dependsOn": [
"[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
]
}
],
"outputs": {
"adminUsername": {
"type": "string",
"value": "[parameters('adminUsername')]"
},
"hostname": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))).dnsSettings.fqdn]"
},
"sshCommand": {
"type": "string",
"value": "[format('ssh {0}@{1}', parameters('adminUsername'), reference(resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))).dnsSettings.fqdn)]"
}
}
}
The values of the parameters configured in the ARM template are fetched from the parameter file. For instance, the value of vmName (mentioned in step 3):
"parameters": {
"vmName": {
"value": "vm"
}
}
arm_template.parameters.json content
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vmName": {
"value": "vm"
},
"adminUsername": {
"value": "admin1234"
},
"authenticationType":{
"value":"password"
},
"adminPasswordOrKey":{
"value":"password@A1"
},
"dnsLabelPrefix":{
"value":"dnsazure"
},
"ubuntuOSVersion":{
"value":"18.04-LTS"
},
"vmSize": {
"value": "Standard_B1s"
},
"virtualNetworkName": {
"value": "vnamedemo"
},
"subnetName": {
"value": "subnetdemo"
},
"networkSecurityGroupName": {
"value": "securitygnamedemo"
},
"location": {
"value": "Central India"
}
}
}
Both these files combined contain everything required for creating the required virtual machine.
Step 4: Deploy both these files to apply changes to infrastructure by using the following command:
az deployment group create --resource-group user_EW58SGJKPV_ResourceGroup --template-file arm_template.json --parameters arm_template.parameters.json
Once the command executes successfully, you can scroll down the terminal to see that your provisioning has succeeded:
Step 5: Switch to your web browser and inspect the Resource Group in Azure Portal.
The resources have been created in the Resource Group.
Step 6: After using the virtual machine, you can destroy all the resources by using the following command:
az vm delete -g user_E5IMNPKIRL_ResourceGroup -n vm
Type ‘y’ to confirm the deletion.
Step 7: Switch to your web browser again and inspect the Resource Group in Azure Portal.
The resources have been deleted and the Resource group is empty now.
Installing Azure CLI
For Windows:
1. For Windows, the Azure CLI is installed via an MSI, which gives you access to the CLI through the Windows Command Prompt (CMD) or PowerShell.
2. Download the latest release of Azure CLI from https://aka.ms/installazurecliwindows. An MSI file will be downloaded.
3. Open the MSI file and it will prepare to install the CLI on your local machine. Accept the terms and conditions. Click on Install.
4. When the installer asks if it can make changes to your computer, click the “Yes” box. After the installation is complete, you will need to close and reopen any active Windows Command Prompt or PowerShell windows to use the Azure CLI.
For macOS:
1. For macOS, you can install the Azure CLI with Homebrew package Managers which will manage your CLI installation.
2. Download homebrew from https://docs.brew.sh/Installation.html.
3. Install Azure CLI by using the following command in bash:
brew update && brew install azure-cli
For Ubuntu/Debian:
1. For Ubuntu/Debian, installation can be done with the command given below. This script is downloaded via curl and piped directly to bash to install the CLI.
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
You can check if the installation is successful by running the following Azure command:
az version
Looking for a platform to try this task hands-on? Subscribe or sign up for a 7-day, risk-free trial with INE and access this lab and a robust library covering the latest in Cyber Security, Networking, Cloud, and Data Science!