HOWTO: Deploy Ubuntu Linux VM with SSH Key using Power Shell and Azure Resource Manager (ARM)
With the release of Azure Resource Manager and its corresponding new set of REST services, it has put those of us who have to script and develop against these providers in a bit of a tough spot, because there are some definite differences and not all of them have been documented as of yet. So to help that along, I thought that I would provide you with the solution to a problem that I ran into recently.
I was working on the next post in my Deploying a SaaS Application series and was trying to build out the Power Shell script to deploy a Ubuntu Linux server with Key based authentication rather than the standard user name and password. If you are going to make your system accessible from the internet, then key based authentication is the most secure route. I could not find any examples that fit the bill, so after a lot of troubleshooting and research, I was able to figure out all the necessary commands and I would like to walk through that script, focusing on the pieces that are related to the Key based authentication. I will also try and point out some of the differences between the use of the Azure Service Management model, IaaS V1, versus the Azure Resource Management model, IaaS V2.
1.) In the ARM model, the first thing that you will need to do is to create a new Resource Group for all of the resources to be a part of.
$rgName = "hotel-mgmt-westeu"
$location = "West Europe"
New-AzureResourceGroup -Location $location -Name $rgName
2.) Next, as you would with any new environment, you will need to setup a Virtual Network and at least one Subnet
$vnetName = "vnet-harrisonhotel-prodeu"
$subnetShared = New-AzureVirtualNetworkSubnetConfig -Name "Subnet-Shared" -AddressPrefix "10.2.4.0/24"
$vnet = New-AzureVirtualNetwork -Location $location -Name $vnetName -ResourceGroupName $rgName -AddressPrefix "10.2.0.0/16" -Subnet $subnetShared
$subnetShared = $vnet.Subnets
TIP: Please note that although there are other methods to add a Subnet to a Virtual Network, the New-AzureVirtualNetworkSubnet seems to be the only one that will not only create the Subnet, but make sure that it has an Id. This may not be important for some tasks, it is an absolute requirement for the next step of creating a NIC. The New-AzureNetworkInterface requires either a Subnet or Subnet.Id parameter.
3.) As I mentioned above, because this VM is going to be accessible from the internet, you need to provide a NIC that a new Public IP/Reserved IP can be attached to
$nicJumpName = "nic-jump-westeu"
$jumpIP = New-AzurePublicIpAddress -Name "reservedip-jump-eu" -ResourceGroupName $rgName -Location $location -AllocationMethod Dynamic
$jumpNic = New-AzureNetworkInterface -Location $location -Name $nicJumpName -ResourceGroupName $rgName -Subnet $subnetShared -PublicIpAddress $jumpIP
4.) Create a new storage account that can be used to store the VHD for the VM being created
$stdStorName = "hotelmgmtstoragestdeu"
$vmStorContainer = "stdvmstorage"
$stdStorage = New-AzureStorageAccount -ResourceGroupName $rgName -Location $location -Type Standard_LRS -Name $stdStorName
5.) Next we need to setup the VM object and start to add needed configuration information
$vmImageOffer = "UbuntuServer"
$vmImageSku = "14.04.2-LTS"
$osDiskName = "osDisk"
$osDiskCaching = "ReadWrite"
$vmUserName = "harrison"
$jumpVMName = "vm-jump-westeu"
$jumpVM = New-AzureVMConfig -VMName $jumpVMName -VMSize "Standard_A1"
$jumpVM = Add-AzureVMNetworkInterface -VM $jumpVM -NetworkInterface $jumpNic
$cred = Get-Credential -UserName $vmUserName -Message "SSHCredential, use blank password"
$jumpVM = Set-AzureVMOperatingSystem -VM $jumpVM -Linux -ComputerName $jumpVMName -Credential $cred
NOTE: Please note that that I put a blank password in when the prompt appears or you can use what ever pass phrase you used when you created the SSH Key.
$jumpVM = Set-AzureVMSourceImage -VM $jumpVM -PublisherName $vmImagePublisher -Offer $vmImageOffer -Skus $vmImageSku -Version "latest"
$vmJumpOSStorage = "http://$stdStorName.blob.core.windows.net/$vmStorContainer/vm-jump-westeuOSDisk.vhd"
$jumpVM = Set-AzureVMOSDisk -VM $jumpVM -VhdUri $vmJumpOSStorage -name "vm-jump-westeuOSDisk" -CreateOption fromImage
ASM vs ARM DIFFERENCE: Please notice that there are some differences in how we configure a VM. There are a few more cmdlets available to provide specific pieces of the configuration, such as a separate cmdlet for defining the operating system, which also takes in a PSCredential object for the username and password. There is also a separate cmdlet for the creating of the Operating System disk or VHD. In the ASM set of cmdlets, these were handled within the main Config cmdlets.
6.) Next to Last, we need to create the SSH Public Key and make sure that it stored within the server for authentication use for a specific username.
$jumpVM = Add-AzureVMSshPublicKey -VM $jumpVM -Path "/home/$vmUserName/.ssh/authorized_keys" -KeyData <Enter Public Key Data Here>
ASM vs ARM DIFFERENCE: Here is another small, but very important difference when deploying a VM. In IaaS V1, an x.509 based RSA cert is required for the Public Key, but in ARM mode, a standard openssh based RSA Key is required. This means that the process for creating the keys are very different. To create a key using the ever popular PuttyGen utility, use the following article: Generating RSA Keys with SSH - using PuttyGen
7.) Lastly, we need to actually create the VM with all of the configuration information that we have passed into the object
New-AzureVM -ResourceGroupName $rgname -Location $location -VM $jumpVM;
Once this is done, you should be able to connect to and authenticate against the server using the private key that was created from the PuttyGen utility. You will of course need to make sure to get the Public IP that was attached to the NIC to know how to connect. Some additional articles related to other VM configurations and SSH based combinations can be found below. Pay close attention to the first one as it is from a fellow CSA and goes into a lot of detail about many of the cmdlets that I used above.