Who does not know this scenario? You want a trainee to deploy a Windows Server but you do not want to give him or her access to your secret administrator passwords at all. Or you want to delegate deployments to a service provider but you need your passwords to stay save? Azure Key Vault could be what makes your life way easier.
Azure Key Vault is a cloud service used for storing keys and secrets which are encrypted using keys from Hardware Security Modules (HSMs). It is designed so that Microsoft never sees or can extract your keys or secrets stored in Azure Key Vault.
What do we need?
First of all we need a Key Vault. You can create one using Azure Primary Portal or using PowerShell:
New-AzureRmKeyVault -VaultName "MyKeyVault" -ResourceGroupName "MyResourceGroup" -Location "NorthEurope" -EnabledForDeployment -Sku standard
There are two pricing tiers (A1 Standard and P1 Premium). Both of them differ in the fact that with P1 you get your keys HSM backed; with A1 you don’t.

Access policies are an interesting feature. Storing your keys and secrets encrypted and having the whole world read them won’t make sense in most scenarios. And having your secrets altered by anyone you don’t know will not make your security strategy better. So you should kiss – keep it simple, stupid.

In my demo environment I have selected two principals that have access to keys and/or secrets in my key vault. One of them, a delegated admin account that I use for automated VM deployments only has access to secrets like passwords, not to keys.
Create a secret for your local admin password
In an automated VM deployment a user account can be logged in into an Azure subscription via PowerShell using encrypted credentials. After having created your Key Vault you need to enter your passphrase as secure string and pass it to the Set-AzureKeyVaultSecret cmdlet which creates or updates a secret in your Vault:
$password = read-host -assecurestring Set-AzureKeyVaultSecret -VaultName keyvault -Name admin -SecretValue $password
Now you’re all set up for some PowerShell automation.
Automated login to Azure Resource Manager
For automated PowerShell login to Azure Resource Manager you first have to enter your Azure admins passphrase as secure string and save it in a .txt-file.
read-host -assecurestring | convertfrom-securestring | out-file C:\temp\passphrase_encrypted.txt
That file then contains an AES-encrypted standard string that can be imported again later on. To reimport the saved encrypted passphrase and create logon credentials you can use the following PowerShell code:
$password = get-content C:\temp\passphrase_encrypted.txt | convertto-securestring $credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist "user@yourdomain.onmicrosoft.com",$password
With those credentials you can now login into your subscription:
Login-AzureRMAccount -Credential $credentials
Automated VM deployment
Now you can automate your VM deployment. For this purpose you can use the following example script:
$location = "NorthEurope" $ResourceGroupName= "myResourceGroup" $LocalAdminUser = "adminUserName" $ResourceGroup = New-AzureRmResourceGroup -Name $ResourceGroupName -Location $Location $StorageAccountName = "mystorageaccount" $Test = Get-AzureRmStorageAccountNameAvailability $StorageAccountName If ($Test) { $storageAccount =New-AzureRmStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName -SkuName "Standard_LRS"-Kind "Storage"-Location $location } $mySubnet = New-AzureRmVirtualNetworkSubnetConfig -Name "mySubnet" -AddressPrefix 10.0.0.0/24 $myVnet = New-AzureRmVirtualNetwork -Name "myVnet" -ResourceGroupName $ResourceGroupName -Location $location -AddressPrefix 10.0.0.0/16 -Subnet $mySubnet $myPublicIp = New-AzureRmPublicIpAddress -Name "myPublicIp" -ResourceGroupName $ResourceGroupName -Location $location -AllocationMethod Static $myNIC = New-AzureRmNetworkInterface -Name "myNIC" -ResourceGroupName $ResourceGroupName -Location $location -SubnetId $myVnet.Subnets[0].Id -PublicIpAddressId $myPublicIp.Id ## Now get the secret from your Azure Key Vault that you've created before and create your local admin credentials $Secret = Get-AzureKeyVaultSecret -VaultName MyKeyVault -Name admin $Cred = [PSCredential]::new($LocalAdminUser, $Secret.SecretValue) $myVm = New-AzureRmVMConfig -VMName "myVM" -VMSize "Standard_A2" $myVM = Set-AzureRmVMOperatingSystem -VM $myVM -Windows -ComputerName "myVM" -Credential $cred -ProvisionVMAgent -EnableAutoUpdate $myVM = Set-AzureRmVMSourceImage -VM $myVM -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Skus "2016-Datacenter" -Version "latest" $myVM = Add-AzureRmVMNetworkInterface -VM $myVM -Id $myNIC.Id $blobPath = "vhds/myOsDisk1.vhd" $osDiskUri = $storageAccount.PrimaryEndpoints.Blob.ToString() + $blobPath $myVM = Set-AzureRmVMOSDisk -VM $myVM -Name "myOsDisk1" -VhdUri $osDiskUri -CreateOption fromImage New-AzureRmVM -ResourceGroupName $ResourceGroupName -Location $location -VM $myVM
The passage that’s relevant for us is
$Secret = Get-AzureKeyVaultSecret -VaultName MyKeyVault -Name admin $Cred = [PSCredential]::new($LocalAdminUser, $Secret.SecretValue)
With that code you read the Azure KeyVault secret you created earlier and put it into credentials that are passed to the VM configuration and so will be used as admin logon credentials for your new VM. No trainee and no service provider will ever get access to the passphrase and yet they will be able to automatically deploy a new VM to Azure Resource Manager.
Now, give it a try and happy testing.
Stay tuned and bye for now,
Tom
2 thoughts on “How to use stored secrets from Azure Key Vault while deploying ARM VMs”